Skip to content

Commit 9a4cfdc

Browse files
authored
Add files via upload
0 parents  commit 9a4cfdc

File tree

4 files changed

+374
-0
lines changed

4 files changed

+374
-0
lines changed

AudioToolbox.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from ctypes import *
2+
import ctypes.util
3+
4+
from CoreFoundation import *
5+
6+
_at = CDLL(ctypes.util.find_library("AudioToolbox"))
7+
8+
OpaqueAUGraph = c_void_p
9+
AUGraph = POINTER(OpaqueAUGraph) # typedef struct OpaqueAUGraph *AUGraph;
10+
AUNode = c_int32 # typedef SInt32 AUNode;
11+
AudioComponentInstance = c_void_p # typedef struct ComponentInstanceRecord *AudioComponentInstance;
12+
AudioUnit = AudioComponentInstance # typedef AudioComponentInstance AudioUnit;
13+
MusicDeviceComponent = AudioComponentInstance # typedef AudioComponentInstance MusicDeviceComponent;
14+
AudioUnitParameterID = c_uint32 # typedef UInt32 AudioUnitParameterID;
15+
AudioUnitScope = c_uint32 # typedef UInt32 AudioUnitScope;
16+
AudioUnitElement = c_uint32 # typedef UInt32 AudioUnitElement;
17+
AudioUnitParameterValue = c_float # typedef Float32 AudioUnitParameterValue;
18+
19+
kMusicDeviceParam_Volume = AudioUnitParameterID(1)
20+
kAudioUnitScope_Global = AudioUnitScope(0)
21+
22+
def FOUR_CHAR_CODE(code):
23+
value = 0
24+
for i in range(4):
25+
value += ord(code[i]) << (3 - i) * 8
26+
return value
27+
28+
kAudioUnitManufacturer_Apple = FOUR_CHAR_CODE('appl')
29+
kAudioUnitType_MusicDevice = FOUR_CHAR_CODE('aumu')
30+
kAudioUnitSubType_DLSSynth = FOUR_CHAR_CODE('dls ')
31+
kAudioUnitType_Effect = FOUR_CHAR_CODE('aufx')
32+
kAudioUnitSubType_PeakLimiter = FOUR_CHAR_CODE('lmtr')
33+
kAudioUnitType_Output = FOUR_CHAR_CODE('auou')
34+
kAudioUnitSubType_DefaultOutput = FOUR_CHAR_CODE('def ')
35+
36+
class AudioComponentDescription(Structure):
37+
_fields_ = [("componentType", OSType), # OSType componentType;
38+
("componentSubType", OSType), # OSType componentSubType;
39+
("componentManufacturer", OSType), # OSType componentManufacturer;
40+
("componentFlags", c_uint32), # UInt32 componentFlags;
41+
("componentFlagsMask", c_uint32)] # UInt32 componentFlagsMask;
42+
43+
# OSStatus NewAUGraph(AUGraph _Nullable *outGraph);
44+
_at.NewAUGraph.argtypes = [POINTER(AUGraph)]
45+
_at.NewAUGraph.restype = OSStatus
46+
NewAUGraph = _at.NewAUGraph
47+
48+
# OSStatus AUGraphAddNode(AUGraph inGraph, const AudioComponentDescription *inDescription, AUNode *outNode);
49+
_at.AUGraphAddNode.argtypes = [AUGraph, POINTER(AudioComponentDescription), POINTER(AUNode)]
50+
_at.AUGraphAddNode.restype = OSStatus
51+
AUGraphAddNode = _at.AUGraphAddNode
52+
53+
# OSStatus AUGraphOpen(AUGraph inGraph);
54+
_at.AUGraphOpen.argtypes = [AUGraph]
55+
_at.AUGraphOpen.restype = OSStatus
56+
AUGraphOpen = _at.AUGraphOpen
57+
58+
# OSStatus AUGraphConnectNodeInput(AUGraph inGraph, AUNode inSourceNode, UInt32 inSourceOutputNumber, AUNode inDestNode, UInt32 inDestInputNumber);
59+
_at.AUGraphConnectNodeInput.argtypes = [AUGraph, AUNode, c_uint32, AUNode, c_uint32]
60+
_at.AUGraphConnectNodeInput.restype = OSStatus
61+
AUGraphConnectNodeInput = _at.AUGraphConnectNodeInput
62+
63+
# OSStatus AUGraphNodeInfo(AUGraph inGraph, AUNode inNode, AudioComponentDescription *outDescription, AudioUnit _Nullable *outAudioUnit);
64+
_at.AUGraphNodeInfo.argtypes = [AUGraph, AUNode, POINTER(AudioComponentDescription), POINTER(AudioUnit)]
65+
_at.AUGraphNodeInfo.restype = OSStatus
66+
AUGraphNodeInfo = _at.AUGraphNodeInfo
67+
68+
# OSStatus AUGraphInitialize(AUGraph inGraph);
69+
_at.AUGraphInitialize.argtypes = [AUGraph]
70+
_at.AUGraphInitialize.restype = OSStatus
71+
AUGraphInitialize = _at.AUGraphInitialize
72+
73+
# OSStatus AUGraphStart(AUGraph inGraph);
74+
_at.AUGraphStart.argtypes = [AUGraph]
75+
_at.AUGraphStart.restype = OSStatus
76+
AUGraphStart = _at.AUGraphStart
77+
78+
# OSStatus AudioUnitGetParameter(AudioUnit inUnit, AudioUnitParameterID inID, AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterValue *outValue);
79+
_at.AudioUnitGetParameter.argtypes = [AudioUnit, AudioUnitParameterID, AudioUnitScope, AudioUnitElement, POINTER(AudioUnitParameterValue)]
80+
_at.AudioUnitGetParameter.restype = OSStatus
81+
AudioUnitGetParameter = _at.AudioUnitGetParameter
82+
83+
# OSStatus AudioUnitSetParameter(AudioUnit inUnit, AudioUnitParameterID inID, AudioUnitScope inScope, AudioUnitElement inElement, AudioUnitParameterValue inValue, UInt32 inBufferOffsetInFrames);
84+
_at.AudioUnitSetParameter.argtypes = [AudioUnit, AudioUnitParameterID, AudioUnitScope, AudioUnitElement, AudioUnitParameterValue, c_uint32]
85+
_at.AudioUnitSetParameter.restype = OSStatus
86+
AudioUnitSetParameter = _at.AudioUnitSetParameter
87+
88+
# OSStatus MusicDeviceMIDIEvent(MusicDeviceComponent inUnit, UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame);
89+
_at.MusicDeviceMIDIEvent.argtypes = [MusicDeviceComponent, c_uint32, c_uint32, c_uint32, c_uint32]
90+
_at.MusicDeviceMIDIEvent.restype = OSStatus
91+
MusicDeviceMIDIEvent = _at.MusicDeviceMIDIEvent
92+
93+
# void CAShow(void *inObject);
94+
_at.CAShow.argtypes = [c_void_p]
95+
CAShow = _at.CAShow

