Question

I'd like to learn if a simple CoreAudio component (of subtype kAudioUnitSubType_HALOutput, e.g.), can be parametrically controlled by a MIDI keyboard, let's say MIDI note number be translated into interpollating oscillator frequency? On the other hand, controlling such a parameter by means of a GUI element works like a dream.

I found no single example of such a code on the entire web. I don't need SinSynth, Sampler, MusicDevice, SoundFonts, Midi files, GM, ADSRs, plug-in level of functionality, etc.

Just need a plain piece of information or hint on how can data from a MIDI packet read by means of a midiReadProc get passed to a audio render callback, much like values of a slider can. With MIDI there seems to be a threading issue, I found no documentation about.

I'd prefer to do it in CoreAudio API, if possible, I'm sure it must be.

On the other hand, using Apple pre-built music instrument devices would lead me into a completely wrong direction.

Thanks in advance,

CA

Was it helpful?

Solution

It seems you want to controls some of parameters or properties of AudioUnit using MIDI-keyboard. In this case all that you need is take MIDIPacket's data field. What every byte mean you can look here. After that, depending on value of needed byte, you need to set property or parameter value.

OTHER TIPS

Here's a minimalistic answer to the question that I've learned and made work meanwhile. It's a matter of making a midiReadProc generate values which an audioRenderProc can accept as parameters. Please note that this works in stand-alone apps. For writing AU-plug-ins I recommend understanding and using CoreAudioUtilityClasses, as provided by Apple. A simplest example of createMidi in C:

//these have to be declared somewhere
MIDIClientRef midiclient;
MIDIPortRef   midiin;

void createMIDI (void)
{
//create MIDI input and client - - - - - - - - - - - 
midiclient = 0;

CheckError(MIDIClientCreate(CFSTR("MIDI_Client"), 
                            NULL, 
                            /*midiClientNotifyRefCon*/NULL, 
                            &midiclient), 
            "MIDI Client Create Error\n");

CheckError(MIDIInputPortCreate(midiclient, 
                                CFSTR("MIDI_Input"), 
                                midiReadProc, 
                                NULL, 
                                &midiin),
            "MIDI Port Create Error\n");

//connect MIDI - - - - - - - - - - - - - - - - - - -         
ItemCount mSrcs = MIDIGetNumberOfSources();
printf("MIDI Sources: %ld\n", (long)mSrcs);
ItemCount iSrc;

for (iSrc=0; iSrc<mSrcs; iSrc++) {
    MIDIEndpointRef src = MIDIGetSource(iSrc);
    MIDIPortConnectSource(midiin, src, NULL);
    } 
}

CheckError( ) is a generic utility function modeled after "Learning Core Audio", by C.Adamson & K.Avila, ISBN 0-321-63684-8...

...and a plain-C midiReadProc template. Please note that many manufacturers of MIDI hardware don't implement the standardized noteOff event, but rather a "hacked" version consisting of a zero-velocity-noteOn, due to alleged improving MIDI-latency issues, but they hardly document it. So, one has to check against both scenarios:

void midiReadProc(const MIDIPacketList *packetList, 
              void* readProcRefCon, 
              void* srcConnRefCon)
{
Byte note;
Byte velocity;
MIDIPacket *packet = (MIDIPacket*)packetList->packet;
int count = packetList->numPackets;

for (int k=0; k < count; k++) {
    Byte midiStatus  = packet->data[0];
    Byte midiChannel = midiStatus & 0x0F;
    Byte midiCommand = midiStatus >> 4;

    if ((midiCommand == 0x08)||(midiCommand == 0x09)){        
        if(midiCommand == 0x09){            
            note     = packet->data[1] & 0x7F; 
            velocity = packet->data[2] & 0x7F;

            if (velocity == 0x0){ //"hacked" note-off                
                 ; //do something                                     
            }else{//note on                                                  
                ; //do something                     
            }
        }            
        if(midiCommand == 0x08){ //proper note-off                                   
        ;//do something               
        }
    }else{
    ;//do something else
    }
packet = MIDIPacketNext(packet);    
}//end for (k = 0; ...;...)
}

Everything else is a matter of common good programing practice.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top