MT32MusicComponent.cMT32MusicComponent.c
/*
File: MT32MusicComponent.c
Contains: xxx put contents here xxx
Written by: xxx put writers here xxx
Copyright: © 1994-1996 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<14> 4/8/96 dvb New Interfaces
<13> 9/13/95 JB music dumpfile for new build
<12> 8/21/95 dvb new musiccomponent.h stuff
<10> 6/12/95 dvb
<9+> fine tune the gaps yet again... NAMIDI had it all wrong.
<9> 28-4-95 dvb CanDo implemented wrong for subclassed component
<8> 14-3-95 dvb gap directive.
<7+> delay packet type, set reserved to zero
<7> 6-2-95 dvb patch params
<6+> patch and timbre params as part of instrument
<6> 5-1-95 dvb
<5> 14-11-94 dvb upp fixes
<4> 24-10-94 dvb minor
<3+> make it cleaner for copying and reusing
<3> 11-10-94 dvb
<2> 10/3/94 JB Dispos... ==> Dispose...
*/
/*
File: MT32MusicComponent.c
Written by: dvb
Copyright: © 1993-1994 by Apple Computer, Inc., all rights reserved.
*/
/*-----------------------------------
Inclusions
-----------------------------------*/
#ifdef MUSICDUMP
#ifdef DUMP_USEINCLUDE
#include MUSICDUMP
#else
#pragma load MUSICDUMP
#endif
#else
#include "QTEnv.h"
#include "MusicComponent.h"
#endif
/*-----------------------------------
pascal ComponentResult Types
-----------------------------------*/
#define kBaseResID 300
#define kSysexTimeGap 15 /* milliseconds midi bus gap after param change */
typedef struct
{
MusicComponent super; /* the component that does everything we cannot */
MusicComponent self;
MusicMIDISendProcPtr midiProc;
long midiProcRefCon;
} GGlobals;
#define MUSIC_BASENAME() MT32
#define MUSIC_GLOBALS() GGlobals *g
#include "MusicComponent.k.h"
/*-----------------------------------
pascal ComponentResult Prototypes
-----------------------------------*/
static ComponentFunctionUPP FindRoutine(short selektor);
pascal ComponentResult MT32Open (GGlobals *g, ComponentInstance self);
pascal ComponentResult MT32Close (GGlobals *g, ComponentInstance self);
pascal ComponentResult MT32CanDo (GGlobals *g, short selektor);
pascal ComponentResult MT32Version (GGlobals *g);
static ComponentResult MT32WriteMIDI(GGlobals *g,int firstByte,...);
static ComponentResult SetMT32Parameter(GGlobals *g,long p,short v);
/*-----------------------------------
The Stuff
-----------------------------------*/
#define mt32ParamChannels 0x4000D
#define mt32ParamTimbre 0x10000
#define mt32ParamPatch 0x0C000
pascal ComponentResult MT32MusicComponent( ComponentParameters *params, Handle storage )
{
ComponentFunctionUPP gcProc;
ComponentResult result;
MusicComponent self;
gcProc = 0;
result = 0;
self = (MusicComponent)params->params[0];
gcProc = FindRoutine(params->what);
if (gcProc)
result = CallComponentFunctionWithStorage(storage, params, gcProc);
else
result = DelegateComponentCall(params, ((GGlobals *)storage)->super);
return result;
}
#define CCaseSelect(callName) \
case kComponent##callName##Select: \
componentProc = (ComponentFunctionUPP) MUSIC_BASENAME()callName; \
break
#define CaseSelect(callName) \
case kMusic##callName##Select: \
componentProc = (ComponentFunctionUPP) MUSIC_BASENAME()callName; \
break
#define DCaseSelect(callName) \
case kMusicDerived##callName##Select: \
componentProc = (ComponentFunctionUPP) MUSIC_BASENAME()Derived##callName; \
break
static ComponentFunctionUPP FindRoutine(short selektor)
{
ComponentFunctionUPP componentProc;
switch (selektor)
{
CCaseSelect(Open);
CCaseSelect(Close);
CCaseSelect(CanDo);
CCaseSelect(Version);
CaseSelect(SetMIDIProc);
DCaseSelect(SetKnob);
DCaseSelect(SetPart);
DCaseSelect(SetInstrument);
default:
componentProc = 0;
break;
}
return componentProc;
}
pascal ComponentResult MT32CanDo (GGlobals *g, short selektor)
{
ComponentResult result;
result = FindRoutine(selektor) != 0;
if(!result)
result = ComponentFunctionImplemented(g->super,selektor);
return result;
}
pascal ComponentResult MT32Version (GGlobals *g)
{
return 0x00010001;
}
pascal ComponentResult MT32Open (GGlobals *g, ComponentInstance self)
{
ComponentResult result;
g = (GGlobals *)NewPtrClear(sizeof(GGlobals));
if (result = MemError())
goto goHome;
g->self = self;
SetComponentInstanceStorage(self, (Handle)g);
g->super = OpenDefaultComponent(kMusicComponentType,kGenericMusicComponentSubtype);
if(!g->super)
{
result = -1; /* cant open synth err */
fail:
SetComponentInstanceStorage(self, nil);
DisposePtr((Ptr)g);
goto goHome;
}
result = ComponentSetTarget(g->super,g->self);
if(result)
goto fail;
result = MusicGenericConfigure(g->super,0,
kGenericMusicDoMIDI
+ kGenericMusicCallKnobs
+ kGenericMusicCallParts
+ kGenericMusicCallInstrument,
kBaseResID); /* tell it our resource ID */
if(result)
goto fail;
goHome:
return result;
}
pascal ComponentResult MT32Close (GGlobals *g, ComponentInstance self)
{
ComponentResult result;
SetMT32Parameter(g,0x1FFFFF,0); /* reset all parameters */
result = CloseComponent(g->super);
DisposePtr((Ptr)g);
SetComponentInstanceStorage(self,0);
return result;
}
/* -------------------------------- -------------------------------- */
pascal ComponentResult MT32SetMIDIProc(GGlobals *g,
MusicMIDISendProcPtr midiProc, long refCon)
{
ComponentResult result;
short i;
g->midiProc = midiProc;
g->midiProcRefCon = refCon;
result = MusicSetMIDIProc(g->super,midiProc,refCon);
/*
* Turn off the 6 PCM voices above, if
* it happens to be a CM500.
* This assumes we chose mode B for our unit.
*/
MT32WriteMIDI(g,0xF0,0x41,0x10,0x16,0x12,
0x52,0x00,0x0A,
0x10,0x10,0x10,
0x10,0x10,0x10,
0 ,0xF7,-3);
/*
* Turn off all 9 parts of the CM32
*/
MT32WriteMIDI(g,0xF0,0x41,0x10,0x16,0x12,
0x10,0x00,0x0D,
0x10,0x10,0x10,
0x10,0x10,0x10,
0x10,0x10,0x10,
0 ,0xF7,-3);
return result;
}
static ComponentResult MT32WriteMIDI(GGlobals *g,int firstByte,...)
{
MusicMIDIPacket somePacket;
register unsigned char *w;
register int *source;
register short x;
OSErr result;
if(!g->midiProc)
{
result = cantSendToSynthesizerErr;
goto goHome;
}
w = somePacket.data;
source = &firstByte;
do
{
x = *source++;
if(x >= 0)
*w++ = x;
} while (x >= 0);
if(x == -2 || x == -3) /* we're asked to compute checksum */
{
unsigned char *w1,*w2;
short sum;
w1 = somePacket.data + 5;
w2 = w - 2;
sum = 0;
while(w1 < w2)
sum -= *w1++;
*w2 = sum & 0x7F;
}
if(x == -3) // -3 is checksum and time gap before & after
{
MusicMIDIPacket gapPacket;
gapPacket.length = 1;
gapPacket.reserved = kMusicPacketTimeGap;
gapPacket.data[0] = kSysexTimeGap; /* pause in milliseconds */
result = (*g->midiProc)(g->self,g->midiProcRefCon,&gapPacket);
somePacket.length = w - somePacket.data + 1;
*w = kSysexTimeGap;
somePacket.reserved = kMusicPacketTimeGap;
}
else
{
somePacket.length = w - somePacket.data;
somePacket.reserved = 0;
}
result = (*g->midiProc)(g->self,g->midiProcRefCon,&somePacket);
goHome:
return result;
}
pascal ComponentResult MT32DerivedSetKnob(GGlobals *g,
long knobType,long knobNumber,long knobValue,
long partNumber,GCPart *p,
GenericKnobDescription *gkd)
{
ComponentResult result;
short effectSetting;
if(knobType == kGenericMusicKnob)
result = SetMT32Parameter(g,gkd->hw1,knobValue);
else if(knobType == kGenericMusicInstrumentKnob)
{
long param;
partNumber--;
if(gkd->hw1 & 0x80000000)
param = mt32ParamPatch + partNumber * 0x10 + (gkd->hw1 & 0xFF);
else
param = mt32ParamTimbre + partNumber * 0xF6 + gkd->hw1;
knobValue = knobValue + gkd->hw3 - gkd->kd.lowValue;
result = SetMT32Parameter(g,param,knobValue);
}
return result;
}
ComponentResult SetMT32Parameter(GGlobals *g,long p,short v)
{
unsigned short ah,am,al;
ComponentResult result;
ah = (p>>14) & 0x7F;
am = (p>>7) & 0x7F;
al = p & 0x7F;
result = MT32WriteMIDI(g,
(int)0xF0,
(int)0x41,
(int)0x10,
(int)0x16,
(int)0x12,
(int)ah,
(int)am,
(int)al,
(int)v,
(int)0, // checksum computed by writemidi
(int)0xF7,
(int)-3);
#if 0
lame, lame, attach to packet
if(g->midiProc)
{
MusicMIDIPacket somePacket;
somePacket.length = 1;
somePacket.reserved = kMusicPacketTimeGap;
somePacket.data[0] = kSysexTimeGap; /* pause in milliseconds */
result = (*g->midiProc)(g->self,g->midiProcRefCon,&somePacket);
}
#endif
return result;
}
pascal ComponentResult MUSIC_BASENAME()DerivedSetPart(GGlobals *g,
long partNumber,GCPart *p)
{
long param;
short v;
ComponentResult result;
result = noErr;
v = p->midiChannel;
param = mt32ParamChannels + partNumber - 1;
if(v == 0)
v = 16;
else
v--;
result = SetMT32Parameter(g,param,v);
return result;
}
pascal ComponentResult MUSIC_BASENAME()DerivedSetInstrument(GGlobals *g,
long partNumber,GCPart *p)
/*
* Set the knobs one by one. It would be cooler
* if we could set them all at once. !!!
*/
{
short i;
ComponentResult result;
result = noErr;
for(i = 0; i < p->id.knobCount; i++)
MusicSetPartKnob(g->self,partNumber,i+1,p->id.knob[i]);
return result;
}
PM.7/22/96 - 8:44.PM