CoreFoundation.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from ctypes import *
2+
import ctypes.util
3+
4+
_cf = CDLL(ctypes.util.find_library("CoreFoundation"))
5+
6+
FourCharCode = c_uint # typedef unsigned int FourCharCode;
7+
OSType = FourCharCode # typedef FourCharCode OSType;
8+
OSStatus = c_int32 # typedef SInt32 OSStatus;
9+
10+
CFIndex = c_long # typedef long CFIndex;
11+
CFStringEncoding = c_uint32 # typedef UInt32 CFStringEncoding;
12+
CFString = c_void_p
13+
CFArray = c_void_p
14+
CFDictionary = c_void_p
15+
CFError = c_void_p
16+
CFType = c_void_p
17+
18+
CFAllocatorRef = c_void_p
19+
CFStringRef = POINTER(CFString)
20+
CFArrayRef = POINTER(CFArray)
21+
CFDictionaryRef = POINTER(CFDictionary)
22+
CFErrorRef = POINTER(CFError)
23+
CFTypeRef = POINTER(CFType)
24+
25+
kCFStringEncodingUTF8 = CFStringEncoding(0x08000100)
26+
27+
# CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
28+
_cf.CFStringCreateWithCString.argstype = [CFAllocatorRef, c_char_p, CFStringEncoding]
29+
_cf.CFStringCreateWithCString.restype = CFStringRef
30+
CFStringCreateWithCString = _cf.CFStringCreateWithCString
31+
32+
# Boolean CFStringGetCString(CFStringRef theString, char *buffer, CFIndex bufferSize, CFStringEncoding encoding);
33+
_cf.CFStringGetCString.argtypes = [CFStringRef, c_char_p, CFIndex, CFStringEncoding]
34+
_cf.CFStringGetCString.restype = c_bool
35+
CFStringGetCString = _cf.CFStringGetCString
36+
37+
# const char * CFStringGetCStringPtr(CFStringRef theString, CFStringEncoding encoding);
38+
_cf.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding]
39+
_cf.CFStringGetCStringPtr.restype = c_char_p
40+
CFStringGetCStringPtr = _cf.CFStringGetCStringPtr
41+
42+
# CFIndex CFStringGetLength(CFStringRef theString);
43+
_cf.CFStringGetLength.argtypes = [CFStringRef]
44+
_cf.CFStringGetLength.restype = CFIndex
45+
CFStringGetLength = _cf.CFStringGetLength

