alda-lang / alda-core

The core machinery of Alda
80 stars 26 forks source link

[WIP] Midi import #30

Closed gdpelican closed 3 years ago

gdpelican commented 7 years ago

For #25

Alright, I've made some decent progress with this. So far it's able to read some notes from a simple midi file, and store them as data in a Seq which includes info about the pitch, volume, duration, start time, instrument (although it's just a hex instrument atm, need to do some sort of map from MIDI instruments to Alda instruments yet...) etc. Sample output below:

(import-midi "./examples/midi/twotone.mid")
({
  :instrument 0,
  :start 0,
  :channel 0,
  :pitch 72,
  :duration 11520,
  :volume 40
} {
  :instrument 0, 
  :start 1440,
  :channel 0,
  :pitch 74,
  :duration 7200,
  :volume 40
})

Question is, where do I go from here? Do I try to output some data like that outlined in the docs, which could then be transformed into an Alda score somehow?

Also this is my first evar clojure, so code feedback more than welcome too!

daveyarwood commented 7 years ago

Excellent work so far! I'll take a closer look a bit later when I have some time and leave some code review comments/thoughts.

I like your approach where the first step is to translate the MIDI data into data that looks sort of like the score data that results from processing an Alda score. What we want to do from here is to generate a string of Alda code.

I don't know too much about what kind of data is in a MIDI file, but are the note-lengths always expressed in milliseconds instead of standard notation (e.g. quarter, eighth, etc.)? If we have them in standard notation, then we can just reuse the same note lengths when we generate the Alda code. If all we have is the millisecond lengths, then I think we might be able to determine the note lengths (in standard notation) by working backwards from the length in milliseconds, along with the tempo.

For example, if we know the tempo is 120 bpm, and a note is 500 milliseconds long, then we could conclude that the note is one beat long and thus represent it as a quarter note. 60 divided by the tempo bpm gives you the length of 1 beat in seconds, at that tempo. e.g. at 120 bpm, 60/120 = 0.5, which means 1 beat = 0.5 seconds or 500 ms. If the note is 250ms long, then we could compare that to the 500ms = 1 beat rule and conclude that the note is half a beat long, which would be an eighth note.

The trouble is that notes are not going to be an exact number of milliseconds. For example, if a quarter note at 120 bpm is played staccato, it is still conceptually a quarter note, but it might only last 250-400 ms instead of the full 500. I'm not sure how to reverse engineer this from a MIDI file, so this could be a little tricky. :thinking:

gdpelican commented 7 years ago

Hm yeah, I think there are other events (other than instrument change, note on, etc) which set and change the tempo, so we'll want to include those as well, and then do some fiddling with the durations to relate them to the standard note lengths, and if they're off we might be able to (quant) them based on how far off they are.

daveyarwood commented 3 years ago

Closing - see https://github.com/alda-lang/alda/issues/326#issuecomment-753378770