midi using pygame

newbie here so excuse my frankenstein code

I am using pygame.midi to get data from a midi controller

here is my basic midi module:

import pygame.midi as pgm

pgm.init()
midin=pgm.Input(2)

def mRead():
        mOut=midin.read(1)
        return mOut

def mRtrn(mRaw,sldr,chan=176):
    if mRaw:
        mChan = mRaw[0][0][0]
        mSld = mRaw[0][0][1]
        mVal = mRaw[0][0][2]
        if mChan==chan:
            if mSld==sldr:
                return mVal
    else:return None

when reading from a device, pygame midi returns an array in the pattern of [[[a,b,c,d],x]] where a,b,c… are the midi information–

if there is no signal it returns []

this works great since you feed the function the slider number and it returns the midi slider output value or None if there is no activity on that slider

so I can call it up in a task where ever I need it

#from within a task declaration 
mCall=mRead()
mGet=mRtrn(mCall,10)

my code is modular so I have a camera module, an actor module, lights, etc… all being imported from a main python file…

these midi functions work great as long as I do not import the midi module into more than one of my other python modules.

e.g. when I try to get both my actors and my cameras to react to midi I get a ‘bad Pointer’ error

midin=pgm.Input(2)

this little guy is the culprit, if it is called more than once in two different modules it produces an error-- This is actually calling my midi control device and without it I can’t request a midi value from within a module using “.read”

how do I get around this without having to put all my code into one huge .py file?

thanks for any help!

dp

Without your complete source it’s hard to see what you are actually doing. Your question is that of a python behavior problem.

Your code is modular but it doesn’t seem to be in classes. You might want to consider putting them in classes as this will solve your problem.

For example:
If you have file: ClassA.py as

class A:
  def __init__(self):
    print "initializing A"

print "At the bottom"

if you run the code

from ClassA import A

You will get no output until you make an instance of A. However if you run

from ClassA import *

You will get the print out “At the bottom”

If you put everything inside a class and make sure in your main file that you only have one instance of that class, then you should be good to go no matter how many times you import that class.

Thanks!

Yeah I have midi working with Panda now using a midi handler class partly modeled after the joystick handlers posted in the forum–using pygame.

I will post it when I get home from work. however I have to combine it with other defs in my main script to have it work properly–

I am new to all of this so there is probably a more efficient way…but if it works it works…

dp

so here is the MidiHandler Class I came up with-- it is pretty rudimentary

##feel free to use or modify-- Daniel Potthast ##www.danielraphael.info
import pygame
import pygame.midi

pgm=pygame.midi
pgm.init()
midin=pgm.Input(1) #this value will vary with your hardware mine is 1

class MidiHandler():
    
    def __init__(self):
        global midin       
        self.midin=midin
    def mRead(self):
        self.mOut=self.midin.read(1)
        if self.mOut:
            return self.mOut
        else:return None
    def mRtrn(self,mRaw,sldr,chan=176):
        if mRaw:
            mChan = mRaw[0][0][0]
            mSld = mRaw[0][0][1]
            mVal = mRaw[0][0][2]
            
            if mChan==chan and mSld==sldr: 
                return mVal
        else:return None
        
    def mKill(self):
        midin.close()
    def mRange(self,mInput, min=-1, max=1): #restricts output range
        mRatio = (max-min)/127.0
        mOut = ((mInput-1)*mRatio)+min
        return mOut
    def mTime(self):
        return self.pgm.time()

here is the implementation in the main module:

from MidiHandler import *

x=MidiHandler()

#this line in the main __init__
base.accept('1',self.midiEnable)


    def midiEnable(self):
        
        def setOut():  #establish variables and initial values
            self.mOut1=1
            self.mOut2=1
            self.mOut3=1
            self.mOut4=0
            self.mOut5=0
            self.mOut6=0
            self.mOut7=1
            self.mOut8=1
            self.mOut9=1
            self.mOut10=1
