Appendix 8

Listing for AFM Realtime.c

#include <QuickDraw.h>

#include <MacTypes.h>

#include <FontMgr.h>

#include <WindowMgr.h>

#include <MenuMgr.h>

#include <TextEdit.h>

#include <DialogMgr.h>

#include <EventMgr.h>

#include <DeskMgr.h>

#include <FileMgr.h>

#include <ToolboxUtil.h>

#include <ControlMgr.h>

#include <console.h>

#include <stdlib.h>

#include <math.h>

#include "Class.h"

#include "Utils.h"

#include "GlobalDefs.h"

#include "CSoundAccelerator.h"

#include "Others.h"

/****************************************************************************/

#define kOurAlgorithmID 2 /* resource ID of our 56k code algorithm */

WindowPtr myWindow;

MenuHandle myMenus[2];

int OurVolume;

short *CurSample = NULL,*LastSample = NULL,*SampBuffer = NULL;

short OnLastBuf,dataLoaded=0;

long MacBufSize,GrowAmt;

/****************************************************************************/

/* Prototypes for all the functions in this file. */

void InitApplication(void);

void CloseApplication(void);

void RunDSP(void);

SetUpMenus(void);

int DoMenuCommand(long mResult);

int MainEventLoop(void);

/****************************************************************************/

void main(void)

{

InitApplication();

while (MainEventLoop()) ;

CloseApplication();

}

/****************************************************************************/

void InitApplication(void)

{

/* Do standard Mac initializations. */

InitGraf(&thePort);

InitFonts();

FlushEvents(everyEvent,0);

InitWindows();

InitMenus();

TEInit();

InitDialogs(0L);

InitCursor();

MaxApplZone();

/* Open up a console window so we can write debugging info.

See Utils.c for details. */

#ifdef DEBUG

console_options.top = 40; /* set options for console window */

console_options.left = 2;

console_options.title = "\pRealTime Console";

console_options.txFont = 1;

console_options.nrows = 30;

console_options.ncols = 60;

console_options.pause_atexit = TRUE;

printf(">>> RealTime Up And Running <<<\n");

#endif

/*

/* The following statement is included as a check to see if we can

/* access our program's resources. When the project is run from

/* THINK C, the resource file <project name>.rsrc is automatically

/* opened. When an application is built, these resources are

/* automatically merged with the application.

/*

*/

if (GetResource('MENU', fileID) IS 0) {

SysBeep(20);

return;

}

/* Setup and draw our whopping big menu bar. */

SetUpMenus();

/* Get A5 for slot interrupt routine's use. */

GetOurA5();

/* Initialize the Sound Accelerator driver and class code. */

FailOSErr(InitSoundAcceleratorDriver());

}

/****************************************************************************/

void CloseApplication(void)

{

/* Release our global sample buffer. */

/* if (SampBuffer ISNOT NULL) DisposPtr(SampBuffer); */

}

/***************************************************************************************/

void RunDSP(void)

