Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Informatique musicale : créer un séquenceur pas-à-pas avec Python

Informatique musicale : créer un séquenceur pas-à-pas avec Python

Pycon-Fr 2016, Rennes

Aujourd’hui, que ce soit via « Maschine » de Native Instruments, « Push » de Ableton, ou encore via des machines à l’esprit plus vintage comme le « Dark Time » de Doepfer ou des émulations de vieilles boites à rythmes, les musiciens retrouvent le goût du séquencement pas à pas ou « Step Sequencing ».
Le bidouilleur que je suis avait envie de détourner son matériel pour reproduire ce type d’outil de création…

Après une introduction au MIDI et aux principes d’un séquenceur, nous verrons comment nous pouvons, avec Python et la librairie mido, « hacker » un certain synthétiseur hardware pour en faire un séquenceur pas à pas, à l’aide d’une boucle d’événements. Nous essaierons même de l’interfacer avec Ableton Live pour contrôler non plus les sons du synthétiseur, mais des samples !

Vidéo disponible ici : https://www.pycon.fr/2016/videos/informatique-musicale-creer-un-sequenceur-pas-a-pas-avec-python.html

-----
Nowadays, using Native Instruments "Maschine", Ableton "Push", or machines with a vintage heritage such as Doepfer "Dark Time", musicians enjoy getting back to a special kind of sequencing which is step sequencing.
I wanted to hack with my current hardware to try and do the same as these tools.

After an introduction to MIDI and notions of sequencing, we will see how, thanks to Python and the Mido library, we can hack hardware to turn it into a step sequencer, using an event loop. We will try and interface our program with Ableton Live to control not only sounds from the synthetizer, but also trigger samples!

Video (in French) available @ https://www.pycon.fr/2016/videos/informatique-musicale-creer-un-sequenceur-pas-a-pas-avec-python.html

Yann Gravrand

October 16, 2016
Tweet

More Decks by Yann Gravrand

Other Decks in Technology

Transcript

  1. MUSICAL INSTRUMENTS Can be played by humans Some can be

    "played" by computers: Synthetizers Samplers ...
  2. STEP SEQUENCER A 4/4 measure is divided into: 4 quarter

    notes Each quarter note is divided into 4 steps --> A sequence is usually 16 steps long
  3. STEP SEQUENCER For each step, we define: the note /

    pitch other attributes: length... ... and activate it or not
  4. USING A STEP SEQUENCER "Live" mode: turn steps on and

    off in real time, adjust pitch, length... "Step by step" mode: for each step, define the note attributes. No timing, no rush
  5. PART 2: THE PROJECT Project goals MIDI Using mido The

    Dirty Part: blocking, threads, asyncio...
  6. PROJECT GOALS Make the synthetizer play notes using Python Modify

    and turn notes on / off to create a sequence Implement "step by step" and "live" modes Change tempo in real time Make interactions possible with any controller... ... Starting with mine, of course :)
  7. MIDI: MUSICAL INSTRUMENT DIGITAL INTERFACE Extremely old standard: 1983! Still

    largely in use today To synchronize and communicate between devices Message types: Notes (NOTE ON, NOTE OFF) Control Change (Ex: Filter resonance, Hold pedal...) Program Change (Change instrument) Sys ex ...
  8. WE WILL NEED TO SPEAK MIDI WITH DEVICES Midi input:

    pads pressed, keys pressed, knobs turned... Midi output: play a note, turn a LED on...
  9. MIDI INPUT: RECEIVING MESSAGES Message reception blocks So if we

    want to do something else in parallel, we have to handle this in a thread or coroutine or...? inport = mido.open_input() msg = inport.receive() # Blocking call
  10. MIDI OUTPUT: PLAYING NOTES --> BEEEEEEEEEEEEEEEEEEEE... --> ... EEEP. To

    play notes, we need a timer between NOTE_ON and NOTE_OFF (note duration). time.sleep? import mido outport = mido.open_output() msg = mido.Message('note_on', note=100, velocity=3) outport.send(msg) outport.send(mido.Message('note_off', note=100))
  11. ALIGNING NOTES (STEPS) WITH TEMPO Naive implementation: Two problems: time.sleep

    also blocks, so we have to handle it in a thread or coroutine or... Waking up, sleeping for X seconds, waking up...: the tempo slowly drifts while True: outport.send(mido.Message(...)) time.sleep(tempo.step_duration)
  12. A STORY ABOUT BLOCKING AND TIMING So how can we

    have: 1. independent yet connected blocking loops? 2. timing accuracy to keep a stable tempo?
  13. SOLUTIONS Threads Many queues to avoid shared state Coroutines with

    asyncio Everything in a single thread, less concurrency issues Ok since our app is I/O bound ...But we have to modify mido to insert yield from or await... Greenlets with gevent Monkey patches time.sleep so we can use mido as is and have greenlets Drifting? calculate absolute times
  14. IMPLEMENTING A CONTROLLER Map messages from controller (pad pressed) to

    sequencer actions (toggle step) Send messages to controller for feedback (LEDs...)
  15. INTERPRETING EVENTS Some events are represented by a single message

    Others are the result of a sequence of messages (ex: NPRN LSB, MSB) Solution: a RulesChain Each Rule matches a message A state automaton keeps track of the matched rules Flexible rules evaluation engine self.register('FILTER', self.on_cc, RulesChain(Rule(type_='control_change', control='74'), Rule(type_='control_change', control='27', value='0')) )
  16. REACTING TO SEQUENCER STATES Event system: self.sequencer.on(SequencerEvents.STEP_BEGIN, self, self.on_step_begin) ...

    def on_step_begin(self, step): # Turn on current step LED self.sequencer.output(self, *msb_lsb_output(60, 0, 32 + step.pos))
  17. IN ACTION! Bass pattern Drum pattern 1 Drum pattern 2

    Mozart pattern (32-step sequence) Daft punk - da funk
  18. FUTURE Plans: Release in Open Source Chords (especially important for

    a drum machine...) Multi track Load / save to midi External tempo sync Reactive Web interface (iPad, ...) Conquer the world!