v / examples / sokol / sounds / melody.v
59 lines · 54 sloc · 1.83 KB · e1b7cb16f36095dbe0ed62c9c7341850d78ae507
Raw
1// vtest build: !openbsd
2import gg
3import sokol.audio
4
5struct AppState {
6mut:
7 frame_0 int // offset of the current audio frames, relative to the start of the music
8 frames [2048]f32 // a copy of the last rendered audio frames
9 gg &gg.Context = unsafe { nil } // used for drawing
10}
11
12fn my_audio_stream_callback(mut soundbuffer &f32, num_frames int, num_channels int, mut acontext AppState) {
13 for frame := 0; frame < num_frames; frame++ {
14 t := int(f32(acontext.frame_0 + frame) * 0.245)
15 // "Techno" by Gabriel Miceli
16 y := (t * (((t / 10 | 0) ^ ((t / 10 | 0) - 1280)) % 11) / 2 & 127) +
17 (t * (((t / 640 | 0) ^ ((t / 640 | 0) - 2)) % 13) / 2 & 127)
18 for ch := 0; ch < num_channels; ch++ {
19 idx := frame * num_channels + ch
20 a := f32(y - 127) / 255.0
21 soundbuffer[idx] = a
22 acontext.frames[idx & 2047] = a
23 }
24 }
25 acontext.frame_0 += num_frames
26}
27
28fn graphics_frame(mut state AppState) {
29 ws := gg.window_size()
30 center_y := f32(ws.height / 2)
31 state.gg.begin()
32 for x in 0 .. 1024 {
33 vx := ws.width * f32(x) / 1024.0
34 vy := center_y * 3.0 / 4.0 * (state.frames[2 * x] + state.frames[2 * x + 1])
35 color := gg.Color{f(state, x), f(state, x + 300), f(state, x + 700), 255}
36 state.gg.draw_line(vx, center_y, vx, center_y + vy, color)
37 }
38 state.gg.end()
39}
40
41fn f(state &AppState, idx int) u8 {
42 return u8(127 + state.frames[(int(state.gg.frame) + idx) & 2047] * 128)
43}
44
45fn main() {
46 println('Based on the ByteBeat formula from: https://www.youtube.com/watch?v=V4GfkFbDojc \n "Techno" by Gabriel Miceli')
47 mut state := &AppState{}
48 audio.setup(stream_userdata_cb: my_audio_stream_callback, user_data: state)
49 defer { audio.shutdown() }
50 state.gg = gg.new_context(
51 bg_color: gg.Color{50, 50, 50, 255}
52 width: 800
53 height: 600
54 window_title: 'ByteBeat Music'
55 frame_fn: graphics_frame
56 user_data: state
57 )
58 state.gg.run()
59}
60