#and so on for all knobs and sliders

        setOut()
        def mTask(task):
            self.mIn=x.mRead()
            self.step=task.time
            def setCtrl(): #returns to each variable if value is not None
                self.mCtrl1=x.mRtrn(self.mIn,1)
                self.mCtrl2=x.mRtrn(self.mIn,2)
                self.mCtrl3=x.mRtrn(self.mIn,3)
                self.mCtrl4=x.mRtrn(self.mIn,4)
                self.mCtrl5=x.mRtrn(self.mIn,5)
                self.mCtrl6=x.mRtrn(self.mIn,6)
                self.mCtrl7=x.mRtrn(self.mIn,7)
                self.mCtrl8=x.mRtrn(self.mIn,8)
                self.mCtrl9=x.mRtrn(self.mIn,9)
                self.mCtrl10=x.mRtrn(self.mIn,10)

#and so on for all your knobs and sliders

            setCtrl()
            def setRead():
                if self.mCtrl1:
                    self.mRg=x.mRange(self.mCtrl1,-90,90)
                    self.mOut1=self.mRg
                elif self.mCtrl2:
                    self.mRg=x.mRange(self.mCtrl2,-90,90)
                    self.mOut2=self.mRg
                elif self.mCtrl3:
                    self.mRg=x.mRange(self.mCtrl3,-90,90)
                    self.mOut3=self.mRg
                elif self.mCtrl4:
                    self.mRg=x.mRange(self.mCtrl4,-10,10)
                    self.mOut4=self.mRg
                elif self.mCtrl5:
                    self.mRg=x.mRange(self.mCtrl5,-10,10)
                    self.mOut5=self.mRg
                elif self.mCtrl6:
                    self.mRg=x.mRange(self.mCtrl6,-10,10)
                    self.mOut6=self.mRg
                elif self.mCtrl7:
                    self.mRg=x.mRange(self.mCtrl7,-180,180)
                    self.mOut7=self.mRg
                elif self.mCtrl8:
                    self.mRg=x.mRange(self.mCtrl8,-180,180)
                    self.mOut8=self.mRg    
                elif self.mCtrl9:
                    self.mRg=x.mRange(self.mCtrl9,-180,180)
                    self.mOut9=self.mRg 
                elif self.mCtrl10:
                    self.mRg=x.mRange(self.mCtrl10,-30.0,30.0)
                    self.mOut10=self.mRg

#and so on for your knobs, sliders, etc...


  #place commands for midi to influence here:
  #see example below


                return task.cont

base.taskMgr.add(mTask, "mTask")

I realize this is probably far more verbose than it needs to be (and it is even abridged)
however it does work… I think a ‘for loop’ may be able to do the initializing of the variables more efficiently… but I would not be able to assign individual default values that way.

the “x.mRange” calls a simple function to make the 1-128 midi return values stick to whatever range of values I require
so:

elif self.mCtrl28:
                    self.mRg=x.mRange(self.mCtrl28,-31.4,31.4)
                    self.mOut28=self.mRg 

This makes the 28th midi slider output values from -31.4 to 31.4 rather than 1-128

after the midi is read I can then assign the output to whatever I need to e.g.

self.actor2Pivot.setHpr(self.mOut1,self.mOut2,self.mOut3)
#allows x,y,z rotation to be handled by sliders 1,2,3

these are placed at the bottom of the same task.

I have not used the x.mKill function but include it in the module if needed…

I should experiment more, but I am not sure if this could be done with two or more tasks however, the midi seems to get along much better if it is all handled with one task…

**what I have noticed with this implementation is that the midi read values buffer up and the midi clock is running 10-20 clicks per task frame so if you go crazy with your sliders it will take a little time for the individual reads to catch up to all the values stacked up in the buffer.

Please Please Please if any of you have a better way of doing this I am all ears, however it was gratifying and educational to actually get this far-- I hope this comes in handy to someone out there.

dp

this should be placed to initialize that last def

def setRead():
.
.
.
.

setRead()