home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Audio 4.94 - Over 11,000 Files
/
audio-11000.iso
/
mac
/
soundutl
/
vmtrs10s.hqx
/
VUMeters
/
Sources
/
VUMeters.C
< prev
next >
Wrap
Text File
|
1993-08-05
|
46KB
|
1,835 lines
/*
* ARTA VUMeters for Macintosh
* Malcolm Slaney
* Advanced Technology Group
* Apple Computer, Inc.
* malcolm@apple.com
* 1992-1993
*
* Warranty Information
* Even though Apple has reviewed this software, Apple makes no warranty
* or representation, either express or implied, with respect to this
* software, its quality, accuracy, merchantability, or fitness for a
* particular purpose. As a result, this software is provided "as is,"
* and you, its user, are assuming the entire risk as to its quality
* and accuracy.
*
* Copyright (c) 1992-1993 by Apple Computer, Inc
* All Rights Reserved.
*/
/*
* This application is actually implemented using three different ThinkC
* objects.
*
* The most primitive is call CWindowPiece. This is just a piece of a
* window on the screen. It comes with it's own offscreen GWorld and a
* record of what region of the window is dirty. The idea is that a normal
* Macintosh window can be tiled with CWindowPieces to provide all the
* interesting graphics. This class is not specific to specific to a meter.
* It can be used by any object that needs fast graphics on the screen.
*
* The CVUMeter class is a specialized kind of CWindowPiece. It knows
* about all the things that make a VUMeter worthwhile. As such, it knows
* how to draw a scale with ticks and labels, how to draw a pointer, and
* where to get the latest meter reading. These objects contain off-screen
* GWorlds for the scale (and the overall Gworld provided by the CWindowPiece.)
*
* The CPortWindow is a high level object that keeps track of a Macintosh
* window and tiles one or two of the CVUMeter objects (depending on whether
* we are displaying a mono or stereo VUMeter.).
*
* One helper objects is also defined.
*
* The CPictureMeter class is a special object that uses a PICT in the resource
* fork to define the scale. This is only used by the "About VUMeters" dialog.
*
*/
#include <math.h>
#include <stdio.h>
#include "VUMeters.h"
#include "VUMeterResources.h"
#include <DSPManager.h>
#include <StandardSound.h>
#include "SoundMonitor.h"
RGBColor rgbBackgroundColor = {65535, 63542, 55792}; /* Dirty Yellow */
RGBColor rgbTickColor = {0, 0, 0}; /* Black */
RGBColor rgbOverloadColor = {65535, 0, 0}; /* Bright Red */
RGBColor rgbBlackColor = {0, 0, 0}; /* Black */
RGBColor rgbWhiteColor = {65535, 65535, 65535}; /* White */
#define kMeterTimeConstant .25 /* In Seconds */
#define kDefaultVUWidth 200
#define kDefaultVUHeight 90
#define MIN_WINDOW_HEIGHT kDefaultVUWidth
#define MIN_WINDOW_WIDTH kDefaultVUHeight
#define DSP_MAXIMUM_VALUE (float)1.0
int gPatchChannels = kMaxChannel;
int gPortType = kInputPort;
int gLevelType = kPeakReading;
int gSpeedType = kNormalSpeed;
int gReferenceType = kFullScaleReference;
float gLeftInputGain = 0.0, gRightInputGain = 0.0, gMaxInputGain = 0.0;
float gLeftOutputGain = 0.0, gRightOutputGain = 0.0, gMaxOutputGain = 0.0;
/* OK, just a few more globals for
* some state information.
*/
MenuHandle gAppleMenu, gFileMenu, gEditMenu, gPatchMenu;
Boolean gDone = false;
WindowPtr gCurrentWindow = 0;
/* A simple structure to map a small
* integer key into a new number and
* a Pascal string for output.
*/
struct tagStruct {
int num; /* Number with this key */
int name; /* Index in STR# Resource */
};
struct tagStruct portTypes[] = {
{ SMMonitorInput, kInputPortString}, /* kInputPort */
{ SMMonitorOutput, kOutputPortString} /* kOutputPort */
};
/* Mapping between channel type
* and the pretty name in the
* meter window.
*/
struct tagStruct channelTypes[] = {
{ 0, kLeftChannelString}, /* kLeftChannel */
{ 0, kRightChannelString}, /* kRightChannel */
{ 0, kMaximumChannelString}, /* kMaxChannel */
{ 0, 0} /* kBothChannel */
};
/* Mapping between level number
* and the pretty name in the
* meter window.
*/
struct tagStruct levelNames[] = {
{ kPeakReading, kPeakReadingString}, /* kPeakReading */
{ kPowerReading, kPowerReadingString} /* kPowerReading */
};
/* Mapping between level number
* and the DSP module name defined
* in the DSP assembly language.
*/
struct tagStruct levelModules[] = {
{ kPeakReading, kPeakModuleString}, /* kPeakReading */
{ kPowerReading, kPowerModuleString} /* kPowerReading */
};
struct tagStruct referenceNames[] = {
{ kFullScaleReference, kFullScaleString},
{ kAnalogLineReference, kAnalogLineString}
};
#define DSPMonitorNum(port, level) (port + (level * 2))
#define MAX_DSP_MONITORS (DSPMonitorNum(kOutputPort, kPowerReading)+1)
static DSPMonitor aDSPMonitor[MAX_DSP_MONITORS];
int useMouseForLevels = 0;
float gMouseLevel[2];
static DSPCPUDeviceParamBlkPtr theDSP = 0;
#define UNIMPL_TRAP_NUM 0x9F
#define BOM_TRAP_NUM 0xBF5
void CloseDSPs(){
int i;
for (i=0;i<MAX_DSP_MONITORS; i++){
if (aDSPMonitor[i])
SMDestroyDSPMonitor(aDSPMonitor[i]);
aDSPMonitor[i] = 0;
}
if (theDSP)
SMCloseDSP3210(theDSP);
theDSP = 0;
}
static SoundStream theSoundStream = 0;
float *GetDSPVolumeAddress(enum portNum portType, enum channelNum channelType,
enum levelNum levelType, enum speedNum speedType){
DSPMonitor theMonitor;
Fixed frameRate, sampleRate;
float decayRate;
if (useMouseForLevels) /* Don't call DSP Manager */
return gMouseLevel;
if (NGetTrapAddress(BOM_TRAP_NUM, ToolTrap) == NGetTrapAddress(UNIMPL_TRAP_NUM, ToolTrap)){
DoStopAlert(kConfigurationInstallError);
ExitToShell();
}
if (theDSP == 0){
int i;
if (!theSoundStream)
theSoundStream = SMOpenDSPSoundStream();
theDSP = SMOpenDSP3210(theSoundStream);
if (theDSP == 0){
DoStopAlert(kConfigurationStartError);
ExitToShell();
}
for (i=0;i<MAX_DSP_MONITORS; i++){
aDSPMonitor[i] = 0;
}
}
theMonitor = aDSPMonitor[DSPMonitorNum(portType, levelType)];
if ( theMonitor == 0){
Str255 moduleName;
GetIndString(moduleName, METER_LABEL_RESOURCE, levelModules[levelType].name);
theMonitor = aDSPMonitor[DSPMonitorNum(portType, levelType)] =
SMCreateDSPMonitor(theDSP, theSoundStream,
moduleName, portTypes[portType].num);
if (!theMonitor){
DoStopAlert(kCreateDSPMonitorError);
CloseDSPs();
ExitToShell();
}
}
switch(channelType){
case kLeftChannel:
SMSetChannel(theMonitor, SMChannelAddClient, SMChannelDontChange);
break;
case kRightChannel:
SMSetChannel(theMonitor, SMChannelDontChange, SMChannelAddClient);
break;
case kBothChannel:
case kMaxChannel:
SMSetChannel(theMonitor, SMChannelAddClient, SMChannelAddClient);
break;
}
StdSndGetSampleAndFrameRate(theSoundStream, &frameRate, &sampleRate);
decayRate=exp(-1/kMeterTimeConstant/(frameRate/65536.0));
SMMaxSetDecayRate(theMonitor, decayRate);
SMMaxSetScaleFactor(theMonitor, 1.0/(frameRate/65536.0));
switch (speedType){
case kFastSpeed:
return SMGetFastLevelsPtr(theMonitor);
default:
return SMGetSlowLevelsPtr(theMonitor);
}
}
void ReleaseDSPVolumeAddress(enum portNum portType, enum channelNum channelType,
enum levelNum levelType){
DSPMonitor theMonitor;
if (useMouseForLevels) /* Short Circuit this routine. */
return;
theMonitor = aDSPMonitor[DSPMonitorNum(portType, levelType)];
if ( theMonitor == 0){
if (!theMonitor){
DoStopAlert(kReleaseDSPMonitorError);
CloseDSPs();
ExitToShell();
}
}
switch(channelType){
case kLeftChannel:
SMSetChannel(theMonitor, SMChannelRemoveClient, SMChannelDontChange);
break;
case kRightChannel:
SMSetChannel(theMonitor, SMChannelDontChange, SMChannelRemoveClient);
break;
case kBothChannel:
case kMaxChannel:
SMSetChannel(theMonitor, SMChannelRemoveClient, SMChannelRemoveClient);
break;
}
}
void GetDSPGains(){
unsigned long left, right;
StdSndGetInputGain(theSoundStream, &left, &right);
gLeftInputGain = -1.5*left;
gRightInputGain = -1.5*right;
gMaxInputGain = gLeftInputGain>gRightInputGain? gLeftInputGain : gRightInputGain;
StdSndGetOutputAttenuation(theSoundStream, &left, &right);
gLeftOutputGain = -1.5*left;
gRightOutputGain = -1.5*right;
gMaxOutputGain = gLeftOutputGain>gRightOutputGain? gLeftOutputGain : gRightOutputGain;
}
/****************************************** ScaleAngle *********************************/
/*
* The following scale angles were computed using Mathematica. Assuming that the
* scale is logarithmic and has a total range of SCALE_DEGREES. The most positive
* excursion (SCALE_DEGREES/2) should occur at the maximum volume level (+5) and the
* most negative excursion (-SCALE_DEGREES/2) should occur at the minimum volume
* level. We solve the following equation:
* degrees = a log(dB + 65) + b
* at the following points
* degrees dB
* DEG/2 +5
* -DEG/2 -60
* The solution is
* a = d/(x1 - x2)
* b = -d/2 (x1+x2)/(x1-x2)
* where d = SCALE_DEGREES, x1 = log(10 - 5), and x2 = log(10 - -60).
*/
float ScaleAngle(dB)
float dB;
{
register float a, b, x1, x2;
const float mindB = -60, maxdB = 5, offsetdB = 10, d = SCALE_DEGREES;
if (dB < mindB)
return -d/2;
else if (dB > maxdB)
return d/2;
x1 = log(offsetdB-maxdB);
x2 = log(offsetdB-mindB);
a = d/(x1 - x2);
b = -d/2*(x1 + x2)/(x1 - x2);
return a * log(offsetdB-dB) + b;
}
/****************************************** ComputeTick *********************************/
Rect ComputeTick(vu, center, length, start, stop)
float vu;
Point center;
int length;
float start, stop;
{
Rect r;
float angle = ScaleAngle(vu)*3.1415926535/180.0;
float cosAngle = cos(angle);
float sinAngle = sin(angle);
r.top = center.v - cosAngle*length*stop;
r.bottom = center.v - cosAngle*length*start;
r.right = center.h + sinAngle*length*start;
r.left = center.h + sinAngle*length*stop;
return r;
}
/*=================================== CWindowPiece ====================================*/
void CWindowPiece::IWindowPiece(){
fOffScreenWorld = 0;
SetRect(&this->fWindowRect, 0, 0, 0, 0);
fWindow = 0;
fDirtyScreenRegion = NewRgn();
if (!fDirtyScreenRegion){
DoStopAlert(kScreenRegionAllocationError);
CloseDSPs();
ExitToShell();
}
}
void CWindowPiece::SetWindow(WindowPtr win){
fWindow = win;
}
void CWindowPiece::SetWindowRect(Rect *screenRect, Rect *windowRect){
QDErr errorCode;
GWorldPtr newWorld = 0;
this->fWindowRect = *windowRect;
if (fOffScreenWorld){ /* Resize Existing GWorld */
newWorld = fOffScreenWorld;
errorCode = UpdateGWorld(&newWorld, DEFAULT_SCREEN_DEPTH, screenRect,
NIL_POINTER, NIL_POINTER, NO_FLAGS);
} else { /* Allocate a new one */
errorCode = NewGWorld(&newWorld, DEFAULT_SCREEN_DEPTH, screenRect, NIL_POINTER,
NIL_POINTER, NO_FLAGS);
}
fOffScreenWorld = newWorld;
if (errorCode == memFullErr || !IsMemoryAvailable(0)){
DoStopAlert(kNoMemoryWindowPieceError);
CloseDSPs();
ExitToShell();
}
if (errorCode != noErr){
DoStopAlert(kNoOffscreenWorldError);
CloseDSPs();
ExitToShell();
}
this->Update();
}
void CWindowPiece::Erase(){
GDHandle oldGD;
GWorldPtr oldGW;
GetGWorld(&oldGW, &oldGD);
LockPixels(fOffScreenWorld->portPixMap);
SetGWorld(fOffScreenWorld, NIL_POINTER);
RGBForeColor(&rgbBackgroundColor);
EraseRect(&fWindowRect);
SetGWorld(oldGW, oldGD);
UnlockPixels(fOffScreenWorld->portPixMap);
}
void CWindowPiece::CopyToWindow(){
GDHandle oldGD;
GWorldPtr oldGW;
if (!fWindow){
DoStopAlert(kNoCopyToWindowError);
CloseDSPs();
ExitToShell();
}
GetGWorld(&oldGW, &oldGD);
LockPixels(fOffScreenWorld->portPixMap);
SetPort(fWindow);
OffsetRgn(fDirtyScreenRegion, fWindowRect.left, fWindowRect.top);
RGBBackColor(&rgbWhiteColor);
RGBForeColor(&rgbBlackColor);
CopyBits((BitMap *)&fOffScreenWorld->portPixMap, &fWindow->portBits,
&fOffScreenWorld->portRect, &fWindowRect, srcCopy, fDirtyScreenRegion);
OffsetRgn(fDirtyScreenRegion, -fWindowRect.left, -fWindowRect.top);
SetGWorld(oldGW, oldGD);
UnlockPixels(fOffScreenWorld->portPixMap);
}
void CWindowPiece::Dispose(){
if (fOffScreenWorld)
DisposeGWorld(fOffScreenWorld);
fOffScreenWorld = 0;
if (fDirtyScreenRegion)
DisposeRgn(fDirtyScreenRegion);
fDirtyScreenRegion = 0;
/* Don't do this here... the CPortWindow
* gets to dispose of this... don't want
* to do this more than once!
* if (fWindow)
* DisposeWindow(fWindow);
*/
fWindow = 0;
}
void CWindowPiece::Update(){
RectRgn(fDirtyScreenRegion, &fWindowRect);
OffsetRgn(fDirtyScreenRegion, -fWindowRect.left, -fWindowRect.top);
}
/*=================================== CVUMeter ====================================*/
void CVUMeter::IVUMeter(enum portNum portType, enum channelNum channelIndicator,
enum levelNum levelType, enum speedNum speedType,
enum referenceNum referenceType){
this->IWindowPiece();
fLastReading = -1000; /* Arbitrary and unlikely */
fScaleWorld = 0;
SetPt(&fMeterCenter, 0, 0);
fScaleLength = 0;
fOverload = 0;
fPortType = portType;
fChannelIndicator = channelIndicator;
fLevelType = levelType;
fSpeedType = speedType;
fReferenceType = referenceType;
fDirtyScaleRegion = NewRgn();
if (!fDirtyScaleRegion){
DoStopAlert(kNoScaleRegionError);
CloseDSPs();
ExitToShell();
}
fCurrentReading = GetDSPVolumeAddress(fPortType, fChannelIndicator, fLevelType, fSpeedType);
}
void CVUMeter::GetExternalGain(){
static float zeroGain = 0.0;
if (fReferenceType == kAnalogLineReference){
if (fPortType == kInputPort){
switch (fChannelIndicator){
case kLeftChannel:
fChannelGainPointer = &gLeftInputGain;
break;
case kRightChannel:
fChannelGainPointer = &gRightInputGain;
break;
case kMaxChannel:
fChannelGainPointer = &gMaxInputGain;
break;
default:
fChannelGainPointer = &zeroGain;
}
} else {
switch (fChannelIndicator){
case kLeftChannel:
fChannelGainPointer = &gLeftOutputGain;
break;
case kRightChannel:
fChannelGainPointer = &gRightOutputGain;
break;
case kMaxChannel:
fChannelGainPointer = &gMaxOutputGain;
break;
default:
fChannelGainPointer = &zeroGain;
}
}
} else{
fChannelGainPointer = &zeroGain;
}
}
struct tagStruct tickList[] = {
{-60, kMinusSixtyString},
{-50, 0},
{-40, kMinusFourtyString},
{-30, kMinusThirtyString},
{-25, 0},
{-20, kMinusTwentyString},
{-15, 0},
{-10, kMinusTenString},
{-5, kMinusFiveString},
{-4, 0},
{-3, 0},
{-2, 0},
{-1, 0},
{0, kZeroLevelString},
{1, 0},
{2, 0},
{3, 0},
{4, 0},
{5, kPlusFiveString}};
void CVUMeter::DrawScale(){
int i, len;
const int kCenterRadius = 5;
Rect rect;
GDHandle oldGD;
GWorldPtr oldGW;
Str255 tickString, channelString, levelString, referenceString, minusString;
if (!fScaleWorld)
return; /* Should never see this condition...*/
GetGWorld(&oldGW, &oldGD);
LockPixels(fScaleWorld->portPixMap);
SetGWorld(fScaleWorld, NIL_POINTER);
RGBBackColor(&rgbBackgroundColor); /* Sort of dirty yellow */
rect = fScaleWorld->portRect;
EraseRect(&rect);
RGBForeColor(&rgbOverloadColor); /* Draw Overload Bar */
SetRect(&rect, fMeterCenter.h - fScaleLength, fMeterCenter.v - fScaleLength,
fMeterCenter.h + fScaleLength, fMeterCenter.v + fScaleLength);
i = fScaleLength * (kTickEnd - kTickStart) + 0.5;
PenSize(i, i);
FrameArc(&rect, (short)(ScaleAngle(0.0)),
(short)(ScaleAngle(5.0)-ScaleAngle(0.0)+0.5));
RGBForeColor(&rgbTickColor); /* Draw the ticks and legend */
TextSize(SCALE_FONT_SIZE);
TextFont(SCALE_FONT_NUMBER);
PenSize(1,1);
GetIndString(minusString, TICK_LABEL_RESOURCE, kMinusSignString);
for (i=0;i<sizeof(tickList)/sizeof(struct tagStruct);i++){
GetIndString(tickString, TICK_LABEL_RESOURCE, tickList[i].name);
if (tickString[0] != 0)
rect = ComputeTick(tickList[i].num, fMeterCenter, fScaleLength,
kTickStart, kTickEnd);
else
rect = ComputeTick(tickList[i].num, fMeterCenter, fScaleLength,
kTickStart, kTickMiddle);
MoveTo(rect.right, rect.bottom);
LineTo(rect.left, rect.top);
if (tickString[0] != 0){
len = StringWidth(tickString);
/* Want to center without worrying
* about the initial '-'. Add in
* the width again so it won't
* affect the centering calucation
*/
if (minusString[0] && minusString[1] == tickString[1])
len += StringWidth(minusString);
Move(-len/2, -3); /* Center String */
DrawString(tickString);
}
}
/* Draw Needle Center */
SetRect(&rect, -kCenterRadius, -kCenterRadius, kCenterRadius, kCenterRadius);
OffsetRect(&rect, fMeterCenter.h, fMeterCenter.v);
FrameOval(&rect);
GetIndString(channelString, METER_LABEL_RESOURCE, channelTypes[fChannelIndicator].name);
GetIndString(levelString, METER_LABEL_RESOURCE, levelNames[fLevelType].name);
GetIndString(referenceString, METER_LABEL_RESOURCE, referenceNames[fReferenceType].name);
MoveTo(5, SCALE_FONT_SIZE+2); /* Draw Channel Label */
DrawString(channelString);
if (levelNames[fLevelType].name){ /* Draw Meter Type */
len = StringWidth(levelString);
len += StringWidth(referenceString);
i = fMeterCenter.v + kCenterRadius;
rect = (**fScaleWorld->portPixMap).bounds;
if (i > rect.bottom)
i = rect.bottom;
i -= (SCALE_FONT_SIZE*3)/2;
MoveTo(fMeterCenter.h - len/2, i);
DrawString(levelString);
DrawString(referenceString);
}
if (0) { /* Add Screen Depth for Debugging */
Str255 screenDepthString;
NumToString(-(**((*fOffScreenWorld).portPixMap)).pixelSize, screenDepthString);
DrawString(screenDepthString);
}
SetGWorld(oldGW, oldGD);
UnlockPixels(fScaleWorld->portPixMap);
}
void CVUMeter::SetMeterParms(Rect *sizeRect){
fScaleLength = (sizeRect->right - 3*SCALE_FONT_SIZE)/2;
SetPt(&fMeterCenter, sizeRect->right/2, fScaleLength+2*SCALE_FONT_SIZE);
}
/*
* CVUMeter::SetWindowRect - Set the size of a VUMeter. First update the size of
* the private GWorld I use for the scale, then let the inherited method take care
* of the offscreen GWorld.
*/
void CVUMeter::SetWindowRect(Rect *screenRect, Rect *windowRect){
Rect sizeRect;
QDErr errorCode;
GWorldPtr newWorld;
sizeRect = *windowRect;
OffsetRect(&sizeRect, -sizeRect.left, -sizeRect.top);
this->SetMeterParms(&sizeRect);
if (fScaleWorld){
newWorld = fScaleWorld;
errorCode = UpdateGWorld(&newWorld, DEFAULT_SCREEN_DEPTH, screenRect,
NIL_POINTER, NIL_POINTER, NO_FLAGS);
} else {
errorCode = NewGWorld(&newWorld, DEFAULT_SCREEN_DEPTH, screenRect, NIL_POINTER,
NIL_POINTER, NO_FLAGS);
}
fScaleWorld = newWorld;
if (errorCode != noErr){
DoCautionAlert(kCantCreateScaleWorldError);
this->Dispose();
return;
}
RectRgn(fDirtyScaleRegion, &sizeRect);
inherited::SetWindowRect(screenRect, windowRect);
if (!fOffScreenWorld)
return;
SetRect(&fOverloadRect,
fOffScreenWorld->portRect.right - SCALE_OVERLOAD_DELTA - SCALE_OVERLOAD_SIZE,
fOffScreenWorld->portRect.top + SCALE_OVERLOAD_DELTA - SCALE_OVERLOAD_SIZE,
fOffScreenWorld->portRect.right - SCALE_OVERLOAD_DELTA + SCALE_OVERLOAD_SIZE,
fOffScreenWorld->portRect.top + SCALE_OVERLOAD_DELTA + SCALE_OVERLOAD_SIZE);
this->Update();
this->DrawScale();
}
/*
* This routine is responsible for combining the meter scale with the new needle's
* position and dumping the new face into an offscreen bitmap (which is called
* fOffscreenWorld).
*
* Remember, that we've already cached an offscreen bitmap with the meter's face.
* This routine first copies in the background and the screen, then overlays the
* meter's needle and the overload light. Finally, all the parts that have changed
* are stored in the fDirtyScreenRegion so we know what needs updating.
*/
void CVUMeter::DrawNeedle(){
short currentOverload;
GDHandle oldGD;
GWorldPtr oldGW;
Rect rect;
static RgnHandle overloadRegion = 0;
if (overloadRegion == 0){
overloadRegion = NewRgn();
}
GetGWorld(&oldGW, &oldGD);
LockPixels(fOffScreenWorld->portPixMap);
LockPixels(fScaleWorld->portPixMap);
SetGWorld(fOffScreenWorld, NIL_POINTER);
RGBBackColor(&rgbWhiteColor); /* Copy in scale and bgnd. */
RGBForeColor(&rgbBlackColor);
CopyBits((BitMap *)&fScaleWorld->portPixMap, (BitMap *)&fOffScreenWorld->portPixMap,
&fScaleWorld->portRect, &fOffScreenWorld->portRect, srcCopy, fDirtyScaleRegion);
RGBForeColor(&rgbBlackColor); /* Be sure we are drawing in black */
PenSize(2,2); /* Now draw the needle */
rect = ComputeTick(fLastReading, fMeterCenter, fScaleLength, 0.0, kTickStart);
RGBForeColor(&rgbTickColor);
MoveTo(rect.right, rect.bottom);
LineTo(rect.left, rect.top);
if (rect.left > rect.right){
int t;
t = rect.left;
rect.left = rect.right;
rect.right = t;
}
/* OK, we need to take the part of the
* scale region that is dirty (where we
* just drew the needle into) and union
* it with the region that has the old
* needle in it on the screen. Be sure
* to add some extra space to it to make
* sure we get the full width of the line.
*/
InsetRect(&rect, -2, -2);
RectRgn(fDirtyScreenRegion, &rect);
UnionRgn(fDirtyScreenRegion, fDirtyScaleRegion, fDirtyScreenRegion);
RectRgn(fDirtyScaleRegion, &rect);
currentOverload = 0;
if (fLastReading >= 0){ /* Light the overload indicator */
RGBForeColor(&rgbOverloadColor);
FillOval(&fOverloadRect, black);
currentOverload = 1;
}
if (currentOverload != fOverload){
RectRgn(overloadRegion, &fOverloadRect);
UnionRgn(fDirtyScaleRegion, overloadRegion, fDirtyScaleRegion);
UnionRgn(fDirtyScreenRegion, overloadRegion, fDirtyScreenRegion);
}
fOverload = currentOverload;
SetGWorld(oldGW, oldGD);
UnlockPixels(fScaleWorld->portPixMap);
UnlockPixels(fOffScreenWorld->portPixMap);
}
#define kNormalInputGain -11.21334612 /* 20*log10(1.1/4) */
#define kNormalOutputGain 2.278867046 /* 20*log10(1.3/1) */
#define kNormalPeakPowerGain 10 /* Normal Gain due to Peakiness */
void CVUMeter::UpdateLevel(){
float dB, level, left, right;
switch (fChannelIndicator){
case kRightChannel:
case kLeftChannel:
level = fCurrentReading[fChannelIndicator];
break;
default: /* Maximum of two channels */
right = fCurrentReading[kRightChannel];
left = fCurrentReading[kLeftChannel];
if (left > right)
level = left;
else
level = right;
break;
}
if (!useMouseForLevels){
if (fLevelType == kPeakReading)
dB = 20.*log10(level/DSP_MAXIMUM_VALUE);
else {
dB = 10.*log10(level/DSP_MAXIMUM_VALUE/DSP_MAXIMUM_VALUE);
dB += kNormalPeakPowerGain;
}
if (fReferenceType == kAnalogLineReference){
if (fPortType == kInputPort)
dB -= kNormalInputGain;
else
dB -= kNormalOutputGain;
}
dB += *fChannelGainPointer; /* Add in optional Singer gain */
} else {
dB = level;
}
if (dB != fLastReading){
fLastReading = dB;
this->DrawNeedle();
this->CopyToWindow();
}
}
void CVUMeter::RefreshLevel(){
this->DrawNeedle();
this->CopyToWindow();
}
void CVUMeter::Dispose(){
ReleaseDSPVolumeAddress(fPortType, fChannelIndicator, fLevelType);
if (fScaleWorld)
DisposeGWorld(fScaleWorld);
fScaleWorld = 0;
if (fDirtyScaleRegion)
DisposeRgn(fDirtyScaleRegion);
fDirtyScaleRegion = 0;
inherited::Dispose();
}
int CVUMeter::AllMemoryAllocated(){
return fOffScreenWorld && fScaleWorld;
}
/*=================================== CPictureMeter ====================================*/
void CPictureMeter::IVUMeter(enum portNum portType, enum channelNum channelType,
enum levelNum levelType, enum speedNum speedType,
enum referenceNum referenceType){
PicHandle thePicture;
CVUMeter::IVUMeter(portType, channelType, levelType, speedType,
referenceType);
thePicture = GetPicture(ABOUT_BOX_PICT_ID);
fPicture = thePicture;
}
void CPictureMeter::DrawScale(){
GDHandle oldGD;
GWorldPtr oldGW;
GWorldPtr newWorld = 0;
Rect rect;
short wide, high;
OSErr errorCode;
if (!fPicture || !fScaleWorld)
return;
if (!fScaleWorld)
return; /* Should never see this condition...*/
GetGWorld(&oldGW, &oldGD);
LockPixels(fScaleWorld->portPixMap);
rect = (*fPicture)->picFrame;
wide = rect.right - rect.left; /* calculate width and height */
high = rect.bottom - rect.top;
SetRect(&rect, 0, 0, wide,high );
errorCode = NewGWorld(&newWorld, 1, &rect, NIL_POINTER, NIL_POINTER, NO_FLAGS);
if (errorCode == noErr){
LockPixels(newWorld->portPixMap);
SetGWorld(newWorld, NIL_POINTER);
EraseRect(&newWorld->portRect);
DrawPicture(fPicture, &rect);
SetGWorld(fScaleWorld, NIL_POINTER);
RGBBackColor(&rgbBackgroundColor); /* Sort of dirty yellow */
EraseRect(&newWorld->portRect);
CopyBits((BitMap *)&newWorld->portPixMap,
(BitMap *)&fScaleWorld->portPixMap, &rect, &rect, srcOr, 0);
DisposeGWorld(newWorld);
} else {
SetGWorld(fScaleWorld, NIL_POINTER);
RGBBackColor(&rgbBackgroundColor); /* Sort of dirty yellow */
rect = newWorld->portRect;
EraseRect(&rect);
DrawPicture(fPicture, &rect );
}
SetGWorld(oldGW, oldGD);
UnlockPixels(fScaleWorld->portPixMap);
}
void CPictureMeter::SetMeterParms(Rect *sizeRect){
Str255 theText;
long x, y, len;
GetIndString(theText, ABOUT_BOX_PICT_ID, 1);
StringToNum(theText, &x);
GetIndString(theText, ABOUT_BOX_PICT_ID, 2);
StringToNum(theText, &y);
GetIndString(theText, ABOUT_BOX_PICT_ID, 3);
StringToNum(theText, &len);
fScaleLength = len;
SetPt(&fMeterCenter, x, y);
}
/*=================================== CPortWindow ====================================*/
void CPortWindow::IPortWindow(){
fChannel = gPatchChannels;
fFirstMeter = fSecondMeter = 0;
fPortType = gPortType;
fLevelType = gLevelType;
fSpeedType = gSpeedType;
fReferenceType = gReferenceType;
fWindow = 0;
}
void CPortWindow::NewWindow(){
WindowPtr cWindow;
Str255 windowTitle;
if (fChannel == kBothChannel)
cWindow = GetNewCWindow(BASE_RES_ID+1, NIL_POINTER, (WindowPtr)MOVE_TO_FRONT);
else
cWindow = GetNewCWindow(BASE_RES_ID, NIL_POINTER, (WindowPtr)MOVE_TO_FRONT);
if (!cWindow){
DoCautionAlert(kCantAllocateCWindowError);
this->Dispose();
return;
}
if (!IsMemoryAvailable(MemoryNeededForNewWindow(&cWindow->portRect))){
DoCautionAlert(kCantAllocateCWindowError);
this->Dispose();
DisposeWindow(cWindow);
return;
}
SetPort(cWindow);
DrawControls(cWindow);
#ifdef SCROLL_BARS
DrawGrowIcon(cWindow);
#endif
fWindow = cWindow;
GetIndString(windowTitle, METER_LABEL_RESOURCE, portTypes[fPortType].name);
if (windowTitle[0])
SetWTitle(cWindow, windowTitle);
ShowWindow(cWindow);
this->UpdateWindowSize();
if (fFirstMeter)
fFirstMeter->GetExternalGain();
if (fSecondMeter)
fSecondMeter->GetExternalGain();
}
void CPortWindow::UpdateWindowType(){
int destroyVUs = 0;
if (fChannel != gPatchChannels){
if (gPatchChannels == kBothChannel)
SizeWindow(fWindow, 2*kDefaultVUWidth, kDefaultVUHeight, FALSE);
else
SizeWindow(fWindow, kDefaultVUWidth, kDefaultVUHeight, FALSE);
fChannel = gPatchChannels;
destroyVUs = 1;
}
if (fLevelType != gLevelType){
destroyVUs = 1;
fLevelType = gLevelType;
}
if (fPortType != gPortType){
destroyVUs = 1;
fPortType = gPortType;
}
if (fSpeedType != gSpeedType){
destroyVUs = 1;
fSpeedType = gSpeedType;
}
if (fReferenceType != gReferenceType){
destroyVUs = 1;
fReferenceType = gReferenceType;
}
if (destroyVUs != 0){
Str255 windowTitle;
if (fFirstMeter){
fFirstMeter->Dispose();
delete(fFirstMeter);
}
if (fSecondMeter){
fSecondMeter->Dispose();
delete(fSecondMeter);
}
fFirstMeter = fSecondMeter = 0;
SetPort(fWindow);
DrawControls(fWindow);
#ifdef SCROLL_BARS
DrawGrowIcon(fWindow);
#endif
this->UpdateWindowSize();
GetIndString(windowTitle, METER_LABEL_RESOURCE, portTypes[fPortType].name);
if (windowTitle)
SetWTitle(fWindow, windowTitle);
if (fFirstMeter)
fFirstMeter->GetExternalGain();
if (fSecondMeter)
fSecondMeter->GetExternalGain();
}
}
void CPortWindow::UpdateWindowSize(){
Rect screenRect, windowRect;
CWindowPeek myWinPeek;
myWinPeek = (CWindowPeek)fWindow;
screenRect = (*myWinPeek->contRgn)->rgnBBox;
#ifdef SCROLL_BARS
screenRect.right -= SCROLL_BAR_SIZE; /* Actually Grow Bar Control */
screenRect.bottom -= SCROLL_BAR_SIZE;
#endif
windowRect = screenRect;
OffsetRect(&windowRect, -windowRect.left, -windowRect.top);
if (fChannel != kBothChannel){ /* Allocate a single VU Meter */
if (!fFirstMeter){
fFirstMeter = new(CVUMeter);
if (!fFirstMeter){
DoStopAlert(kCantAllocateVUMeterError);
CloseDSPs();
ExitToShell();
}
fFirstMeter->IVUMeter(fPortType, fChannel, fLevelType,
fSpeedType, fReferenceType);
}
fFirstMeter->SetWindowRect(&screenRect, &windowRect);
fFirstMeter->SetWindow(fWindow);
if (!fFirstMeter->AllMemoryAllocated()){
this->Dispose();
return;
}
} else {
int width = screenRect.right - screenRect.left, t;
/* Allocate left VU Meter */
screenRect.right = screenRect.left + width/2;
windowRect.right = width/2;
if (!fFirstMeter){
fFirstMeter = new(CVUMeter);
if (!fFirstMeter){
DoStopAlert(kCantAllocateVUMeterError);
CloseDSPs();
ExitToShell();
}
fFirstMeter->IVUMeter(fPortType, kLeftChannel, fLevelType,
fSpeedType, fReferenceType);
}
fFirstMeter->SetWindowRect(&screenRect, &windowRect);
fFirstMeter->SetWindow(fWindow);
/* Allocate right VU Meter */
windowRect.left = width/2;
windowRect.right = width;
screenRect.right = screenRect.left + width;
screenRect.left = screenRect.left + width/2;
if (!fSecondMeter){
fSecondMeter = new(CVUMeter);
if (!fSecondMeter){
DoStopAlert(kCantAllocateVUMeterError);
CloseDSPs();
ExitToShell();
}
fSecondMeter->IVUMeter(fPortType, kRightChannel, fLevelType,
fSpeedType, fReferenceType);
}
fSecondMeter->SetWindowRect(&screenRect, &windowRect);
fSecondMeter->SetWindow(fWindow);
if (!fSecondMeter->AllMemoryAllocated()){
this->Dispose();
return;
}
}
this->RefreshWindow();
}
void CPortWindow::UpdateLevel(){
if (fFirstMeter)
fFirstMeter->UpdateLevel();
if (fSecondMeter)
fSecondMeter->UpdateLevel();
}
void CPortWindow::RefreshWindow(){
if (fFirstMeter)
fFirstMeter->RefreshLevel();
if (fSecondMeter)
fSecondMeter->RefreshLevel();
}
WindowPtr CPortWindow::GetWindow(){
return fWindow;
}
void CPortWindow::RedrawWindow(){
#ifdef SCROLL_BARS
DrawGrowIcon(fWindow);
#endif
if (fFirstMeter)
fFirstMeter->CopyToWindow();
if (fSecondMeter)
fSecondMeter->CopyToWindow();
}
void CPortWindow::SetUpMenus(){
CheckItem(gPatchMenu, LEFT_ITEM, fChannel == kLeftChannel);
CheckItem(gPatchMenu, RIGHT_ITEM, fChannel == kRightChannel);
CheckItem(gPatchMenu, BOTH_ITEM, fChannel == kBothChannel);
CheckItem(gPatchMenu, MAXIMUM_ITEM, fChannel == kMaxChannel);
CheckItem(gPatchMenu, INPUT_ITEM, fPortType == kInputPort);
CheckItem(gPatchMenu, OUTPUT_ITEM, fPortType == kOutputPort);
CheckItem(gPatchMenu, POWER_ITEM, fLevelType == kPowerReading);
CheckItem(gPatchMenu, PEAK_ITEM, fLevelType == kPeakReading);
CheckItem(gPatchMenu, FAST_ITEM, fSpeedType == kFastSpeed);
CheckItem(gPatchMenu, NORMAL_ITEM, fSpeedType == kNormalSpeed);
CheckItem(gPatchMenu, FULLSCALE_ITEM, fReferenceType == kFullScaleReference);
CheckItem(gPatchMenu, ANALOGLINE_ITEM, fReferenceType == kAnalogLineReference);
if (gCurrentWindow)
EnableItem(gFileMenu, CLOSE_ITEM);
else
DisableItem(gFileMenu, CLOSE_ITEM);
}
void CPortWindow::Update(){
if (fFirstMeter)
fFirstMeter->Update();
if (fSecondMeter)
fSecondMeter->Update();
}
void CPortWindow::Dispose(){
if (fFirstMeter){
fFirstMeter->Dispose();
delete(fFirstMeter);
}
if (fSecondMeter){
fSecondMeter->Dispose();
delete(fSecondMeter);
}
fFirstMeter = fSecondMeter = 0;
if (fWindow)
DisposeWindow(fWindow);
fWindow = 0;
}
int CPortWindow::AllMemoryAllocated(){
return fFirstMeter && fWindow;
}
/************************************** Entry Library ************************/
#define MAX_ENTRIES 100
struct objectEntry {
long key, value;
} objectList[MAX_ENTRIES];
Boolean AddEntry(key, value)
long key, value;
{
int i;
for (i=0;i<MAX_ENTRIES;i++){
if (objectList[i].key == 0){
objectList[i].key = key;
objectList[i].value = value;
return true;
}
}
return false;
}
long FindKey(value)
long value;
{
int i;
for (i=0;i<MAX_ENTRIES;i++){
if (objectList[i].value == value)
return objectList[i].key;
}
return 0;
}
long RemoveEntry(key)
long key;
{
int i;
for (i=0;i<MAX_ENTRIES;i++){
if (objectList[i].key == key){
objectList[i].key = 0;
return;
}
}
}
static int entryNumber = 0;
long GetNextKey(){
int i = MAX_ENTRIES;
while (i-- > 0){
if (objectList[entryNumber].key)
return objectList[entryNumber++].key;
else
entryNumber++;
if (entryNumber >= MAX_ENTRIES)
entryNumber = 0;
}
return 0;
}
/****************************************** main *********************************/
#define kCheckGainMask (0x3f) /* Must be (power of two) minus 1 */
main(){
KeyMap theKeys;
Boolean Is32Bit();
int eventCount = 0, i;
MaxApplZone();
for (i = 0; i<20; i++) /* Lots of handles */
MoreMasters();
ToolBoxInit();
MenuBarInit();
GetKeys(theKeys);
if (theKeys[1] &0x04){
useMouseForLevels = 1;
SysBeep(10);
}
if (!Is32Bit()){
DoStopAlert(kNeed32BitQuickDrawError);
} else {
extern void MakeNewWindow();
gPatchChannels = kMaxChannel;
MakeNewWindow();
while (!gDone){
Point theLoc;
CPortWindow *aPortWindow;
if (useMouseForLevels){
GetMouse(&theLoc);
gMouseLevel[0] = theLoc.h;
gMouseLevel[1] = theLoc.v;
}
aPortWindow = (CPortWindow *)GetNextKey();
if (aPortWindow)
aPortWindow->UpdateLevel();
HandleEvent();
if (!useMouseForLevels && (eventCount++ & kCheckGainMask) == 0)
GetDSPGains();
}
CloseDSPs();
}
}
#define kMemCushion (80*1024L) /* How much needed to be safe. */
IsMemoryAvailable(long memoryRequest){
long spaceAvailable;
spaceAvailable = MaxBlock();
if (spaceAvailable > kMemCushion+memoryRequest)
return 1;
return 0;
}
#define kTrialWindowSize 256
#define kBytesPerPixel 5/2
long MemoryNeededForNewWindow(Rect *screenRect){
QDErr errorCode;
GDHandle gDevice;
long bytesNeeded;
gDevice = GetMaxDevice(screenRect);
bytesNeeded = (*((*gDevice)->gdPMap))->pixelSize;
bytesNeeded *= (long)(screenRect->right - screenRect->left) *
(long)(screenRect->bottom - screenRect->top) /
8; /* Bits per Byte */
return 2 * bytesNeeded;
}
void MakeNewWindow(){
CPortWindow *aPortWindow;
if (!IsMemoryAvailable(0)){
DoCautionAlert(kNeedMoreMemoryError);
return;
}
if (AddEntry(0,0)){
aPortWindow = new(CPortWindow);
if (!aPortWindow){
DoCautionAlert(kCantAllocateCPortWindowError);
return;
}
aPortWindow->IPortWindow();
aPortWindow->NewWindow();
if (aPortWindow->AllMemoryAllocated()){
AddEntry((long)aPortWindow, (long)aPortWindow->GetWindow());
}
} else {
DoCautionAlert(kCantAllocateMoreWindowsError);
}
}
/****************************************** ToolBoxInit *********************************/
Rect gSizeRect;
ToolBoxInit(){
InitGraf(&thePort);
InitFonts();
FlushEvents(everyEvent, REMOVE_ALL_EVENTS);
InitWindows();
InitMenus();
TEInit();
InitDialogs(NIL_POINTER);
InitCursor();
gSizeRect.top = MIN_WINDOW_HEIGHT;
gSizeRect.left = MIN_WINDOW_WIDTH;
gSizeRect.bottom = screenBits.bounds.bottom - screenBits.bounds.top;
gSizeRect.right = screenBits.bounds.right - screenBits.bounds.left;
}
/****************************************** Is32Bit *********************************/
#define QD32TRAP 0xAB03
#define UNIMPL_TRAP 0xA89F
Boolean Is32Bit(){
SysEnvRec mySE;
SysEnvirons(2,&mySE);
if (!mySE.hasColorQD)
return FALSE;
return (NGetTrapAddress(QD32TRAP, ToolTrap) !=
NGetTrapAddress(UNIMPL_TRAP, ToolTrap));
}
/****************************************** DoAlert *********************************/
void DoCautionAlert(short messageNumber)
{
Str255 string;
GetIndString(string, ALERT_STRING_RESOURCE, messageNumber);
ParamText(string, NIL_STRING, NIL_STRING, NIL_STRING);
CautionAlert(BASE_RES_ID, NIL_POINTER);
}
void DoStopAlert(short messageNumber)
{
Str255 string;
GetIndString(string, ALERT_STRING_RESOURCE, messageNumber);
ParamText(string, NIL_STRING, NIL_STRING, NIL_STRING);
StopAlert(BASE_RES_ID, NIL_POINTER);
}
void ShowValue(short messageNumber, long val){
Str255 messageString, valString, formatString;
GetIndString(messageString, ALERT_STRING_RESOURCE, messageNumber);
p2cstr(messageString);
GetIndString(formatString, ALERT_STRING_RESOURCE, kShowValueError);
p2cstr(formatString);
sprintf((char *)valString, (char *)formatString, (char *)messageString, val);
c2pstr((char *)valString);
ParamText(valString, NIL_STRING, NIL_STRING, NIL_STRING);
CautionAlert(BASE_RES_ID, NIL_POINTER);
}
/****************************************** MenuBarInit *********************************/
MenuBarInit(){
Handle myMenuBar;
long size;
int *ip;
myMenuBar = GetNewMBar(BASE_RES_ID);
if (!myMenuBar){
DoStopAlert(kCantFindMenuBarError);
CloseDSPs();
ExitToShell();
}
SetMenuBar(myMenuBar);
gAppleMenu = GetMHandle(APPLE_MENU);
if (!gAppleMenu){
DoStopAlert(kCantFindAppleMenuError);
CloseDSPs();
ExitToShell();
}
gFileMenu = GetMHandle(FILE_MENU);
if (!gAppleMenu){
DoStopAlert(kCantFindFileMenuError);
CloseDSPs();
ExitToShell();
}
gPatchMenu = GetMHandle(PATCH_MENU);
if (!gPatchMenu){
DoStopAlert(kCantFindPatchMenuError);
CloseDSPs();
ExitToShell();
}
AddResMenu(gAppleMenu, 'DRVR');
DrawMenuBar();
}
void SetUpMenus(){
CPortWindow *thePortWindow;
if (gCurrentWindow){
thePortWindow = (CPortWindow *)FindKey((long)gCurrentWindow);
if (!thePortWindow)
DoCautionAlert(kMenuSetupError);
else {
thePortWindow->SetUpMenus();
}
return;
}
CheckItem(gPatchMenu, LEFT_ITEM, gPatchChannels == kLeftChannel);
CheckItem(gPatchMenu, RIGHT_ITEM, gPatchChannels == kRightChannel);
CheckItem(gPatchMenu, BOTH_ITEM, gPatchChannels == kBothChannel);
CheckItem(gPatchMenu, MAXIMUM_ITEM, gPatchChannels == kMaxChannel);
CheckItem(gPatchMenu, INPUT_ITEM, gPortType == kInputPort);
CheckItem(gPatchMenu, OUTPUT_ITEM, gPortType == kOutputPort);
CheckItem(gPatchMenu, POWER_ITEM, gLevelType == kPowerReading);
CheckItem(gPatchMenu, PEAK_ITEM, gLevelType == kPeakReading);
CheckItem(gPatchMenu, FULLSCALE_ITEM, gReferenceType == kFullScaleReference);
CheckItem(gPatchMenu, ANALOGLINE_ITEM, gReferenceType == kAnalogLineReference);
if (gCurrentWindow)
EnableItem(gFileMenu, CLOSE_ITEM);
else
DisableItem(gFileMenu, CLOSE_ITEM);
}
/****************************************** HandleEvent *********************************/
EventRecord gTheEvent;
HandleEvent(){
char theChar;
CPortWindow *thePortWindow;
WaitNextEvent(everyEvent, &gTheEvent, MIN_SLEEP, NIL_MOUSE_REGION);
switch(gTheEvent.what){
case nullEvent:
break;
case mouseDown:
HandleMouseDown();
break;
case keyDown:
case autoKey:
theChar = gTheEvent.message & charCodeMask;
if ((gTheEvent.modifiers & cmdKey) != 0)
HandleMenuChoice( MenuKey(theChar));
break;
case updateEvt:
BeginUpdate((WindowPtr)gTheEvent.message);
thePortWindow = (CPortWindow *)FindKey((long)gTheEvent.message);
if (thePortWindow){
thePortWindow->Update();
thePortWindow->RedrawWindow();
} else {
DoCautionAlert(kUpdateEventError);
}
EndUpdate((WindowPtr)gTheEvent.message);
break;
case activateEvt:
#ifdef SCROLL_BARS
DrawGrowIcon((WindowPtr)gTheEvent.message);
#endif
gCurrentWindow = (WindowPtr)gTheEvent.message;
break;
}
}
HandleMouseDown(){
WindowPtr whichWindow;
short int thePart;
long int menuChoice, windSize;
CPortWindow *thePortWindow;
thePart = FindWindow(gTheEvent.where, &whichWindow);
switch (thePart){
case inMenuBar:
SetUpMenus();
menuChoice = MenuSelect(gTheEvent.where);
HandleMenuChoice(menuChoice);
break;
case inSysWindow:
SystemClick(&gTheEvent, whichWindow);
break;
case inDrag:
DragWindow(whichWindow, gTheEvent.where, &screenBits.bounds);
thePortWindow = (CPortWindow *)FindKey((long)whichWindow);
if (!thePortWindow)
DoCautionAlert(kInDragError);
else
thePortWindow->UpdateWindowSize();
break;
case inContent:
SelectWindow(whichWindow);
break;
case inGoAway:
thePortWindow = (CPortWindow *)FindKey((long)whichWindow);
if (!thePortWindow)
DoCautionAlert(kGoAwayError);
else {
RemoveEntry((long)thePortWindow);
thePortWindow->Dispose();
delete(thePortWindow);
}
gCurrentWindow = 0; /* If somebody else is active
* then they'll get an Activate
*/
break;
#ifdef SCROLL_BARS
case inGrow:
windSize = GrowWindow(whichWindow, gTheEvent.where, &gSizeRect);
if (windSize != 0){
GrafPtr oldPort;
GetPort(&oldPort);
SetPort(whichWindow);
EraseRect(&whichWindow->portRect);
SizeWindow(whichWindow, LoWord(windSize), HiWord(windSize), NORMAL_UPDATES);
InvalRect(&whichWindow->portRect);
SetPort(oldPort);
}
thePortWindow = (CPortWindow *)FindKey((long)whichWindow);
if (!thePortWindow)
DoCautionAlert(kInGrowError);
else {
thePortWindow->UpdateWindowSize();
if (!thePortWindow->AllMemoryAllocated()){
RemoveEntry((long)thePortWindow);
thePortWindow->Dispose();
delete(thePortWindow);
}
}
break;
case inZoomIn:
case inZoomOut:
if (TrackBox(whichWindow, gTheEvent.where, thePart)){
GrafPtr oldPort;
GetPort(&oldPort);
SetPort(whichWindow);
EraseRect(&whichWindow->portRect);
ZoomWindow(whichWindow, thePart, LEAVE_WHERE_IT_IS);
InvalRect(&whichWindow->portRect);
SetPort(oldPort);
}
thePortWindow = (CPortWindow *)FindKey((long)whichWindow);
if (!thePortWindow)
DoCautionAlert(kInZoomError);
else {
thePortWindow->UpdateWindowSize();
if (!thePortWindow->AllMemoryAllocated()){
RemoveEntry((long)thePortWindow);
thePortWindow->Dispose();
delete(thePortWindow);
}
}
break;
#endif /* SCROLL_BARS */
}
}
HandleMenuChoice(menuChoice)
long int menuChoice;
{
int theMenu;
int theItem;
if (menuChoice != 0){
theMenu = HiWord(menuChoice);
theItem = LoWord(menuChoice);
switch(theMenu){
case APPLE_MENU:
HandleAppleChoice(theItem);
break;
case FILE_MENU:
HandleFileChoice(theItem);
break;
case PATCH_MENU:
HandlePatchChoice(theItem);
break;
default:
/* ShowValue(kMenuChoiceError, menuChoice); */
break;
}
HiliteMenu(0);
}
}
DisplayAboutBox(){
Rect r;
PicHandle thePicture;
short wide, high;
WindowPtr wind;
CPictureMeter *pictureMeter;
short oldUseMouse = useMouseForLevels, waitForMouse = 1;
float v = 0, eps=.98;
Str255 titleString;
long size;
thePicture = GetPicture(ABOUT_BOX_PICT_ID);
r = (*thePicture)->picFrame;
wide = r.right - r.left; /* calculate width and height */
high = r.bottom - r.top;
SetRect(&r, 0, 0, wide,high );
OffsetRect(&r, 100, 100);
if (!IsMemoryAvailable(MemoryNeededForNewWindow(&r))){
DoCautionAlert(kCantCreatePictureWindowError);
return;
}
GetIndString(titleString, ALERT_STRING_RESOURCE, kAboutVUMetersString);
wind = NewCWindow(nil, &r, titleString, TRUE, dBoxProc, (WindowPtr)-1,
FALSE, 0);
if (!wind){
DoCautionAlert(kCantAllocateVUPictureError);
return;
}
useMouseForLevels = 1;
SetPort(wind);
DrawControls(wind);
ShowWindow(wind);
pictureMeter = new(CPictureMeter);
if (!pictureMeter){
DoCautionAlert(kCantAllocateVUPictureError);
return;
}
pictureMeter->IVUMeter(0, 0, 0, 0, 0); /* Don't care about meter types */
OffsetRect(&r, -r.left, -r.top);
pictureMeter->SetWindowRect(&r, &r); /* Place PictureMeter into window */
pictureMeter->SetWindow(wind);
while (waitForMouse){
v = eps*v + (1-eps)*((Random() & 0x7f)-65);
gMouseLevel[0] = v;
gMouseLevel[1] = v; /* Set new random level */
pictureMeter->UpdateLevel(); /* Redraw the meter's needle */
WaitNextEvent(everyEvent, &gTheEvent, MIN_SLEEP, NIL_MOUSE_REGION);
switch(gTheEvent.what){
case mouseDown:
waitForMouse = 0; /* Wait for a mouse click */
break;
default:
break;
}
}
pictureMeter->Dispose(); /* Cleanup things */
DisposeWindow(wind);
useMouseForLevels = oldUseMouse; /* Go back to normal operation */
}
HandleAppleChoice(theItem)
int theItem;
{
Str255 accName;
int accNumber;
short itemNumber;
switch (theItem){
case ABOUT_ITEM:
DisplayAboutBox();
break;
default:
GetItem(gAppleMenu, theItem, accName);
accNumber = OpenDeskAcc(accName);
break;
}
}
HandleFileChoice(theItem)
int theItem;
{
CPortWindow *thePortWindow;
switch (theItem){
case NEW_ITEM:
MakeNewWindow();
break;
case CLOSE_ITEM:
if (gCurrentWindow){
thePortWindow = (CPortWindow *)FindKey((long)gCurrentWindow);
if (!thePortWindow)
DoCautionAlert(kCloseMenuError);
else {
RemoveEntry((long)thePortWindow);
thePortWindow->Dispose();
delete(thePortWindow);
}
gCurrentWindow = 0;
}
break;
case QUIT_ITEM:
gDone = true;
break;
}
}
HandlePatchChoice(theItem)
int theItem;
{
CPortWindow *thePortWindow;
switch (theItem){
case LEFT_ITEM:
gPatchChannels = kLeftChannel;
break;
case RIGHT_ITEM:
gPatchChannels = kRightChannel;
break;
case MAXIMUM_ITEM:
gPatchChannels = kMaxChannel;
break;
case BOTH_ITEM:
gPatchChannels = kBothChannel;
break;
case INPUT_ITEM:
gPortType = kInputPort;
break;
case OUTPUT_ITEM:
gPortType = kOutputPort;
break;
case PEAK_ITEM:
gLevelType = kPeakReading;
break;
case POWER_ITEM:
gLevelType = kPowerReading;
break;
case FAST_ITEM:
gSpeedType = kFastSpeed;
break;
case NORMAL_ITEM:
gSpeedType = kNormalSpeed;
break;
case FULLSCALE_ITEM:
gReferenceType = kFullScaleReference;
break;
case ANALOGLINE_ITEM:
gReferenceType = kAnalogLineReference;
break;
default:
return;
}
if (gCurrentWindow){
thePortWindow = (CPortWindow *)FindKey((long)gCurrentWindow);
if (!thePortWindow)
DoCautionAlert(kPatchMenuError);
else {
thePortWindow->UpdateWindowType();
if (!thePortWindow->AllMemoryAllocated()){
RemoveEntry((long)thePortWindow);
thePortWindow->Dispose();
delete(thePortWindow);
}
}
}
}