Pomax / arduino-midi-recorder

Let's build an Arduino-based MIDI recorder!
27 stars 4 forks source link

Playback & SysEx? #11

Closed Klokdoc closed 11 months ago

Klokdoc commented 2 years ago

First of all, what a good idea. I'm still using a 3 1/2" disc recorder/player which is becoming unreliable. I'd like to build a similar device that would also play back. I'd have to record all the SysEx codes as well, my instrument relies on them. It's a three manual electronic organ with pedals so has four channels, all on one track, and stops, swell pedals, etc are all done by SysEx codes (0F?). MIDI files produced by this instrument will only work on this instrument, it's a custom design. Is this feasible? Thanks, Chris

Pomax commented 2 years ago

It should be, there's only a handful of events, so you'd want to update the number of event codes in the code and then you can add handlers for each in the section where the event handling is defined. You may have to have a look at http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html to makes sure you're writing event data in the right order, but once it's in the .mid file, you should be good to go (although if your device is finnicky about playback, it might want the true track length, in which case you'll need to run that python script first. Or figure out how to update the length bytes while the file is still open in append mode without conflicting with new incoming data (if you do, let me know! =D)

The one hard limitation is that this records in single track mode, so if you need to record multiple channels at once, that'd probably require a bit of an overhaul because that changes what the header needs to look like and some of the data write instructions.

ColbyDAllen commented 1 year ago

How hard would it be to implement a looper with Play/Record functionality that updates an existing SMF format 0 .mid file during playback?

Say you're trying to recorder a drum pattern for instance, so only one channel is needed, and you're just playing a different pitch assigned to a different percussion instrument. Could you write a second line over your first pattern on the same channel, different pitch? Like an audio overdub, but a midi-overdub? Like this:

|| "I'm MIDI file (A)... ...and together we are..." || || "And I'm MIDI file (B)... ...and together we are..." ||

ONE OVERDUBBED .MID FILE!!! Lol.

Or maybe simultaneous play record would only be possible if the file being recorded to was not the same one being played?

Just trying to wrap my head around feasibility, whether I'd need a second storage device for playback, and whether a fresh overhaul would make more sense.

Best, Colby

Pomax commented 1 year ago

That sounds like a MIDI looper, of which there are many already =)

ColbyDAllen commented 1 year ago

Beautiful! I've tried nearly every other combination of keywords, especially "sequencer" -related projects, but I see you're not kidding. Will be looking into this tomorrow. Thank you.

ColbyDAllen commented 11 months ago

I was mulling this over this morning, not necessarily SysEx events, but have calls/callbacks outside of the looping Note-On events:

Do you think it's possible to have multiple calls to the "void writeToFile(byteType, byte b1, byte b2, int delta)" function?

/*
    For instance have the original:
*/
void handleNoteOn(byte channel, byte pitch, byte velocity) {
  writeToFile(NOTE_ON_EVENT, pitch, velocity);
}

/*
    AND have separate function:
*/
void ThisNoteOnLOOPED(byte channel, byte pitch, byte velocity) {  
  writeToFile(NOTE_ON_EVENT, pitch, velocity);
}

...working simultaneously...

/*
    ...both being fed into the function:
*/
void writeToFile(byte eventType, byte b1, byte b2, int delta) {
  if (!file) return;
  writeVarLen(file, delta);
  file.write(eventType);
  file.write(b1);
  file.write(b2);
}

...without breaking how the bytes are being fed to the SD card?

ColbyDAllen commented 11 months ago

There's a much larger sketch I'm using to toy with this idea, but the above is the distilled concept. Obviously you'd want a corresponding "void ThisNoteOffLOOPED" function for the additional stream of notes...

I think the trouble might be that the note-on and note-off events may get scrambled if you play fast enough between looping notes. Haha, probably what "Type 1" SMFs are for?

Happy to share the full sketch if you'd be interested.

Best, Colby

Pomax commented 11 months ago

no, what you wrote as "simultaneous" code will write completely different bytes.

(note that I'm closing this issue mostly because we drifted well away from the original issue at this point)

ColbyDAllen commented 11 months ago

Sorry about that, and got you. Thanks for clarifying!

Pomax commented 11 months ago

feel free to open a new issue though!