Using Real-time list of midi messages in this SCAMP script

17 Views Asked by At

Just a quick question about the MIDI flow within this script I’m using. Ive recently been building on my collection of compositional tools when I came across the isorhythm script built by Marc Evanstein using SCAMP…

To summarise, I have midi messages being sent from my DAW (Reaper) into the script, the script then takes these messages and makes a list of 6 midi notes which then get sent to the “do_isorhythm” function that is being forked later on in the script. The problem is, despite defining the list and inputting it into the “args=” of the “do_isorhythm” fork it just isn’t being registered.

Im assume it could be a few things but my main guess is the timing of the script and that the midi information isn’t being passed to the function in time/sync, here’s the code:

from scamp import *
from collections import namedtuple
import datetime
from itertools import cycle
import random
from random import randint

print("Welcome to ISORYTHM MIDI/SCORE GENERATOR USING EX MACHINA (REAPER) INPUT:")

USE_PLAY_NOTE=False
s = Session()
t = Session(tempo=140)
inst_1 = s.new_midi_part("melo-1", 0)

class Manipulator:
    def __init__(self):
        self.session = Session()
        self.session.print_available_midi_output_devices()
        self.session.print_available_midi_input_devices()
        try:
            self.piano = self.session.new_midi_part("piano", midi_output_device=0, num_channels=8) # Scamp to QSynth
        except:
            print("Failed to open MidiLoop Port for output")      

        self.midi_messages = []  # List to store MIDI pitch values
        self.message_count = 0    # Counter for MIDI messages
        self.count_started = False  # Flag to track if the count has started

    def midi_callback(self, midi_message):
        code, pitch, volume = midi_message
        
        if pitch == 0 and volume > 0:  # Start the count when MIDI message "0" is received
            self.count_started = True

        if self.count_started:
            if volume > 0:  # Only append the pitch value if it's an "on" message
                self.midi_messages.append(pitch)  # Append the pitch value to the list
                self.message_count += 1

                if self.message_count == 4:
                    # Insert "None" randomly into the list at two random positions
                    for _ in range(2):
                        index = random.randint(0, len(self.midi_messages))
                        self.midi_messages.insert(index, None)
                    
                    # Print the captured MIDI messages in the desired format
                    print("Captured MIDI messages:")
                    print(self.midi_messages)
                    # Reset counter and clear the list
                    self.message_count = 0
                    self.midi_messages.clear()
            if volume > 0:  # This is an on-event
                self.onTime = datetime.datetime.now()
                self.note = Note(pitch, volume, self.onTime.timestamp())
   
            else:  
                self.offTime = datetime.datetime.now()
                delta = self.offTime - self.onTime
                self.note.duration = float(delta.total_seconds())

                # Eventually do something with the note here
                if USE_PLAY_NOTE:
                    self.piano.play_note(self.note.pitch, .8, self.note.duration) 
                else:
                    noteReference = self.piano.start_note(self.note.pitch, .8)
                    wait(self.note.duration)
                    noteReference.end()

    def Run(self):
        def do_isorhythm(inst_1, color, talea, voluminor=(1.0,)):
            for pitch, volume, dur in zip(cycle(color), cycle(voluminor), cycle(talea)):
                inst_1.play_note(pitch, volume, dur)
        
        try:     
            self.session.register_midi_listener(1, self.midi_callback) #[Port 4]: Input from Virtual Keyboard
        except:
            print("Failed to open MidiLoop Port for input")                
        #self.session.wait_forever()
        s = Session()
        t = Session(tempo=140)
        global_midi = self.midi_messages
        # Call do_isorhythm within Run
        #For the lengths of each argument for the color,voluminor,dur adjust the lengths to prime fibonachi like max/msp engine that way you have "prime fibonaci isorythms" 
        fork(do_isorhythm, args=(inst_1, [64, 62, None, 65, 67, None, 62],
                     [1.0, 0.5, 0.75, 0.25, 1.0], [0.5, 0.7, 0.3]))
        fork(do_isorhythm, args=(inst_1, [None, 64, 67, 69, None],
                     [2.0, 0.5, 1.0], [0.3, 0.5, 0.4, 0.6, 0.9, 0.6, 0.4]))

m = Manipulator()
m.Run()
wait_forever() 

Currently, the fork function looks like this:

        fork(do_isorhythm, args=(inst_1, [64, 62, None, 65, 67, None, 62],
                     [1.0, 0.5, 0.75, 0.25, 1.0], [0.5, 0.7, 0.3]))
        fork(do_isorhythm, args=(inst_1, [None, 64, 67, 69, None],
                     [2.0, 0.5, 1.0], [0.3, 0.5, 0.4, 0.6, 0.9, 0.6, 0.4]))

I’m trying to make it work like this, but having problems:

     fork(do_isorhythm, args=(inst_1, global_midi,
                 [1.0, 0.5, 0.75, 0.25, 1.0], [0.5, 0.7, 0.3]))
     fork(do_isorhythm, args=(inst_1, global_midi,
                 [2.0, 0.5, 1.0], [0.3, 0.5, 0.4, 0.6, 0.9, 0.6, 0.4]))

This way my live midi input gets sent into the isorhythm function and then outputs it back into my DAW for later processing, any insight into how I can achieve this??

Im new here so please do forgive me if my query hasn’t been formatted to this forum’s standards… any help/guidance is much appreciated!!

Thanks in advance <3

0

There are 0 best solutions below