From 36fc7b5b7b003e721bfe7f0b54a290754c863138 Mon Sep 17 00:00:00 2001 From: Wertzui123 <46199283+Wertzui123@users.noreply.github.com> Date: Wed, 20 Apr 2022 13:54:50 +0200 Subject: [PATCH] Update to latest V and format the codebase --- constants.v | 91 ++++++++++++++++++++++++++++++++++++++------- main.v | 32 ++++++++-------- midi.v | 73 +++++++++++++++++++----------------- ui.v | 104 +++++++++++++++++++++++++++++++++------------------- util.v | 26 +++++++++++-- 5 files changed, 221 insertions(+), 105 deletions(-) diff --git a/constants.v b/constants.v index ea990b4..fdb5eb0 100644 --- a/constants.v +++ b/constants.v @@ -31,17 +31,82 @@ const note_names = [ ]! const note_colors = [ - gx.Color{ r: 226, g: 1, b: 68, a: 255 } - gx.Color{ r: 233, g: 67, b: 19, a: 255 } - gx.Color{ r: 236, g: 137, b: 10, a: 255 } - gx.Color{ r: 252, g: 205, b: 16, a: 255 } - gx.Color{ r: 247, g: 232, b: 20, a: 255 } - gx.Color{ r: 190, g: 214, b: 1, a: 255 } - gx.Color{ r: 134, g: 185, b: 20, a: 255 } - gx.Color{ r: 100, g: 178, b: 83, a: 255 } - gx.Color{ r: 70, g: 130, b: 190, a: 255 } - gx.Color{ r: 73, g: 85, b: 155, a: 255 } - gx.Color{ r: 151, g: 107, b: 168, a: 255 } - gx.Color{ r: 189, g: 82, b: 150, a: 255 } - gx.Color{ r: 89, g: 82, b: 150, a: 255 } + gx.Color{ + r: 226 + g: 1 + b: 68 + a: 255 + }, + gx.Color{ + r: 233 + g: 67 + b: 19 + a: 255 + }, + gx.Color{ + r: 236 + g: 137 + b: 10 + a: 255 + }, + gx.Color{ + r: 252 + g: 205 + b: 16 + a: 255 + }, + gx.Color{ + r: 247 + g: 232 + b: 20 + a: 255 + }, + gx.Color{ + r: 190 + g: 214 + b: 1 + a: 255 + }, + gx.Color{ + r: 134 + g: 185 + b: 20 + a: 255 + }, + gx.Color{ + r: 100 + g: 178 + b: 83 + a: 255 + }, + gx.Color{ + r: 70 + g: 130 + b: 190 + a: 255 + }, + gx.Color{ + r: 73 + g: 85 + b: 155 + a: 255 + }, + gx.Color{ + r: 151 + g: 107 + b: 168 + a: 255 + }, + gx.Color{ + r: 189 + g: 82 + b: 150 + a: 255 + }, + gx.Color{ + r: 89 + g: 82 + b: 150 + a: 255 + }, ]! diff --git a/main.v b/main.v index b9acec1..0b04a6b 100644 --- a/main.v +++ b/main.v @@ -1,14 +1,14 @@ import gg import os import time - +import os.font import audio import vidi struct App { mut: - gg &gg.Context = voidptr(0) - vidi &vidi.Context = voidptr(0) + gg &gg.Context = voidptr(0) + vidi &vidi.Context = voidptr(0) audio &audio.Context = voidptr(0) sustained bool win_width int = 1280 @@ -17,19 +17,18 @@ mut: key_height f32 = 200 white_key_count int keys [128]Key - start_note byte = 41 - + start_note u8 = 41 // whether the current song is paused paused bool // the current tempo multiplier - tempo f32 = 1.0 + tempo f32 = 1.0 // info about the current song: // the notes that make it up notes []Note // the current timestamp (in ns) - t u64 + t u64 // the index of the first note currently being played in the song - i u32 + i u32 // the current song's length in ns song_len u64 } @@ -38,14 +37,14 @@ struct Note { mut: start u64 len u32 - midi byte - vel byte + midi u8 + vel u8 } fn (n Note) str() string { a := int(n.midi) - b := f64(n.start) / time.second - c := f64(n.start+n.len) / time.second + b := f64(n.start) / time.second + c := f64(n.start + n.len) / time.second return '\n [$a] $b - $c' } @@ -77,18 +76,18 @@ fn main() { frame_fn: frame event_fn: event user_data: app - font_path: gg.system_font_path() + font_path: font.default() sample_count: 4 ) if os.args.len > 1 { - app.parse_midi_file(os.args[1]) or { + app.parse_midi_file(os.args[1]) or { eprintln('failed to parse midi file `${os.args[1]}`: $err') return } mut song_len := u64(0) - mut notes_needed := map[byte]u16{} + mut notes_needed := map[u8]u16{} for note in app.notes { if note.start + note.len > song_len { song_len = note.start + note.len @@ -100,7 +99,8 @@ fn main() { notes_per_second := f64(app.notes.len) / f64(app.song_len) * f64(time.second) difficulties := ['easy', 'medium', 'hard', 'very hard', 'extreme']! - println('total notes: $app.notes.len (${notes_per_second:.1f} notes/sec, difficulty: ${difficulties[clamp(byte(notes_per_second / 3.3), 0, 4)]})') + println('total notes: $app.notes.len (${notes_per_second:.1f} notes/sec, difficulty: ${difficulties[clamp(u8(notes_per_second / 3.3), + 0, 4)]})') mut keys := notes_needed.keys() keys.sort() diff --git a/midi.v b/midi.v index 8bef568..8a09d60 100644 --- a/midi.v +++ b/midi.v @@ -1,24 +1,25 @@ import time - import vidi [inline] -fn midi2name(midi byte) string { +fn midi2name(midi u8) string { x := ['bass', 'mid', 'high']! - oct := if is_playable(midi) { x[clamp(midi/12 - 4, 0, x.len-1)] } else { '(unplayable)' } - note := note_names[midi%12] + oct := if is_playable(midi) { x[clamp(midi / 12 - 4, 0, x.len - 1)] } else { '(unplayable)' } + note := note_names[midi % 12] return '$oct $note' } -// byte.is_playable returns true if a note is playable using a Boomwhackers set +// u8.is_playable returns true if a note is playable using a Boomwhackers set [inline] -fn is_playable(n byte) bool { +fn is_playable(n u8) bool { return n >= 48 && n <= 76 } [inline] -fn (mut app App) play_note(note byte, vol_ byte) { - if app.keys[note].pressed { return } +fn (mut app App) play_note(note u8, vol_ u8) { + if app.keys[note].pressed { + return + } app.keys[note].pressed = true vol := f32(vol_) / 127 @@ -26,7 +27,7 @@ fn (mut app App) play_note(note byte, vol_ byte) { } [inline] -fn (mut app App) pause_note(note byte) { +fn (mut app App) pause_note(note u8) { app.keys[note].pressed = false app.audio.pause(note) } @@ -36,12 +37,12 @@ fn (mut app App) pause_all() { for note, mut key in app.keys { if key.pressed { key.pressed = false - app.audio.pause(byte(note)) + app.audio.pause(u8(note)) } } } -fn (mut app App) note_down(note byte, velocity byte) { +fn (mut app App) note_down(note u8, velocity u8) { if velocity == 0 { app.pause_note(note) } else { @@ -63,7 +64,7 @@ fn (mut app App) sustain() { fn (mut app App) unsustain() { if app.sustained { app.sustained = false - for midi in 0 .. byte(app.keys.len) { + for midi in 0 .. u8(app.keys.len) { app.pause_note(midi) } } @@ -94,7 +95,7 @@ fn (mut app App) parse_midi_file(name string) ? { cache[event.note] = Note{} } else { // play - cache[event.note] = { + cache[event.note] = Note{ start: t midi: event.note vel: event.velocity @@ -102,24 +103,23 @@ fn (mut app App) parse_midi_file(name string) ? { } } vidi.Controller { - match event.controller_type { - 0x40, 0x17 { - if event.value > 0x40 { - is_sustain = true - } else { - is_sustain = false - for mut note in sustained_notes { - note.len = u32(t - note.start) - } - app.notes << sustained_notes - sustained_notes.clear() + match event.controller_type { + 0x40, 0x17 { + if event.value > 0x40 { + is_sustain = true + } else { + is_sustain = false + for mut note in sustained_notes { + note.len = u32(t - note.start) } - } - else { - // println('Control change (control=$control, value=$value)') + app.notes << sustained_notes + sustained_notes.clear() } } - + else { + // println('Control change (control=$control, value=$value)') + } + } } vidi.SetTempo { mpqn = u32(midi.mpqn(event.microseconds)) @@ -135,9 +135,9 @@ fn (mut app App) parse_midi_file(name string) ? { } fn (mut app App) play() { - mut sw := time.new_stopwatch({}) + mut sw := time.new_stopwatch() for app.t < app.song_len + lookahead + u64(time.second) { - time.sleep(50*time.microsecond) + time.sleep(50 * time.microsecond) if app.paused { sw.restart() continue @@ -145,7 +145,7 @@ fn (mut app App) play() { app.t += u64(f64(sw.elapsed()) * app.tempo) sw.restart() mut is_at_start := true - for i := app.i; i < app.notes.len ; i++ { + for i := app.i; i < app.notes.len; i++ { note := app.notes[i] key := app.keys[note.midi] end := note.start + note.len @@ -159,9 +159,11 @@ fn (mut app App) play() { is_at_start = false } } - + $if !unplayable ? { - if !is_playable(note.midi) { continue } + if !is_playable(note.midi) { + continue + } } if note.start <= lt && end > lt && !key.pressed { @@ -172,8 +174,11 @@ fn (mut app App) play() { app.pause_note(note.midi) } - if note.start > lt { break } + if note.start > lt { + break + } } } + // exit(0) } diff --git a/ui.v b/ui.v index 65ced8a..1112939 100644 --- a/ui.v +++ b/ui.v @@ -1,4 +1,4 @@ -import gg +import gg import gx import time @@ -10,14 +10,14 @@ const ( const ( default_key_width = 56 min_key_height = 128 - max_key_height = 2./3 + max_key_height = 2.0 / 3 ) const ( - bg_color = gx.rgb(24, 24, 24) - red_strip_color = gx.rgb(80, 0, 0) - white_key_color = gx.rgb(255, 255, 245) - black_key_color = gx.rgb(25, 25, 25) + bg_color = gx.rgb(24, 24, 24) + red_strip_color = gx.rgb(80, 0, 0) + white_key_color = gx.rgb(255, 255, 245) + black_key_color = gx.rgb(25, 25, 25) pressed_white_key_color = gx.rgb(210, 210, 175) pressed_black_key_color = gx.rgb(80, 80, 80) @@ -39,43 +39,53 @@ const lookahead = u64(2 * time.second) fn (app &App) draw() { ww, wh := app.win_width, app.win_height kw, kh := app.key_width, app.key_height + // allow for a 5px margin at the bottom starty := wh - kh - 5 bar_area_height := wh - kh - 10 // draw red "felt" strip above keyboard - app.gg.draw_rect(0, starty - 5, ww, 5, red_strip_color) + app.gg.draw_rect_filled(0, starty - 5, ww, 5, red_strip_color) // draw the note bars mut i := u32(0) - for i = app.i; i < app.notes.len ; i++ { + for i = app.i; i < app.notes.len; i++ { note := app.notes[i] - if note.start > app.t { break } + if note.start > app.t { + break + } h := f32((note.len) * u64(bar_area_height) / lookahead) y := f32((app.t - note.start) * u64(bar_area_height) / lookahead) x, w := app.note_pos(note.midi) color := note_color(note.midi, 100) - app.gg.draw_rounded_rect(x, y - h, w, h, f32(w) / 6, color) + app.gg.draw_rounded_rect_filled(x, y - h, w, h, f32(w) / 6, color) + // draw a thin strip below each note in order to be able to make apart quick presses - app.gg.draw_rect(x, y-7, w, 7, lighten(color, 0.67)) + app.gg.draw_rect_filled(x, y - 7, w, 7, lighten(color, 0.67)) c := text_cfg(note.midi) - app.gg.draw_text(int(x + w / 2), int(y - 12), note_names[note.midi % octave.len], { ...c, color: gx.black, size: 20 }) + app.gg.draw_text(int(x + w / 2), int(y - 12), note_names[note.midi % octave.len], + gx.TextCfg{ ...c, color: gx.black, size: 20 }) } i = 0 // draw white keys - for midi := byte(app.start_note); i < app.white_key_count; midi++ { - if octave[midi % octave.len] == .black { midi++ } + for midi := u8(app.start_note); i < app.white_key_count; midi++ { + if octave[midi % octave.len] == .black { + midi++ + } startx := i * kw - if midi > 127 { break } + if midi > 127 { + break + } key := app.keys[midi] pressed := key.pressed || key.sustained color := if pressed { pressed_white_key_color } else { white_key_color } height := if pressed { kh + 5 } else { kh } - app.gg.draw_rounded_rect(startx, starty, kw, height, f32(kw) / 6, color) - app.gg.draw_empty_rounded_rect(startx, starty, kw, height, f32(kw) / 6, gx.black) - app.gg.draw_text(int(startx + kw / 2), wh - 30, note_names[midi % octave.len], text_cfg(midi)) + app.gg.draw_rounded_rect_filled(startx, starty, kw, height, f32(kw) / 6, color) + app.gg.draw_rounded_rect_empty(startx, starty, kw, height, f32(kw) / 6, gx.black) + app.gg.draw_text(int(startx + kw / 2), wh - 30, note_names[midi % octave.len], + text_cfg(midi)) i++ } i = 0 @@ -84,35 +94,43 @@ fn (app &App) draw() { bkw, bkh := app.key_width * 2 / 3, app.key_height * 2 / 3 // draw black keys on top - for midi := byte(app.start_note); i < app.white_key_count - 1; midi++ { + for midi := u8(app.start_note); i < app.white_key_count - 1; midi++ { x := octave[(midi + 1) % octave.len] - if x == .white { i++ continue } else { midi++ } - if midi > 127 { break } + if x == .white { + i++ + continue + } else { + midi++ + } + if midi > 127 { + break + } key := app.keys[midi] startx := i * kw + bkw pressed := key.pressed || key.sustained color := if pressed { pressed_black_key_color } else { black_key_color } height := if pressed { bkh + 3 } else { bkh } - app.gg.draw_rect(startx, starty, bkw, height, color) - app.gg.draw_text(int(startx + kw / 3), int(wh - app.key_height / 3 - 20), note_names[midi % octave.len], text_cfg(midi)) + app.gg.draw_rect_filled(startx, starty, bkw, height, color) + app.gg.draw_text(int(startx + kw / 3), int(wh - app.key_height / 3 - 20), note_names[midi % octave.len], + text_cfg(midi)) i++ } } // note_pos returns the x coordinate of a note bar and its width // TODO -fn (app &App) note_pos(note byte) (f32, f32) { +fn (app &App) note_pos(note u8) (f32, f32) { if octave[note % octave.len] == .white { return f32(note - app.start_note) * app.win_width / app.white_key_count / 1.75, app.key_width } else { - return f32(note - app.start_note) * app.win_width / app.white_key_count / 1.75 + 1/2, app.key_width * 2 / 3 + return f32(note - app.start_note) * app.win_width / app.white_key_count / 1.75 + 1 / 2, app.key_width * 2 / 3 } } [inline] -fn text_cfg(note byte) gx.TextCfg { +fn text_cfg(note u8) gx.TextCfg { size := if octave[note % octave.len] == .black { 18 } else { 32 } - return { + return gx.TextCfg{ color: note_colors[note % octave.len] size: size align: .center @@ -122,7 +140,7 @@ fn text_cfg(note byte) gx.TextCfg { } [inline] -fn note_color(note byte, vol byte) gx.Color { +fn note_color(note u8, vol u8) gx.Color { c := note_colors[note % octave.len] $if !unplayable ? { if !is_playable(note) { @@ -136,10 +154,10 @@ fn note_color(note byte, vol byte) gx.Color { // lighten lightens `color` by a rate of `amount`. An `amount` < 0 means that `color` is darkened instead. [inline] fn lighten(color gx.Color, amount f32) gx.Color { - return { - r: byte(color.r * amount) - g: byte(color.g * amount) - b: byte(color.b * amount) + return gx.Color{ + r: u8(color.r * amount) + g: u8(color.g * amount) + b: u8(color.b * amount) } } @@ -181,6 +199,7 @@ fn event(e &gg.Event, mut app App) { app.t = 0 } } + // TODO if app.i > 10 { app.i -= 10 @@ -223,9 +242,8 @@ fn (mut app App) resize() { // calculate ideal key count/width based on the current window width app.white_key_count = int(f32(ww) / default_key_width + 0.5) // round app.key_width = f32(ww) / app.white_key_count // will be 45 ± some decimal - if app.start_note + app.white_key_count >= 127 { - app.start_note = byte(128 - app.white_key_count) + app.start_note = u8(128 - app.white_key_count) } app.check_bounds() } @@ -236,14 +254,24 @@ fn (mut app App) check_bounds() { app.start_note = 0 } - mut midi := byte(app.start_note) + mut midi := u8(app.start_note) for _ in 0 .. app.white_key_count { - if octave[midi % octave.len] == .black { midi += 2 } else { midi++ } + if octave[midi % octave.len] == .black { + midi += 2 + } else { + midi++ + } + } + if midi <= 128 { + return } - if midi <= 128 { return } for midi > 127 { - if octave[midi % octave.len] == .black { midi -= 2 } else { midi-- } + if octave[midi % octave.len] == .black { + midi -= 2 + } else { + midi-- + } app.start_note-- } diff --git a/util.v b/util.v index 8a7b4e0..bd9de83 100644 --- a/util.v +++ b/util.v @@ -1,19 +1,37 @@ [inline] fn min(a T, b T) T { - if a < b { return a } else { return b } + if a < b { + return a + } else { + return b + } } [inline] fn max(a T, b T) T { - if a > b { return a } else { return b } + if a > b { + return a + } else { + return b + } } [inline] fn clamp(x T, min T, max T) T { - if x < min { return min } else if x > max { return max } else { return x } + if x < min { + return min + } else if x > max { + return max + } else { + return x + } } [inline] fn sign(x T) i8 { - if x < 0 { return -1 } else { return 1 } + if x < 0 { + return -1 + } else { + return 1 + } }