diff --git a/m68k/midi.cpp b/m68k/midi.cpp index 2128438..3fa6832 100644 --- a/m68k/midi.cpp +++ b/m68k/midi.cpp @@ -42,7 +42,7 @@ midi_note_to_oct_fns(const int8_t midi_note) // maximum delay of 3258 days using fp48_16 = fp; -constexpr uint8_t tactl = 7; // F/128 +constexpr uint8_t tactl = 6; // F/128 constexpr uint8_t tima = 0xfe; constexpr fp48_16 increment_ms{2902, 32394}; // 2902.494293212890625 @@ -122,6 +122,34 @@ void auto_vector_1(void) timer_fired = 1; } +struct vs { + int8_t slot_ix; + int8_t count; +}; + +static int32_t slot_alloc; +static struct vs voice_slot[16][128]; + +#pragma GCC push_options +#pragma GCC optimize ("unroll-loops") +int8_t alloc_slot() +{ + for (int i = 0; i < 32; i++) { + uint32_t bit = (1 << i); + if ((slot_alloc & bit) == 0) { + slot_alloc |= bit; + return i; + } + } + return -1; +} +#pragma gcc pop_options + +void free_slot(int8_t i) +{ + slot_alloc &= ~(1 << i); +} + void midi_step() { const uint32_t sine_start = reinterpret_cast(&_sine_start); @@ -164,7 +192,13 @@ void midi_step() switch (midi_event.type) { case midi::midi_event_t::type_t::note_on: { - scsp_slot& slot = scsp.reg.slot[0]; + struct vs& v = voice_slot[midi_event.data.note_on.channel][midi_event.data.note_on.note]; + if (v.slot_ix == -1) { + v.slot_ix = alloc_slot(); + } + v.count++; + + scsp_slot& slot = scsp.reg.slot[v.slot_ix]; scsp.ram.u32[3] = midi_event.data.note_on.note; @@ -179,16 +213,25 @@ void midi_step() slot.LFO = 0; slot.MIXER = MIXER__DISDL(0b110); - kyonex = 1; + if (v.count == 1) + kyonex = 1; } break; case midi::midi_event_t::type_t::note_off: { - scsp_slot& slot = scsp.reg.slot[0]; - slot.LOOP = 0; - scsp.reg.slot[0].SA |= SA__KYONEX; + struct vs& v = voice_slot[midi_event.data.note_on.channel][midi_event.data.note_on.note]; + if (v.slot_ix < 0) error(); - kyonex = 1; + v.count -= 1; + if (v.count == 0) { + free_slot(v.slot_ix); + v.slot_ix = -1; + + scsp_slot& slot = scsp.reg.slot[v.slot_ix]; + slot.LOOP = 0; + scsp.reg.slot[0].SA |= SA__KYONEX; + kyonex = 1; + } } break; default: @@ -227,6 +270,14 @@ void init_midi() state.delta_time_ms = fp48_16{0}; state.midi.tempo = 500000; // default tempo + + slot_alloc = 0; + for (int j = 0; j < 16; j++) { + for (int i = 0; i < 128; i++) { + voice_slot[j][i].slot_ix = -1; + voice_slot[j][i].count = 0; + } + } } void main() diff --git a/midi/dump.cpp b/midi/dump.cpp index 91b3413..f28fe07 100644 --- a/midi/dump.cpp +++ b/midi/dump.cpp @@ -103,10 +103,7 @@ int parse(uint8_t const * start) switch (mtrk_event.event.type) { case midi::event_t::type_t::midi: std::cout << " midi: " << '\n'; - - dump_midi(mtrk_event.event.event.midi); - - + dump_midi(mtrk_event.event.event.midi); break; case midi::event_t::type_t::sysex: std::cout << " sysex: " << '\n'; @@ -120,7 +117,7 @@ int parse(uint8_t const * start) } assert(buf - track_start == track_length); - std::cout << "trailing/unparsed data: " << buf - track_start << '\n'; + std::cout << "trailing/unparsed data: " << track_length - (buf - track_start) << '\n'; } return 0; } diff --git a/midi/parser.py b/midi/parser.py index 07e6ee3..cea0acc 100644 --- a/midi/parser.py +++ b/midi/parser.py @@ -383,17 +383,35 @@ def parse_track(buf): events.append(event) return buf, Track(events) +_slots = set() + +def simulate_note(ix, ev): + if type(ev.event) is NoteOn: + print(repr(ev.event)) + + _slots.add((ev.event.channel, ev.event.note)) + assert len(_slots) <= 32, (hex(ix)) + if type(ev.event) is NoteOff: + print(repr(ev.event)) + try: + _slots.remove((ev.event.channel, ev.event.note)) + except: + print("ix", hex(ix)) + raise + def parse_file(buf): buf, header = parse_header(buf) - print(header) + #print(header) assert header.ntrks > 0 tracks = [] for track_num in range(header.ntrks): buf, track = parse_track(buf) tracks.append(track) - print(f"track {track_num}:") - for event in track.events: - print(' ' + repr(event)) + #print(f"track {track_num}:") + for i, event in enumerate(track.events): + #simulate_note(i, event) + print(event) + print("remaining data:", len(buf)) import sys