CoreMIDI.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
from ctypes import *
2+
import ctypes.util
3+
4+
from CoreFoundation import *
5+
6+
_cm = CDLL(ctypes.util.find_library("CoreMIDI"))
7+
8+
kMIDIPropertyDisplayName = c_char_p(b"displayName")
9+
10+
ItemCount = c_ulong
11+
ByteCount = c_ulong
12+
Byte = c_ubyte
13+
MIDIObjectRef = c_uint32 # typedef UInt32 MIDIObjectRef;
14+
MIDIEndpointRef = MIDIObjectRef # typedef MIDIObjectRef MIDIEndpointRef;
15+
MIDIClientRef = MIDIObjectRef # typedef MIDIObjectRef MIDIClientRef;
16+
MIDINotifyProc = c_void_p # typedef void (*MIDINotifyProc)(const MIDINotification *message, void *refCon);
17+
MIDIReadProc = c_void_p # typedef void (*MIDIReadProc)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);
18+
MIDIPortRef = MIDIObjectRef # typedef MIDIObjectRef MIDIPortRef;
19+
MIDITimeStamp = c_uint64 # typedef UInt64 MIDITimeStamp;
20+
21+
class MIDIPacket(Structure):
22+
_pack_ = 1
23+
_fields_ = [("timeStamp", MIDITimeStamp), # MIDITimeStamp timeStamp;
24+
("length", c_uint16), # UInt16 length;
25+
("data", Byte*256)] # Byte data[256];
26+
27+
class MIDIPacketList(Structure):
28+
_fields_ = [("numPackets", c_uint32), # UInt32 numPackets;
29+
("packet", MIDIPacket*1)] # MIDIPacket packet[1];
30+
31+
# MIDIEndpointRef MIDIGetSource(ItemCount sourceIndex0);
32+
_cm.MIDIGetSource.argtypes = [ItemCount]
33+
_cm.MIDIGetSource.restype = MIDIEndpointRef
34+
MIDIGetSource = _cm.MIDIGetSource
35+
36+
# MIDIEndpointRef MIDIGetDestination(ItemCount destIndex0);
37+
_cm.MIDIGetDestination.argtypes = [ItemCount]
38+
_cm.MIDIGetDestination.restype = MIDIEndpointRef
39+
MIDIGetDestination = _cm.MIDIGetDestination
40+
41+
# ItemCount MIDIGetNumberOfSources(void);
42+
_cm.MIDIGetNumberOfSources.restype = ItemCount
43+
MIDIGetNumberOfSources = _cm.MIDIGetNumberOfSources
44+
45+
# ItemCount MIDIGetNumberOfDestinations(void);
46+
_cm.MIDIGetNumberOfDestinations.restype = ItemCount
47+
MIDIGetNumberOfDestinations = _cm.MIDIGetNumberOfDestinations
48+
49+
# OSStatus MIDIObjectGetStringProperty(MIDIObjectRef obj, CFStringRef propertyID, CFStringRef _Nullable *str);
50+
_cm.MIDIObjectGetStringProperty.argtypes = [MIDIObjectRef, CFStringRef, POINTER(CFStringRef)]
51+
_cm.MIDIObjectGetStringProperty.restype = OSStatus
52+
MIDIObjectGetStringProperty = _cm.MIDIObjectGetStringProperty
53+
54+
# OSStatus MIDIClientCreate(CFStringRef name, MIDINotifyProc notifyProc, void *notifyRefCon, MIDIClientRef *outClient);
55+
_cm.MIDIClientCreate.argtypes = [CFStringRef, MIDINotifyProc, c_void_p, POINTER(MIDIClientRef)]
56+
_cm.MIDIClientCreate.restype = OSStatus
57+
MIDIClientCreate = _cm.MIDIClientCreate
58+
59+
# OSStatus MIDIInputPortCreate(MIDIClientRef client, CFStringRef portName, MIDIReadProc readProc, void *refCon, MIDIPortRef *outPort);
60+
_cm.MIDIInputPortCreate.argtypes = [MIDIClientRef, CFStringRef, MIDIReadProc, c_void_p, POINTER(MIDIPortRef)]
61+
_cm.MIDIInputPortCreate.restype = OSStatus
62+
MIDIInputPortCreate = _cm.MIDIInputPortCreate
63+
64+
# OSStatus MIDIOutputPortCreate(MIDIClientRef client, CFStringRef portName, MIDIPortRef *outPort);
65+
_cm.MIDIOutputPortCreate.argtypes = [MIDIClientRef, CFStringRef, POINTER(MIDIPortRef)]
66+
_cm.MIDIOutputPortCreate.restype = OSStatus
67+
MIDIOutputPortCreate = _cm.MIDIOutputPortCreate
68+
69+
# OSStatus MIDIPortConnectSource(MIDIPortRef port, MIDIEndpointRef source, void *connRefCon);
70+
_cm.MIDIPortConnectSource.argtypes = [MIDIPortRef, MIDIEndpointRef, c_void_p]
71+
_cm.MIDIPortConnectSource.restype = OSStatus
72+
MIDIPortConnectSource = _cm.MIDIPortConnectSource
73+
74+
# OSStatus MIDIPortDisconnectSource(MIDIPortRef port, MIDIEndpointRef source);
75+
_cm.MIDIPortDisconnectSource.argtypes = [MIDIPortRef, MIDIEndpointRef]
76+
_cm.MIDIPortDisconnectSource.restype = OSStatus
77+
MIDIPortDisconnectSource = _cm.MIDIPortDisconnectSource
78+
79+
# MIDIPacket * MIDIPacketListInit(MIDIPacketList *pktlist);
80+
_cm.MIDIPacketListInit.argtypes = [POINTER(MIDIPacketList)]
81+
_cm.MIDIPacketListInit.restype = POINTER(MIDIPacket)
82+
MIDIPacketListInit = _cm.MIDIPacketListInit
83+
84+
# MIDIPacket * MIDIPacketListAdd(MIDIPacketList *pktlist, ByteCount listSize, MIDIPacket *curPacket, MIDITimeStamp time, ByteCount nData, const Byte *data);
85+
_cm.MIDIPacketListAdd.argtypes = [POINTER(MIDIPacketList), ByteCount, POINTER(MIDIPacket), MIDITimeStamp, ByteCount, POINTER(Byte)]
86+
_cm.MIDIPacketListAdd.restype = POINTER(MIDIPacket)
87+
MIDIPacketListAdd = _cm.MIDIPacketListAdd
88+
89+
# OSStatus MIDISend(MIDIPortRef port, MIDIEndpointRef dest, const MIDIPacketList *pktlist);
90+
_cm.MIDISend.argtypes = [MIDIPortRef, MIDIEndpointRef, POINTER(MIDIPacketList)]
91+
_cm.MIDISend.restype = OSStatus
92+
MIDISend = _cm.MIDISend