{

/* Memory locations for general use */

#define FLAGS 0x01 /* these parameters in X memory */

#define DELAY 0x02

#define CYCLE_A 0x03

#define CYCLE_B 0x04

#define CYCLE_C 0x05

#define SINE_TABLE_START 0x06

#define SINE_TABLE_END 0x07

#define SINE_TABLE_SIZE 0x08

#define COSINE_TABLE_START 0x09

#define COSINE_TABLE_END 0x0A

#define COSINE_TABLE_SIZE 0x0B

#define SINE_COSINE_OFFSET 0x0C

#define EXP_TABLE_START 0x0D

#define EXP_TABLE_END 0x0E

#define EXP_TABLE_SIZE 0x0F

#define ZERO 0x10

#define CYCLE_C_LENGTH 0x11

#define ENVELOPE_START 0x12

#define ONE 0x13

/* Parameters for Operator 1 */

#define CARRIER1_FREQ 0x20

#define MODULATOR1_FREQ 0x21

#define MODULATION1_INDEX 0x22

#define RATIO1 0x23

#define NORMALIZATION1 0x24

#define CARRIER1_PHASE 0x25

#define MODULATOR1_PHASE 0x26

#define EXP1_PHASE 0x27

#define IR1_PLUS_START 0x28

#define IR1_MINUS_START 0x29

#define AMP1_START 0x2A

/* Parameters for Operator 2 */

#define CARRIER2_FREQ 0x40

#define MODULATOR2_FREQ 0x41

#define MODULATION2_INDEX 0x42

#define RATIO2 0x43

#define NORMALIZATION2 0x44

#define CARRIER2_PHASE 0x45

#define MODULATOR2_PHASE 0x46

#define EXP2_PHASE 0x47

#define IR2_PLUS_START 0x48

#define IR2_MINUS_START 0x49

#define AMP2_START 0x4A

double amplitude1,freqC1,freqM1,alpha1,beta1,mIndex1,r1,output1;

double amplitude2,freqC2,freqM2,alpha2,beta2,mIndex2,r2,output2;

long carrier1,modulator1,mIndex1Current,ratio1Current,ir1Plus,ir1Minus,amp1;

long carrier2,modulator2,mIndex2Current,ratio2Current,ir2Plus,ir2Minus,amp2;

short xyAddress,counter1,counter2,counter3,overflow;

long xyValue;

long sineStartAddress,sineEndAddress,sineSize,sineCosineOffset;

long expStartAddress,expEndAddress,expSize;

long delay,cycleA,cycleB,cycleC,attackLength,sustainLength,decayLength;

long ir1PlusStartAddress,ir1MinusStartAddress,ir2PlusStartAddress,ir2MinusStartAddress;

long envelopeStartAddress,amp1StartAddress,amp2StartAddress,envelopeLength;

double finalAmplitude,finalOutput,time,freqCorrection,mIndexCorrection,ratioCorrection;

double temp0,temp1,temp2,temp3,maxAmp,maxOutput,maxValue,daOutput;

CSoundAccelerator *ourCard; /* our card object */

/* Create a card object, allocate a card and load our 56k code from a resource.

Then install the slot interrupt routine. Note that we pass the card object

itself as a value to be loaded into A1 when the slot manager calls the

slot managing routines. This way, the slot routines automatically know

what card is requesting service as well as how to service it. */

ourCard = MakeDirectObject(CSoundAccelerator)();

ourCard->Allocate(kOurAlgorithmID);

if (dataLoaded == 0)

{

freqC1 = 440.0; /* resolution = 40 Hz */

freqM1 = 440.0;

freqC2 = 220.0;

freqM2 = 0.0;

attackLength = 40;

sustainLength = 100;

decayLength = 40;

envelopeLength = attackLength + sustainLength + decayLength;

sineStartAddress = 256;

sineSize = 1024;

sineCosineOffset = sineSize / 4;

expStartAddress = 256;

expSize = 1024;

delay = 10; /* 32 */

cycleA = 1;

cycleB = envelopeLength;

cycleC = 200;

sineEndAddress = sineStartAddress + sineSize - 1;

expEndAddress = expStartAddress + expSize - 1;

ir2PlusStartAddress = sineEndAddress + sineCosineOffset + 1;

ir2MinusStartAddress = ir2PlusStartAddress + envelopeLength;

amp2StartAddress = ir2MinusStartAddress + envelopeLength;

ir1PlusStartAddress = expEndAddress + 1;

ir1MinusStartAddress = ir1PlusStartAddress + envelopeLength + 1;

amp1StartAddress = ir1MinusStartAddress + envelopeLength;

envelopeStartAddress = amp1StartAddress + envelopeLength;

mIndexCorrection = 1900.0 / (2.8 * 2.0);

freqCorrection = 40.0;

carrier1 = (long) (freqC1 / freqCorrection);

modulator1 = (long) (freqM1 / freqCorrection);

carrier2 = (long) (freqC2 / freqCorrection);

modulator2 = (long) (freqM2 / freqCorrection);

ourCard->LoadXY(0,ZERO,(long) 0);

ourCard->LoadXY(0,ONE,(long) 1);

ourCard->LoadXY(0,ENVELOPE_START,envelopeStartAddress);

printf("Loading sine table into Y memory...\n");

ourCard->LoadXY(0,SINE_TABLE_START,sineStartAddress);

ourCard->LoadXY(0,SINE_TABLE_END,sineEndAddress);

ourCard->LoadXY(0,SINE_TABLE_SIZE,sineSize);

ourCard->LoadXY(0,SINE_COSINE_OFFSET,sineCosineOffset);

for (counter1 = sineStartAddress; counter1 <= sineEndAddress + sineCosineOffset; counter1++)

{

temp0 = (double) (counter1 - sineStartAddress) / (double) (sineSize);

temp1 = sin(TWOPI * temp0);

xyValue = (long) (8388607.0 * temp1);

ourCard->LoadXY(1,counter1,xyValue);

}

printf("Sine table loaded.\n");

printf("Loading exponential table into X memory...\n");

ourCard->LoadXY(0,EXP_TABLE_START,expStartAddress);

ourCard->LoadXY(0,EXP_TABLE_END,expEndAddress);

ourCard->LoadXY(0,EXP_TABLE_SIZE,expSize);

for (counter1 = expStartAddress; counter1 <= expEndAddress; counter1++)

{

temp0 = (double) (counter1 - expStartAddress) / (double) (expSize);

temp1 = exp(temp0 * log(8388608.0));

xyValue = (long) (temp1);

ourCard->LoadXY(0,(counter1 + expStartAddress),xyValue);

}

printf("Exponential table loaded.\n");

printf("Now loading algorithm parameters into memory...\n");

/* Load ir1Plus/Minus and ir2Plus/Minus now */

/* attack */

mIndex1 = 0.000; /* 1.700 */

r1 = 1.000; /* 0.680 */

mIndex2 = 0.000;

r2 = 1.000;

amp1 = 100;

amp2 = 100 / 4;

ir1Plus = (long) ((mIndex1/2.0) * (r1 + 1.0/r1) * mIndexCorrection);

ir1Minus = (long) ((mIndex1/2.0) * (r1 - 1.0/r1) * mIndexCorrection);

ir2Plus = (long) ((mIndex2/2.0) * (r2 + 1.0/r2) * mIndexCorrection);

ir2Minus = (long) ((mIndex2/2.0) * (r2 - 1.0/r2) * mIndexCorrection);

for (counter1 = ir1PlusStartAddress; counter1 < ir1PlusStartAddress + attackLength; counter1++)

{

ourCard->LoadXY(0,counter1,ir1Plus);

}

printf("Attack ir1Plus table loaded into X memory.\n");

for (counter1 = ir1MinusStartAddress; counter1 < ir1MinusStartAddress + attackLength; counter1++)

{

ourCard->LoadXY(0,counter1,ir1Minus);

}

printf("Attack ir1Minus table loaded into X memory.\n");

for (counter1 = amp1StartAddress; counter1 < amp1StartAddress + attackLength; counter1++)

{

ourCard->LoadXY(0,counter1,amp1);

}

printf("Attack amp1 table loaded into X memory.\n");

for (counter1 = ir2PlusStartAddress; counter1 < ir2PlusStartAddress + attackLength; counter1++)

{

ourCard->LoadXY(1,counter1,ir2Plus);

}

printf("Attack ir2Plus table loaded into Y memory.\n");

for (counter1 = ir2MinusStartAddress; counter1 < ir2MinusStartAddress + attackLength; counter1++)

{

ourCard->LoadXY(1,counter1,ir2Minus);

}

printf("Attack ir2Minus table loaded into Y memory.\n");

for (counter1 = amp2StartAddress; counter1 < amp2StartAddress + attackLength; counter1++)

{

ourCard->LoadXY(1,counter1,amp2);

}

printf("Attack amp2 table loaded into Y memory.\n");

/* */

/* sustain */

mIndex1 = 0.000; /* 1.700 */

r1 = 1.000; /* 0.680 */

mIndex2 = 0.000;

r2 = 1.000;

amp1 = 100;

amp2 = 100 / 4;

ir1Plus = (long) ((mIndex1/2.0) * (r1 + 1.0/r1) * mIndexCorrection);

ir1Minus = (long) ((mIndex1/2.0) * (r1 - 1.0/r1) * mIndexCorrection);

ir2Plus = (long) ((mIndex2/2.0) * (r2 + 1.0/r2) * mIndexCorrection);

ir2Minus = (long) ((mIndex2/2.0) * (r2 - 1.0/r2) * mIndexCorrection);

for (counter1 = ir1PlusStartAddress + (attackLength); counter1 < ir1PlusStartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(0,counter1,ir1Plus);

}

printf("Sustain ir1Plus table loaded into X memory.\n");

for (counter1 = ir1MinusStartAddress + (attackLength); counter1 < ir1MinusStartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(0,counter1,ir1Minus);

}

printf("Sustain ir1Minus table loaded into X memory.\n");

for (counter1 = amp1StartAddress + (attackLength); counter1 < amp1StartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(0,counter1,amp1);

}

printf("Sustain ir1Minus table loaded into X memory.\n");

for (counter1 = ir2PlusStartAddress + (attackLength); counter1 < ir2PlusStartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(1,counter1,ir2Plus);

}

printf("Sustain ir2Plus table loaded into Y memory.\n");

for (counter1 = ir2MinusStartAddress + (attackLength); counter1 < ir2MinusStartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(1,counter1,ir2Minus);

}

printf("Sustain ir2Minus table loaded into Y memory.\n");

for (counter1 = amp2StartAddress + (attackLength); counter1 < amp2StartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(1,counter1,amp2);

}

printf("Sustain amp2 table loaded into Y memory.\n");

/* */

/* decay */

mIndex1 = 0.000; /* 1.700 */

r1 = 1.000; /* 0.680 */

mIndex2 = 0.000;

r2 = 1.000;

amp1 = 100;

amp2 = 100 / 4;

ir1Plus = (long) ((mIndex1/2.0) * (r1 + 1.0/r1) * mIndexCorrection);

ir1Minus = (long) ((mIndex1/2.0) * (r1 - 1.0/r1) * mIndexCorrection);

ir2Plus = (long) ((mIndex2/2.0) * (r2 + 1.0/r2) * mIndexCorrection);

ir2Minus = (long) ((mIndex2/2.0) * (r2 - 1.0/r2) * mIndexCorrection);

for (counter1 = ir1PlusStartAddress + (attackLength + sustainLength); counter1 < ir1PlusStartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(0,counter1,ir1Plus);

}

printf("Decay ir1Plus table loaded.\n");

for (counter1 = ir1MinusStartAddress + (attackLength + sustainLength); counter1 < ir1MinusStartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(0,counter1,ir1Minus);

}

printf("Decay ir1Minus table loaded.\n");

for (counter1 = amp1StartAddress + (attackLength + sustainLength); counter1 < amp1StartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(0,counter1,amp1);

}

printf("Decay amp1 table loaded.\n");

for (counter1 = ir2PlusStartAddress + (attackLength + sustainLength); counter1 < ir2PlusStartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(1,counter1,ir2Plus);

}

printf("Decay ir2Plus table loaded.\n");

for (counter1 = ir2MinusStartAddress + (attackLength + sustainLength); counter1 < ir2MinusStartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(1,counter1,ir2Minus);

}

printf("Decay ir2Minus table loaded.\n");

for (counter1 = amp2StartAddress + (attackLength + sustainLength); counter1 < amp2StartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(1,counter1,amp2);

}

printf("Decay amp2 table loaded.\n");

/* */

/* A simple waveform envelope */

/* 1 */

xyValue = 0;

for (counter1 = envelopeStartAddress; counter1 < envelopeStartAddress + attackLength; counter1++)

{

ourCard->LoadXY(0,counter1,xyValue);

xyValue++;

}

/* 2 */

for (counter1 = envelopeStartAddress + (attackLength); counter1 < envelopeStartAddress + sustainLength + (attackLength); counter1++)

{

ourCard->LoadXY(0,counter1,xyValue);

}

/* 3 */

for (counter1 = envelopeStartAddress + (attackLength + sustainLength); counter1 < envelopeStartAddress + decayLength + (attackLength + sustainLength); counter1++)

{

ourCard->LoadXY(0,counter1,xyValue);

xyValue--;

}

ourCard->LoadXY(0,DELAY,delay);

ourCard->LoadXY(0,CYCLE_A,cycleA);

ourCard->LoadXY(0,CYCLE_B,cycleB);

ourCard->LoadXY(0,CYCLE_C,cycleC);

ourCard->LoadXY(0,CARRIER1_FREQ,carrier1);

ourCard->LoadXY(0,MODULATOR1_FREQ,modulator1);

/* IR1_PLUS/MINUS hold the start addresses of lookup tables for ir1Plus and ir1Minus */

/* AMP1 holds the start address of lookup table for amp1 */

ourCard->LoadXY(0,IR1_PLUS_START,ir1PlusStartAddress);

ourCard->LoadXY(0,IR1_MINUS_START,ir1MinusStartAddress);

ourCard->LoadXY(0,AMP1_START,amp1StartAddress);

/* */

ourCard->LoadXY(0,CARRIER2_FREQ,carrier2);

ourCard->LoadXY(0,MODULATOR2_FREQ,modulator2);

/* IR2_PLUS/MINUS hold the start addresses of lookup tables for ir2Plus and ir2Minus */

/* AMP2 holds the start address of lookup table for amp2 */

ourCard->LoadXY(0,IR2_PLUS_START,ir2PlusStartAddress);

ourCard->LoadXY(0,IR2_MINUS_START,ir2MinusStartAddress);

ourCard->LoadXY(0,AMP2_START,amp2StartAddress);

/* */

printf("All algorithm parameters loaded.\n");

finalAmplitude = 41943; /* max = 4194303 */

dataLoaded = 1;

}

ourCard->DoHostCmd(0);

printf("Waiting for HF3...\n");

while (ourCard->TestHF3() IS 1)

{

}

DestroyDirectObject(ourCard);

ourCard = NULL;

printf("\n");

}

