Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info.

MT32MusicComponent.c

From Higher Intellect Vintage Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
/*
   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;
   }