amiika / ziffers

Numbered musical notation for composing algorithmic and generative melodies
MIT License
81 stars 5 forks source link

midi support #1

Closed yanndepps closed 5 years ago

yanndepps commented 5 years ago

Hi and thank you, ziffers looks like an amazing additon to Sonic-Pi ! Is it already possible to use ziffers with midi, in order to play external instruments ? If not, would you try to implement midi support later on ? All the best !

amiika commented 5 years ago

I'm glad you like it! I added zmidi function that can play midi notation with the repeats and stuff, but thats probably not what you mean by midi support. I havent tried Sonic Pi with external instruments. Do you mean getting the sound from midi input and play it using pitch alternated sample or binaural frequencies? That could work.

yanndepps commented 5 years ago

yes I meant using sonic-pi+ziffers to play external vst instruments, via midi. ziffers syntax looks deep, elegant and concise, and it would be great to be able to use it to compose with external sound sources, hence my idea of "midi support". thanks a lot for adding midi notation already.

amiika commented 5 years ago

Im not so familiar with the MIDI yet (one of the reasons i wrote ziffers). I already tried zmidi with virtual keyboard using loopMidi&VMPK to get something in to Sonic Pi and its starting to work out:

live_loop :midi_piano do
  use_real_time
  note, velocity = sync "/midi/loopmidi_port/0/1/note_on"
  zmidi note, {sample: :ambi_glass_rub, key: :e}, {rateBased: true}
end

Nice glassy sounds from the keyboard. However, you could also use ziffers to produce arrays of midi notes to be sent to midi output, like in one of the examples: https://github.com/amiika/ziffers/blob/master/examples/ievan_polka.rb

amiika commented 5 years ago

It appears you can use ziffers with MIDI out fairly easy. Great idea! Easiest way is to turn the ziffers Hash array to ring and play it trough using midi command:

r = zparse "?????????????????????????", key: :d, scale: :minor_pentatonic
r = r.ring

live_loop :midi_out do
  n = r.tick
  midi n[:note]
  sleep n[:sleep]
end

Ill write a method later that will use all of the features like: midi_note_on, midi_note_off, midi_cc, midi_pitch_bend

yanndepps commented 5 years ago

That is exactly what i was thinking about, thank you so much. It works beautifully ! The next step I'd look at is, how to manage chords, inversions, progessions and whatnot ( using midi, that is ). Thank you @amiika, nice work !

amiika commented 5 years ago

I added port and channel to zplay, so you can now play it directly from zplay for example:

zplay("|:%1 ii 554e56 iv 12323456 %2 i q 334e56 %1 v e75645342:|", chordRelease: 1.5 ,port: "loopmidi", channel: 2)

In this case chordRelease: 1.5 sets midi sustain to 1.5. By default its chordRelease: 1 and chordSleep: 0 so it plays simultaniously in sonic.

I guess some chords could cause issues with the midi out if there are concurrent notes. I could also add escape characters for port and channel so you could change those in the middle say like if "port = X" you could do "XchordPort v^dim XmelodyPort 1234".

amiika commented 5 years ago

Tried to experiment sliding as well without much success. Do you have any idea how one could implement note sliding using midi_cc or midi_pitch_bend?

I tried something like:

midi_note_on 40, port: "loopmidi"
sleep 1
midi_pitch_bend 0.8, port: "loopmidi"
sleep 5
midi_note_off 40, port: "loopmidi"
midi_note_on 40, port: "loopmidi"
sleep 1
midi_cc 40, 50, port: "loopmidi"
sleep 1
midi_note_off 50, port: "loopmidi"
yanndepps commented 5 years ago

hmm not sure. I've been using this to fade midi values:

fade = (line 0.95, 0.05, steps: 8, inclusive: true).mirror
live_loop :mc do
  midi_cc 1,
    val_f: fade.tick,
    channel: 1
  sleep 0.5
end

On another hand, thanks a lot for your work on zplay, works very well but I didn't have much time to test, will try more in depth later. It seems that using +/- for octave transpose doesn't do anything, but I may be missing something.

amiika commented 5 years ago

I also wonder is midi out sustain should be same as the release or attack+decay+sustain+release ... or something that should be controlled with midi_cc etc.

amiika commented 5 years ago

It seems that using +/- for octave transpose doesn't do anything, but I may be missing something.

It changes the pitch parameter, which can be used with the play function, like play n[:note], pitch: n[:pitch]. If you are using some other way to play the hash array you need to add the pitch to the notes, like in ievan polka example: https://github.com/amiika/ziffers/blob/master/examples/ievan_polka.rb#L8

... but i could change the implementation so that it would add the pitch directly to the notes. (I had some reason to do it this way but cant remember it any more).

amiika commented 5 years ago
fade = (line 0.95, 0.05, steps: 8, inclusive: true).mirror
live_loop :mc do
  midi_cc 1,
    val_f: fade.tick,
    channel: 1
  sleep 0.5
end

This doesnt seem to do anything on its own. Can you give (or point to) some example that would play some notes and then do something with the control?

yanndepps commented 5 years ago

This will make the modwheel (midi cc 1) fade back & forth, it's a generic technique for sliding values, more or less. I don't really know how to apply it to notes & controls indeed, but it may be time to move our conversation to the official forum, where more advanced users could come in rescue : https://in-thread.sonic-pi.net/latest

amiika commented 5 years ago

Ah, i didnt notice that midi controls are channel specific. List of channels can be found from midi specs. Ill try to experiment bit more. Meanwhile i could write something about ziffers to the in-thread forum.

amiika commented 5 years ago

I'm closing this issue and opening new more specific ones. Btw, chord degrees can be changed using % and +/- integer like %-4 or %2. If you are having any suggestions or have ideas how to change the syntax please create new issue :)