/****************************************************************************

ALL the following procedures are standard Macintosh menu management

and main event loop stuff.

***************************************************************************/

/****************************************************************************/

SetUpMenus(void)

{

int i;

myMenus[appleM] = NewMenu( appleID, "\p\024" );

AddResMenu( myMenus[appleM], 'DRVR' );

myMenus[fileM] = GetMenu(fileID);

for ( (i=appleM); (i<=fileM); i++ ) InsertMenu(myMenus[i], 0) ;

DrawMenuBar();

}

/****************************************************************************/

int DoMenuCommand(long mResult)

{

Str255 name;

switch (HiWord(mResult)) {

case appleID:

GetItem(myMenus[appleM],LoWord(mResult),&name);

OpenDeskAcc(&name);

SetPort(myWindow);

break;

case fileID:

switch (LoWord(mResult)) {

case fmRunDSP:

RunDSP();

break;

case fmQuit:

return(0);

break;

}

break;

}

HiliteMenu(0);

return(1);

}

/****************************************************************************/

int MainEventLoop(void)

{

EventRecord myEvent;

WindowPtr whichWindow;

register char theChar;

SystemTask();

if (GetNextEvent(everyEvent,&myEvent)) {

switch (myEvent.what) {

case keyDown:

case autoKey:

theChar = myEvent.message & charCodeMask;

if ((myEvent.modifiers & cmdKey) ISNOT 0) {

return( DoMenuCommand(MenuKey(theChar)));

} else {

if ((theChar >= '0') AND (theChar <= '9')) {

OurVolume = theChar - '0';

}

}

break;

case mouseDown:

switch (FindWindow(myEvent.where,&whichWindow)) {

case inSysWindow:

SystemClick(&myEvent,whichWindow);

break;

case inMenuBar:

return(DoMenuCommand(MenuSelect(myEvent.where)));

break;

} /* end switch FindWindow */

break;

} /* end of switch myEvent.what */

} /* if */

return(1);

}