Closed PedroAlvesV closed 6 years ago
Hi @PedroAlvesV ,
Currently it is not possible to have overlapping durations within a single track in this API; it would have to be on separate tracks. This would be a nice feature, though I'm not sure how the API would look for that. Do you have any ideas?
-Garrett
Yep. I was thinking about giving the user more control over it. I mean, the NoteEvent
is an awesome abstraction, but, as I pointed, there's this one limitation. Maybe if the user could, by wish, set the On and Off signals, it would solve the problem. So, it would keep the NoteEvent
, but also offer the usage of NoteOn
and NoteOff
.
Another thing that I noticed is that these classes (NoteOn
and NoteOff
) do exactly the same, and what they do is not even enough to justify a single whole class, from the way I see it. Also, they're used exclusively in NoteEvent:buildData()
and in Track:polyModeOn()
.
What I would do (and probably will with LuaMidi haha):
Util
function to create a table like these current NoteOn
/NoteOff
objects (possibly "on_off_signal()
" or something similar)NoteOn
and NoteOff
classes to let the user instantiate them (as stated in the first paragraph)Hi Pedro,
Good ideas. I think I used separate classes for NoteOn
and NoteOff
with the thought that it would be convenient to add more functionality to them later. You're right though, currently they're just containers for properties.
I'm thinking something like this may work to provide the ability to have two simultaneous notes with different durations, where the duration index would line up with the pitch index:
new MidiWriter.NoteEvent({pitch: ['E4','D4'], duration: ['4', '2']})
The problem, though, is how to know where the next NoteEvent
will begin.
As you suggested, we could provide functions which allow you to explicitly turn on/off notes, but the user/developer would need to keep track of timing themselves though so it's just not very user friendly. Do you have a particular need for this, or is it just something you had in mind?
-Garrett
The user would have to be aware of the delta time, that's true, but most people working with MIDI frameworks do. Besides, the NoteEvent
would always be available. I agree that it's very dangerous to use an array of durations. I think NoteEvent
is just fine as it currently is.
I have been wondering about it because I wrote a function that receives a MIDI file and creates LuaMidi objects to represent it. It works pretty fine, actually. The only thing I couldn't manage it to get, yet, is the timing, but that's because I haven't code anything this week haha
However, this overlapping functionality is somehow a basic need. Take as example Stairway to Heaven's intro. It sounds kind of chiptune or something like it, because the arpeggio sounds as if there's a hardware limitation of one note at a time.
I think in the case of Stairway to Heaven, and other similarly played sustained arpeggios, changing the note durations isn't the best approach because it becomes a bit unreadable as musical notation. I understand that you can dial in the exact note length that way though. The notes would still be abruptly cut off instead of trailed off.
For this case I think there should be support in this API for Controller Change events. Then you can apply a sustain pedal as needed for the notes that should be sustained.
Looks like the status code for Control Change is Bn
. Here's a list of messages:
https://www.midi.org/specifications/item/table-3-control-change-messages-data-bytes-2
I'll take a closer look at this when I have some time and try to incorporate into MidiWriterJS.
-Garrett
Hi @PedroAlvesV,
I've added a ControllerChangeEvent
class in 1.5.2 which can be used to add controller events.
track.addEvent([
new MidiWriter.NoteEvent({pitch: ['A4'], duration: '4'}),
new MidiWriter.ControllerChangeEvent({controllerNumber: 1, controllerValue: 127}),
new MidiWriter.NoteEvent({pitch: ['B4'], duration: '4'}),
]);
I think whether or not the control changes are respected will depend on the player you use. But you should now be able to add sustain pedal controls to achieve what we were discussing above. Let me know if you have any issues.
-Garrett
I knew there was an issue somewhere I meant to comment on!
Starting one note on a channel before another ends (legato?), where the second note "chokes" the first seems often to be how slides/glissando are sequenced on 303-style hardware synths (MB-33 & clones, TT-303, x0xb0x...), probably because they tend not to have MIDI implementations sophisticated enough for controller events. Some more sophisticated synths (e.g. Behringer DeepMind 12) also use this same mechanism, the speed of the slide (or none at all) being dependant on a portamento setting.
IIRC MIDI notes on a single channel cannot overlap, so no gap is a primitive way of specifying slide.
However I have not tested this with MidiWriterJS (I am using it to algo-generate MIDI files and play them with hardware) but will give it a go and find out. Thanks!
Is there any way of, in a single track, playing two notes, with different durations, simultaneously?
I mean, imagine an
A4
and anE4
; One whole note, the other quarter note; Both starting together. Is there any way of producing it with this API?The same for arpeggios: is it possible to start a note before stopping the previous one?