midi: add basic polyphony
Timing is still broken/inconsistent between emulators and I don't yet understand why.
This commit is contained in:
parent
778138971f
commit
9b57987717
@ -42,7 +42,7 @@ midi_note_to_oct_fns(const int8_t midi_note)
|
|||||||
// maximum delay of 3258 days
|
// maximum delay of 3258 days
|
||||||
using fp48_16 = fp<uint64_t, uint64_t, 16>;
|
using fp48_16 = fp<uint64_t, uint64_t, 16>;
|
||||||
|
|
||||||
constexpr uint8_t tactl = 7; // F/128
|
constexpr uint8_t tactl = 6; // F/128
|
||||||
constexpr uint8_t tima = 0xfe;
|
constexpr uint8_t tima = 0xfe;
|
||||||
|
|
||||||
constexpr fp48_16 increment_ms{2902, 32394}; // 2902.494293212890625
|
constexpr fp48_16 increment_ms{2902, 32394}; // 2902.494293212890625
|
||||||
@ -122,6 +122,34 @@ void auto_vector_1(void)
|
|||||||
timer_fired = 1;
|
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()
|
void midi_step()
|
||||||
{
|
{
|
||||||
const uint32_t sine_start = reinterpret_cast<uint32_t>(&_sine_start);
|
const uint32_t sine_start = reinterpret_cast<uint32_t>(&_sine_start);
|
||||||
@ -164,7 +192,13 @@ void midi_step()
|
|||||||
switch (midi_event.type) {
|
switch (midi_event.type) {
|
||||||
case midi::midi_event_t::type_t::note_on:
|
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;
|
scsp.ram.u32[3] = midi_event.data.note_on.note;
|
||||||
|
|
||||||
@ -179,17 +213,26 @@ void midi_step()
|
|||||||
slot.LFO = 0;
|
slot.LFO = 0;
|
||||||
slot.MIXER = MIXER__DISDL(0b110);
|
slot.MIXER = MIXER__DISDL(0b110);
|
||||||
|
|
||||||
|
if (v.count == 1)
|
||||||
kyonex = 1;
|
kyonex = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case midi::midi_event_t::type_t::note_off:
|
case midi::midi_event_t::type_t::note_off:
|
||||||
{
|
{
|
||||||
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 < 0) error();
|
||||||
|
|
||||||
|
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;
|
slot.LOOP = 0;
|
||||||
scsp.reg.slot[0].SA |= SA__KYONEX;
|
scsp.reg.slot[0].SA |= SA__KYONEX;
|
||||||
|
|
||||||
kyonex = 1;
|
kyonex = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -227,6 +270,14 @@ void init_midi()
|
|||||||
|
|
||||||
state.delta_time_ms = fp48_16{0};
|
state.delta_time_ms = fp48_16{0};
|
||||||
state.midi.tempo = 500000; // default tempo
|
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()
|
void main()
|
||||||
|
@ -103,10 +103,7 @@ int parse(uint8_t const * start)
|
|||||||
switch (mtrk_event.event.type) {
|
switch (mtrk_event.event.type) {
|
||||||
case midi::event_t::type_t::midi:
|
case midi::event_t::type_t::midi:
|
||||||
std::cout << " midi: " << '\n';
|
std::cout << " midi: " << '\n';
|
||||||
|
|
||||||
dump_midi(mtrk_event.event.event.midi);
|
dump_midi(mtrk_event.event.event.midi);
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case midi::event_t::type_t::sysex:
|
case midi::event_t::type_t::sysex:
|
||||||
std::cout << " sysex: " << '\n';
|
std::cout << " sysex: " << '\n';
|
||||||
@ -120,7 +117,7 @@ int parse(uint8_t const * start)
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(buf - track_start == track_length);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -383,17 +383,35 @@ def parse_track(buf):
|
|||||||
events.append(event)
|
events.append(event)
|
||||||
return buf, Track(events)
|
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):
|
def parse_file(buf):
|
||||||
buf, header = parse_header(buf)
|
buf, header = parse_header(buf)
|
||||||
print(header)
|
#print(header)
|
||||||
assert header.ntrks > 0
|
assert header.ntrks > 0
|
||||||
tracks = []
|
tracks = []
|
||||||
for track_num in range(header.ntrks):
|
for track_num in range(header.ntrks):
|
||||||
buf, track = parse_track(buf)
|
buf, track = parse_track(buf)
|
||||||
tracks.append(track)
|
tracks.append(track)
|
||||||
print(f"track {track_num}:")
|
#print(f"track {track_num}:")
|
||||||
for event in track.events:
|
for i, event in enumerate(track.events):
|
||||||
print(' ' + repr(event))
|
#simulate_note(i, event)
|
||||||
|
print(event)
|
||||||
|
|
||||||
print("remaining data:", len(buf))
|
print("remaining data:", len(buf))
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
Loading…
x
Reference in New Issue
Block a user