v2 / examples / sokol / sounds / simple_sin_tone_using_audio_push.v
68 lines · 62 sloc · 2.07 KB · e1b7cb16f36095dbe0ed62c9c7341850d78ae507
Raw
1// vtest build: !openbsd && !sanitize-memory-clang // Fails compilation with: `ld: /lib/x86_64-linux-gnu/libpthread.so.0: error adding symbols: DSO missing from command line`
2// import log
3import math
4import time
5import sokol.audio
6
7fn main() {
8 args := arguments()
9 freq := args[1] or { '417' }.int()
10 amplitude := args[2] or { '0.5' }.f32()
11 dump(freq)
12 dump(amplitude)
13
14 audio.setup(num_channels: 1)
15 sample_rate := dump(audio.sample_rate())
16 dump(audio.buffer_frames())
17 dump(audio.expect())
18
19 // create an array of frames, filled with the desired pure sine tone:
20 mut frames := []f32{len: sample_rate * 2} // 2 seconds
21 for i in 0 .. frames.len {
22 t := f32(i) / f32(sample_rate)
23 frames[i] = amplitude * math.sinf(f32(freq) * t * (2 * math.pi))
24 }
25
26 // play the sound by continuosly pushing samples from the generated
27 // array of sound frames, when there is need for more:
28 mut fpos := 0
29 for {
30 expected_frames := audio.expect()
31 if expected_frames > 0 {
32 written_frames := audio.push(unsafe { &frames[fpos] }, expected_frames)
33 fpos += written_frames
34 // log.info('> pushing done ... fpos: ${fpos:6} | expected_frames: ${expected_frames:6} | written: ${written:6}')
35 if fpos > frames.len - 2 * written_frames {
36 // log.info('> fpos too large: ${fpos}')
37 fpos = find_loop_position(fpos, frames)
38 // log.info('> fpos looped back to start: ${fpos}')
39 }
40 }
41 time.sleep(50 * time.millisecond)
42 }
43 audio.shutdown()
44}
45
46fn find_loop_position(fpos int, frames []f32) int {
47 return find_matching_position(frames, fpos, 0.01, 2) or {
48 find_matching_position(frames, fpos, 0.05, 2) or {
49 find_matching_position(frames, fpos, 0.1, 2) or { 0 }
50 }
51 }
52}
53
54@[direct_array_access]
55fn find_matching_position(frames []f32, fpos int, tol f32, d int) ?int {
56 if fpos - d < 0 || fpos + d >= frames.len {
57 return none
58 }
59 p1, p2, p3 := frames[fpos - d], frames[fpos], frames[fpos + d]
60 for i in 2 .. fpos / 2 {
61 np1, np2, np3 := frames[i - d], frames[i], frames[i + d]
62 if math.tolerance(np1, p1, tol) && math.tolerance(np2, p2, tol)
63 && math.tolerance(np3, p3, tol) {
64 return i
65 }
66 }
67 return none
68}
69