README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Python Core MIDI
2+
3+
Core MIDI Framework C API wrapper for Python built on [ctypes](https://docs.python.org/3/library/ctypes.html).
4+
5+
## Setup
6+
7+
Simply copy the source files to your directory and import it.
8+
9+
## Usage Example
10+
11+
```python
12+
from AudioToolbox import *
13+
from CoreMIDI import *
14+
15+
16+
# ========== DLS AU GRAPH ==========
17+
18+
graph = AUGraph()
19+
NewAUGraph(byref(graph))
20+
21+
cd = AudioComponentDescription()
22+
cd.componentManufacturer = kAudioUnitManufacturer_Apple
23+
cd.componentType = kAudioUnitType_MusicDevice
24+
cd.componentSubType = kAudioUnitSubType_DLSSynth
25+
cd.componentFlags = 0
26+
cd.componentFlagsMask = 0
27+
synthNode = AUNode()
28+
AUGraphAddNode(graph, byref(cd), byref(synthNode))
29+
30+
cd.componentType = kAudioUnitType_Effect
31+
cd.componentSubType = kAudioUnitSubType_PeakLimiter
32+
limiterNode = AUNode()
33+
AUGraphAddNode(graph, byref(cd), byref(limiterNode))
34+
35+
cd.componentType = kAudioUnitType_Output
36+
cd.componentSubType = kAudioUnitSubType_DefaultOutput
37+
outNode = AUNode()
38+
AUGraphAddNode(graph, byref(cd), byref(outNode))
39+
40+
AUGraphOpen(graph)
41+
AUGraphConnectNodeInput(graph, synthNode, 0, limiterNode, 0)
42+
AUGraphConnectNodeInput(graph, limiterNode, 0, outNode, 0)
43+
44+
outSynth = AudioUnit()
45+
description = AudioComponentDescription()
46+
AUGraphNodeInfo(graph, synthNode, byref(description), byref(outSynth))
47+
48+
AUGraphInitialize(graph)
49+
AUGraphStart(graph)
50+
CAShow(graph)
51+
52+
volume = AudioUnitParameterValue(10)
53+
AudioUnitSetParameter(outSynth, kMusicDeviceParam_Volume, kAudioUnitScope_Global, 0, volume, 0)
54+
55+
56+
# ========== CORE MIDI ==========
57+
58+
delegate = None
59+
60+
# typedef void (*MIDIReadProc)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);
61+
def readProc(pktlist, readProcRefCon, srcConnRefCon):
62+
packet = pktlist.contents.packet[0]
63+
status = packet.data[0]
64+
data1 = packet.data[1]
65+
data2 = packet.data[2]
66+
if delegate: delegate(status, data1, data2)
67+
68+
callback = CFUNCTYPE(None, POINTER(MIDIPacketList), c_void_p, c_void_p)(readProc)
69+
70+
client = MIDIClientRef()
71+
client_name = CFStringCreateWithCString(None, __file__, kCFStringEncodingUTF8)
72+
MIDIClientCreate(client_name, None, None, byref(client))
73+
74+
input_port = MIDIPortRef()
75+
input_name = CFStringCreateWithCString(None, "I_PORT", kCFStringEncodingUTF8)
76+
MIDIInputPortCreate(client, input_name, callback, None, byref(input_port))
77+
78+
output_port = MIDIPortRef()
79+
output_name = CFStringCreateWithCString(None, "O_PORT", kCFStringEncodingUTF8)
80+
MIDIOutputPortCreate(client, output_name, byref(output_port))
81+
82+
def getSources():
83+
names = []
84+
for i in range(MIDIGetNumberOfSources()):
85+
src = MIDIGetSource(i)
86+
names.append(getMIDIDisplayName(src))
87+
return names
88+
89+
def getDestinations():
90+
names = []
91+
for i in range(MIDIGetNumberOfDestinations()):
92+
des = MIDIGetDestination(i)
93+
names.append(getMIDIDisplayName(des))
94+
return names
95+
96+
def getMIDIDisplayName(endpoint):
97+
cf_string = CFStringCreateWithCString(None, c_char_p(b""), kCFStringEncodingUTF8)
98+
cf_name_key = CFStringCreateWithCString(None, kMIDIPropertyDisplayName, kCFStringEncodingUTF8)
99+
MIDIObjectGetStringProperty(endpoint, cf_name_key, byref(cf_string))
100+
c_string_buffer = ctypes.create_string_buffer(64)
101+
CFStringGetCString(cf_string, c_string_buffer, 64, kCFStringEncodingUTF8)
102+
py_string = c_string_buffer.value.decode("utf-8")
103+
if py_string != "" : return py_string
104+
else: return "< Unknown Endpoint >"
105+
106+
current_src = None
107+
current_dest = None
108+
109+
def setInput(index):
110+
global current_src
111+
if current_src:
112+
MIDIPortDisconnectSource(input_port, current_src, None)
113+
if index > 0:
114+
current_src = MIDIGetSource(index-1)
115+
MIDIPortConnectSource(input_port, current_src, None)
116+
117+
def setOutput(index):
118+
global current_dest
119+
if current_dest:
120+
current_dest = None
121+
if index > 0:
122+
current_dest = MIDIGetDestination(index-1)
123+
124+
def sendEvent(status, data1, data2):
125+
if current_dest:
126+
packet = MIDIPacket(
127+
timeStamp=0,
128+
length=3,
129+
data=(Byte*256)(status, data1, data2)
130+
)
131+
pktlist = MIDIPacketList(
132+
numPackets=1,
133+
packet=(MIDIPacket*1)(packet)
134+
)
135+
MIDISend(output_port, current_dest, pktlist)
136+
else:
137+
MusicDeviceMIDIEvent(outSynth, status, data1, data2, 0)
138+
139+
def softsynth_program_change(number):
140+
MusicDeviceMIDIEvent(outSynth, 0xC0, number, 0, 0)
141+
142+
```

0 commit comments

Comments
 (0)