Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
SndEqualizer.c
////////// |
// |
// File: SndEqualizer.c |
// |
// Contains: Sample code for displaying a graphic equalizer (a la QuickTime Player). |
// |
// Written by: Tim Monroe |
// |
// Copyright: © 2000 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <2> 04/07/00 rtm added functions to shown equalizer display with sound files |
// <1> 03/24/00 rtm first file |
// |
// This file contains functions that create and manage a dialog window containing a graphic |
// equalizer display, similar to the one in the "LCD panel" in QuickTime Player. Really there |
// are just two key functions that you use to make this happen, MediaSetSoundEqualizerBands |
// and MediaGetSoundEqualizerBandLevels. |
// |
// For displaying a graphic equalizer while a sound resource is playing, you instead use the |
// SndSetInfo and SndGetInfo functions, with the siEQSpectrumBands, siEQSpectrumOnOff, and |
// siEQSpectrumLevels selectors. |
// |
////////// |
#include "SndEqualizer.h" |
////////// |
// |
// global variables |
// |
////////// |
UInt8 gLevels[kSndEqNumBands]; |
DialogPtr gSndEqDialog = NULL; |
Boolean gSndEqDialogIsVis = false; |
UserItemUPP gSndEqUserItemProcUPP = NULL; // UPP to our custom dialog user item procedure |
RGBColor gDGray = {0x7777, 0x7777, 0x7777}; |
RGBColor gBlack = {0x0000, 0x0000, 0x0000}; |
//RGBColor gMauve = {0x9999, 0xcccc, 0xffff}; |
RGBColor gMauve = {0xffff, 0x6666, 0xffff}; |
// globals variables for playing sound resources |
SndChannelPtr gSndEqSndChannelPtr = NULL; |
SndListHandle gSndEqResourceHandle = NULL; |
short gSndEqResourceFile = -1; |
Boolean gSndEqResourcePlaying = false; |
Boolean gSndEqResourceDone = false; |
SndCallBackUPP gSndCallBackProc = NULL; // UPP to our sound callback procedure |
////////// |
// |
// SndEq_Init |
// Do any initialization required for displaying the sound equalizer. |
// |
////////// |
OSErr SndEq_Init (void) |
{ |
gSndEqUserItemProcUPP = NewUserItemUPP(SndEq_UserItemProcedure); |
SndEq_InitSoundResource(); |
return(SndEq_ShowDialog()); |
} |
////////// |
// |
// SndEq_Stop |
// Do any clean-up required for hiding the sound equalizer. |
// |
////////// |
OSErr SndEq_Stop (void) |
{ |
DisposeUserItemUPP(gSndEqUserItemProcUPP); |
SndEq_StopSoundResource(); |
return(SndEq_HideDialog()); |
} |
////////// |
// |
// SndEq_InitWindowData |
// Do any window-specific initialization for displaying the sound equalizer. |
// |
////////// |
Handle SndEq_InitWindowData (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
Track myTrack = NULL; |
MediaHandler myHandler = NULL; |
UnsignedFixed myBands[kSndEqNumBands]; |
MediaEQSpectrumBandsRecord myInfo; |
myAppData = (ApplicationDataHdl)NewHandleClear(sizeof(ApplicationDataRecord)); |
if (myAppData != NULL) { |
// find the sound media handler |
myTrack = GetMovieIndTrackType((**theWindowObject).fMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly); |
if (myTrack != NULL) |
myHandler = GetMediaHandler(GetTrackMedia(myTrack)); |
// remember the sound media handler |
(**myAppData).fSoundMediaHandler = myHandler; |
// set the frequencies for the bands |
myBands[0] = kBandFreq0; |
myBands[1] = kBandFreq1; |
myBands[2] = kBandFreq2; |
myBands[3] = kBandFreq3; |
myBands[4] = kBandFreq4; |
myBands[5] = kBandFreq5; |
myBands[6] = kBandFreq6; |
myBands[7] = kBandFreq7; |
myInfo.count = kSndEqNumBands; |
myInfo.frequency = myBands; |
MediaSetSoundEqualizerBands(myHandler, &myInfo); |
} |
return((Handle)myAppData); |
} |
////////// |
// |
// SndEq_DumpWindowData |
// Do any window-specific initialization for displaying the sound equalizer. |
// |
////////// |
OSErr SndEq_DumpWindowData (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
OSErr myErr = noErr; |
myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject); |
if (myAppData == NULL) |
goto bail; |
DisposeHandle((Handle)myAppData); |
bail: |
return(myErr); |
} |
////////// |
// |
// SndEq_ShowDialog |
// Show the equalizer display dialog box. |
// |
////////// |
OSErr SndEq_ShowDialog (void) |
{ |
short myItemKind; |
Handle myItemHandle = NULL; |
Rect myItemRect; |
OSErr myErr = noErr; |
if (gSndEqDialog == NULL) { |
gSndEqDialog = GetNewDialog(kSndEqResID, NULL, (WindowPtr)-1L); |
if (gSndEqDialog == NULL) { |
myErr = ResError(); |
goto bail; |
} |
// set the user item drawing procedure |
GetDialogItem(gSndEqDialog, kSndEqUserItemIndex, &myItemKind, &myItemHandle, &myItemRect); |
SetDialogItem(gSndEqDialog, kSndEqUserItemIndex, myItemKind, (Handle)gSndEqUserItemProcUPP, &myItemRect); |
} |
MacShowWindow(GetDialogWindow(gSndEqDialog)); |
gSndEqDialogIsVis = true; |
SndEq_UserItemProcedure(gSndEqDialog, kSndEqUserItemIndex); |
bail: |
return(myErr); |
} |
////////// |
// |
// SndEq_HideDialog |
// Hide the equalizer display dialog box. |
// |
////////// |
OSErr SndEq_HideDialog (void) |
{ |
if (gSndEqDialog != NULL) { |
HideWindow(GetDialogWindow(gSndEqDialog)); |
gSndEqDialogIsVis = false; |
} |
return(noErr); |
} |
////////// |
// |
// SndEq_ToggleDialog |
// Toggle the visibility of the equalizer display dialog box. |
// |
////////// |
OSErr SndEq_ToggleDialog (void) |
{ |
if (gSndEqDialogIsVis) |
SndEq_HideDialog(); |
else |
SndEq_ShowDialog(); |
return(noErr); |
} |
////////// |
// |
// SndEq_UpdateMovieLevels |
// Update the equalizer display for a QuickTime movie. |
// |
////////// |
OSErr SndEq_UpdateMovieLevels (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
OSErr myErr = paramErr; |
myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject); |
if (myAppData == NULL) |
goto bail; |
myErr = MediaGetSoundEqualizerBandLevels((**myAppData).fSoundMediaHandler, gLevels); |
if (myErr != noErr) |
goto bail; |
SndEq_UserItemProcedure(gSndEqDialog, kSndEqUserItemIndex); |
bail: |
return(myErr); |
} |
////////// |
// |
// SndEq_UserItemProcedure |
// A user-item procedure to draw the sound levels. |
// |
////////// |
PASCAL_RTN void SndEq_UserItemProcedure (DialogPtr theDialog, short theItem) |
{ |
short myItemKind; |
Handle myItemHandle = NULL; |
Rect myItemRect; |
Rect myTempRect; |
GrafPtr mySavedPort; |
short myWidth; |
short myHeight; |
static UInt8 myPrevLevels[kSndEqNumBands]; |
static unsigned long myTicks = 0; |
short myCount; |
OSErr myErr = noErr; |
GetPort(&mySavedPort); |
MacSetPort(GetDialogPort(gSndEqDialog)); |
if (theItem != kSndEqUserItemIndex) |
goto bail; |
// if we updated within the last kSndEqTickThreshold ticks, don't bother to do it now |
if (TickCount() - myTicks < kSndEqTickThreshold) |
goto bail; |
myTicks = TickCount(); |
// get the rectangle surrounding the user item |
GetDialogItem(theDialog, kSndEqUserItemIndex, &myItemKind, &myItemHandle, &myItemRect); |
myWidth = myItemRect.right - myItemRect.left; |
myHeight = myItemRect.bottom - myItemRect.top; |
// draw a frame around the picture |
MoveTo(myItemRect.left, myItemRect.top); |
MacLineTo(myItemRect.right, myItemRect.top); |
MoveTo(myItemRect.left, myItemRect.bottom); |
MacLineTo(myItemRect.right, myItemRect.bottom); |
MoveTo(myItemRect.left, myItemRect.bottom); |
MacLineTo(myItemRect.left, myItemRect.top); |
for (myCount = 0; myCount < kSndEqNumBands; myCount++) { |
MoveTo(myItemRect.left + ((myCount + 1) * (myWidth / kSndEqNumBands)), myItemRect.bottom); |
MacLineTo(myItemRect.left + ((myCount + 1) * (myWidth / kSndEqNumBands)), myItemRect.top); |
} |
for (myCount = 0; myCount < kSndEqNumBands; myCount++) { |
if (myPrevLevels[myCount] >= gLevels[myCount]) { |
MacSetRect(&myTempRect, |
myItemRect.left + (myCount * (myWidth / kSndEqNumBands)) + 2, |
myItemRect.top + 1, |
myItemRect.left + ((myCount + 1) * (myWidth / kSndEqNumBands)) - 1, |
myItemRect.bottom - ((gLevels[myCount] * myHeight) / 256)); |
EraseRect(&myTempRect); |
} |
RGBForeColor(&gDGray); // gMauve |
MacSetRect(&myTempRect, |
myItemRect.left + (myCount * (myWidth / kSndEqNumBands)) + 2, |
myItemRect.bottom - ((gLevels[myCount] * myHeight) / 256), |
myItemRect.left + ((myCount + 1) * (myWidth / kSndEqNumBands)) - 1, |
myItemRect.bottom - 1); |
PaintRect(&myTempRect); |
RGBForeColor(&gBlack); |
myPrevLevels[myCount] = gLevels[myCount]; |
} |
bail: |
MacSetPort(mySavedPort); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Sound resource file functions. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// SndEq_InitSoundResource |
// Do any initialization required for playing sound resource files. |
// |
////////// |
OSErr SndEq_InitSoundResource (void) |
{ |
UnsignedFixed myBands[kSndEqNumBands]; |
MediaEQSpectrumBandsRecord myInfo; |
OSErr myErr = memFullErr; |
gSndEqResourcePlaying = false; |
gSndCallBackProc = NewSndCallBackUPP(SndEq_CallbackProc); |
// create storage for a new sound channel |
gSndEqSndChannelPtr = (SndChannelPtr)NewPtrClear(sizeof(SndChannel)); |
if (gSndEqSndChannelPtr == NULL) |
goto bail; |
// set the number of commands in the sound channel queue |
gSndEqSndChannelPtr->qLength = kSndEqNumCmdsInQueue; |
// create the sound channel |
myErr = SndNewChannel(&gSndEqSndChannelPtr, sampledSynth, initMono, gSndCallBackProc); |
if (myErr != noErr) { |
DisposePtr((Ptr)gSndEqSndChannelPtr); |
gSndEqSndChannelPtr = NULL; |
goto bail; |
} |
// set the frequencies for the bands |
myBands[0] = kBandFreq0; |
myBands[1] = kBandFreq1; |
myBands[2] = kBandFreq2; |
myBands[3] = kBandFreq3; |
myBands[4] = kBandFreq4; |
myBands[5] = kBandFreq5; |
myBands[6] = kBandFreq6; |
myBands[7] = kBandFreq7; |
myInfo.count = kSndEqNumBands; |
myInfo.frequency = myBands; |
// configure the equalizer display |
myErr = SndSetInfo(gSndEqSndChannelPtr, siEQSpectrumOnOff, (void *)true); |
if (myErr != noErr) |
goto bail; |
myErr = SndSetInfo(gSndEqSndChannelPtr, siEQSpectrumBands, &myInfo); |
bail: |
return(myErr); |
} |
////////// |
// |
// SndEq_StopSoundResource |
// Do any shut-down required after playing sound resource files. |
// |
////////// |
OSErr SndEq_StopSoundResource (void) |
{ |
if (gSndCallBackProc != NULL) |
DisposeSndCallBackUPP(gSndCallBackProc); |
if (gSndEqSndChannelPtr != NULL) |
DisposePtr((Ptr)gSndEqSndChannelPtr); |
return(noErr); |
} |
////////// |
// |
// SndEq_OpenSoundFile |
// Prompt the user to select a file of type 'sfil' and get the (single) sound resource from it. |
// |
////////// |
SndListHandle SndEq_OpenSoundFile (void) |
{ |
OSType myTypeList[] = {kQTFileTypeSystemSevenSound}; |
FSSpec myFSSpec; |
OSErr myErr = noErr; |
SndListHandle myResource = gSndEqResourceHandle; |
// elicit a new sound file from the user |
myErr = QTFrame_GetOneFileWithPreview(1, (QTFrameTypeListPtr)myTypeList, &myFSSpec, NULL); |
if (myErr == noErr) { |
// close any sound file that's currently open |
SndEq_CloseSoundFile(); |
gSndEqResourceFile = FSpOpenResFile(&myFSSpec, fsRdPerm); |
if (gSndEqResourceFile != -1) { |
myResource = (SndListHandle)Get1IndResource(soundListRsrc, 1); |
} |
} |
return(myResource); |
} |
////////// |
// |
// SndEq_CloseSoundFile |
// Close the open file of type 'sfil'. |
// |
////////// |
void SndEq_CloseSoundFile (void) |
{ |
if (gSndEqResourceHandle != NULL) { |
ReleaseResource((Handle)gSndEqResourceHandle); |
gSndEqResourceHandle = NULL; |
} |
if (gSndEqResourceFile != -1) { |
CloseResFile(gSndEqResourceFile); |
gSndEqResourceFile = -1; |
} |
} |
////////// |
// |
// SndEq_PlaySoundResource |
// Play the specified sound resource. |
// |
////////// |
void SndEq_PlaySoundResource (SndListHandle theSndResource) |
{ |
SndCommand myCommand; |
gSndEqResourcePlaying = true; |
// play the sound asynchronously |
SndPlay(gSndEqSndChannelPtr, theSndResource, true); |
// install a callback command that is executed when the sound is finished playing |
myCommand.cmd = callBackCmd; |
myCommand.param1 = 0; |
myCommand.param2 = 0; |
SndDoCommand(gSndEqSndChannelPtr, &myCommand, false); |
} |
////////// |
// |
// SndEq_UpdateResourceLevels |
// Update the equalizer display for a sound resource. |
// |
////////// |
OSErr SndEq_UpdateResourceLevels (void) |
{ |
unsigned long myTicks; // for Delay |
OSErr myErr = noErr; |
if (gSndEqResourceDone) { |
// zero out the equalizer display |
gLevels[0] = 0; |
gLevels[1] = 0; |
gLevels[2] = 0; |
gLevels[3] = 0; |
gLevels[4] = 0; |
gLevels[5] = 0; |
gLevels[6] = 0; |
gLevels[7] = 0; |
// wait just a bit, to ensure that the display redrawing is triggered |
Delay(kSndEqTickThreshold, &myTicks); |
SndEq_UserItemProcedure(gSndEqDialog, kSndEqUserItemIndex); |
gSndEqResourceDone = false; |
goto bail; |
} |
if (!gSndEqResourcePlaying) |
goto bail; |
if (gSndEqSndChannelPtr != NULL) { |
myErr = SndGetInfo(gSndEqSndChannelPtr, siEQSpectrumLevels, gLevels); |
if (myErr != noErr) |
goto bail; |
SndEq_UserItemProcedure(gSndEqDialog, kSndEqUserItemIndex); |
} |
bail: |
return(myErr); |
} |
////////// |
// |
// SndEq_CallbackProc |
// Handle callback messages. |
// |
////////// |
PASCAL_RTN void SndEq_CallbackProc (SndChannelPtr theChannel, SndCommand *theCommand) |
{ |
#pragma unused(theChannel, theCommand) |
// in this application, a callback message always means that the sound is finished playing, |
// so we simply set our global flag to indicate that fact |
gSndEqResourcePlaying = false; |
gSndEqResourceDone = true; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14