| 1 | // vtest build: !openbsd |
| 2 | import gg |
| 3 | import sokol.audio |
| 4 | |
| 5 | struct AppState { |
| 6 | mut: |
| 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 | |
| 12 | fn 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 | |
| 28 | fn 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 | |
| 41 | fn f(state &AppState, idx int) u8 { |
| 42 | return u8(127 + state.frames[(int(state.gg.frame) + idx) & 2047] * 128) |
| 43 | } |
| 44 | |
| 45 | fn 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 | |