good afternoon, i am working on a project that takes input from a usb midi controller on the host port, saves each event to a struct containing type, data1, data2, channel, and timestamp as shown here:
records each event to a temporary file during record mode
and plays it back in playback mode.
in general it kind of works except that not all events get a timestamp and sometimes note-on and note-off are reversed, so everytime i record a little melody or sequence it plays back something that uses the same notes but sounds completely different. Although i think it's interesting to hear the teensy's creative vision on the things i want it to play, I would prefer it to just play the things i recorded. I added some serial print functions to show what it's doing with the input and outputs and this is the result:
Seems to me not every event gets assigned a timestamp so it's no surprise that certain messages don't get played back, where could the problem lie?
I tried multiple things, like adding the data to the struct in the handler function:
i also tried putting the timer function into the handler, different structs for note on and off, different ways of saving the data (first as bytes, then as midi::dataByte al though these seem like cosmetic details to me) and a lot of other stuff but to no avail. I must admit i know more about music than software and most of this code was written in about half an hour by an acquaintance who is a software engineer but does not know that much about the specific libraries for the teensy, it makes me wonder if we've reinvented the wheel in a way that is not exactly optimal?
Code:
struct MidiEvent {
uint32_t delta_ms;
midi::MidiType type ;
midi::DataByte data1;
midi::DataByte data2;
midi::Channel channel;
};
Code:
void recordTick() {
if (!recordFile) {
return;
}
while (midi2.read()) {
uint32_t now = millis();
Ev.delta_ms = now - lastEventMillis; // Delta t.o.v. vorige event
lastEventMillis = now;
Ev.type = midi2.getType();
Ev.data1 = midi2.getData1();
Ev.data2 = midi2.getData2();
Ev.channel = midi2.getChannel();
recordFile.write((const byte *)&Ev, sizeof(Ev));
Code:
void playTick() {
if (!playFile) {
Serial.println("no file found");
return;
}
if (!hasNextEvent) {
if (LOOP_PLAYBACK) {
restartPlayback();
} else {
stopPlay();
}
return;
}
uint32_t elapsed = millis() - playbackStartMillis; // Hoe lang spelen we al
while (hasNextEvent && elapsed >= playbackElapsedAtNext) {
if (nextEvent.type == 144) {
MIDI.sendNoteOn(nextEvent.data1, nextEvent.data2, nextEvent.channel);
Serial.println();
Serial.print("type=");
Serial.print(nextEvent.type);
Serial.print("channel=");
Serial.print(nextEvent.channel);
Serial.print(", note=");
Serial.print(nextEvent.data1);
Serial.print(", velocity");
Serial.print(nextEvent.data2);
Serial.print(", time=");
Serial.print (elapsed);
} else if (nextEvent.type == 128) {
MIDI.sendNoteOff(nextEvent.data1, nextEvent.data2, nextEvent.channel);
Serial.println();
Serial.print("type=");
Serial.print(nextEvent.type);
Serial.print("channel=");
Serial.print(nextEvent.channel);
Serial.print(", note=");
Serial.print(nextEvent.data1);
Serial.print(", velocity");
Serial.print(nextEvent.data2);
Serial.print(", time=");
Serial.print (elapsed);
} ;
if (!readNextEvent()) {
if (LOOP_PLAYBACK) {
restartPlayback();
} else {
stopPlay();
}
return;
}
elapsed = millis() - playbackStartMillis;
}
}
in general it kind of works except that not all events get a timestamp and sometimes note-on and note-off are reversed, so everytime i record a little melody or sequence it plays back something that uses the same notes but sounds completely different. Although i think it's interesting to hear the teensy's creative vision on the things i want it to play, I would prefer it to just play the things i recorded. I added some serial print functions to show what it's doing with the input and outputs and this is the result:
Code:
record mode
Note On, ch=1, note=29, velocity=127
, time=984
Note Off, ch=1, note=29, velocity=0
, time=173
Note On, ch=1, note=31, velocity=127
Note Off, ch=1, note=31, velocity=0
, time=172
Note On, ch=1, note=33, velocity=127
, time=344
Note Off, ch=1, note=33, velocity=0
Note On, ch=1, note=35, velocity=127
Note Off, ch=1, note=35, velocity=0
recording stopped
playmode
type=144channel=1, note=29, velocity127
, time=984
type=128channel=1, note=29, velocity0
, time=1157
type=128channel=1, note=31, velocity0
, time=1329
type=144channel=1, note=33, velocity127
, time=1673
I tried multiple things, like adding the data to the struct in the handler function:
Code:
void handleNoteOff(byte channel, byte note, byte velocity) {
MIDI.sendNoteOff(note, velocity, channel);
Ev.type = midi::NoteOff;
Ev.data1 = note;
Ev.data2 = velocity;
Ev.channel = channel;