1/*********************************************************************************** 2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. 3 4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), 5 Jerremy Koot (jkoot@snes9x.com) 6 7 (c) Copyright 2002 - 2004 Matthew Kendora 8 9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) 10 11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) 12 13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) 14 15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), 16 Kris Bleakley (codeviolation@hotmail.com) 17 18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), 19 Nach (n-a-c-h@users.sourceforge.net), 20 21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) 22 23 (c) Copyright 2006 - 2007 nitsuja 24 25 (c) Copyright 2009 - 2016 BearOso, 26 OV2 27 28 29 BS-X C emulator code 30 (c) Copyright 2005 - 2006 Dreamer Nom, 31 zones 32 33 C4 x86 assembler and some C emulation code 34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), 35 Nach, 36 zsKnight (zsknight@zsnes.com) 37 38 C4 C++ code 39 (c) Copyright 2003 - 2006 Brad Jorsch, 40 Nach 41 42 DSP-1 emulator code 43 (c) Copyright 1998 - 2006 _Demo_, 44 Andreas Naive (andreasnaive@gmail.com), 45 Gary Henderson, 46 Ivar (ivar@snes9x.com), 47 John Weidman, 48 Kris Bleakley, 49 Matthew Kendora, 50 Nach, 51 neviksti (neviksti@hotmail.com) 52 53 DSP-2 emulator code 54 (c) Copyright 2003 John Weidman, 55 Kris Bleakley, 56 Lord Nightmare (lord_nightmare@users.sourceforge.net), 57 Matthew Kendora, 58 neviksti 59 60 DSP-3 emulator code 61 (c) Copyright 2003 - 2006 John Weidman, 62 Kris Bleakley, 63 Lancer, 64 z80 gaiden 65 66 DSP-4 emulator code 67 (c) Copyright 2004 - 2006 Dreamer Nom, 68 John Weidman, 69 Kris Bleakley, 70 Nach, 71 z80 gaiden 72 73 OBC1 emulator code 74 (c) Copyright 2001 - 2004 zsKnight, 75 pagefault (pagefault@zsnes.com), 76 Kris Bleakley 77 Ported from x86 assembler to C by sanmaiwashi 78 79 SPC7110 and RTC C++ emulator code used in 1.39-1.51 80 (c) Copyright 2002 Matthew Kendora with research by 81 zsKnight, 82 John Weidman, 83 Dark Force 84 85 SPC7110 and RTC C++ emulator code used in 1.52+ 86 (c) Copyright 2009 byuu, 87 neviksti 88 89 S-DD1 C emulator code 90 (c) Copyright 2003 Brad Jorsch with research by 91 Andreas Naive, 92 John Weidman 93 94 S-RTC C emulator code 95 (c) Copyright 2001 - 2006 byuu, 96 John Weidman 97 98 ST010 C++ emulator code 99 (c) Copyright 2003 Feather, 100 John Weidman, 101 Kris Bleakley, 102 Matthew Kendora 103 104 Super FX x86 assembler emulator code 105 (c) Copyright 1998 - 2003 _Demo_, 106 pagefault, 107 zsKnight 108 109 Super FX C emulator code 110 (c) Copyright 1997 - 1999 Ivar, 111 Gary Henderson, 112 John Weidman 113 114 Sound emulator code used in 1.5-1.51 115 (c) Copyright 1998 - 2003 Brad Martin 116 (c) Copyright 1998 - 2006 Charles Bilyue' 117 118 Sound emulator code used in 1.52+ 119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) 120 121 S-SMP emulator code used in 1.54+ 122 (c) Copyright 2016 byuu 123 124 SH assembler code partly based on x86 assembler code 125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) 126 127 2xSaI filter 128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa 129 130 HQ2x, HQ3x, HQ4x filters 131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) 132 133 NTSC filter 134 (c) Copyright 2006 - 2007 Shay Green 135 136 GTK+ GUI code 137 (c) Copyright 2004 - 2016 BearOso 138 139 Win32 GUI code 140 (c) Copyright 2003 - 2006 blip, 141 funkyass, 142 Matthew Kendora, 143 Nach, 144 nitsuja 145 (c) Copyright 2009 - 2016 OV2 146 147 Mac OS GUI code 148 (c) Copyright 1998 - 2001 John Stiles 149 (c) Copyright 2001 - 2011 zones 150 151 152 Specific ports contains the works of other authors. See headers in 153 individual files. 154 155 156 Snes9x homepage: http://www.snes9x.com/ 157 158 Permission to use, copy, modify and/or distribute Snes9x in both binary 159 and source form, for non-commercial purposes, is hereby granted without 160 fee, providing that this license information and copyright notice appear 161 with all copies and any derived work. 162 163 This software is provided 'as-is', without any express or implied 164 warranty. In no event shall the authors be held liable for any damages 165 arising from the use of this software or it's derivatives. 166 167 Snes9x is freeware for PERSONAL USE only. Commercial users should 168 seek permission of the copyright holders first. Commercial use includes, 169 but is not limited to, charging money for Snes9x or software derived from 170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or 171 using Snes9x as a promotion for your commercial product. 172 173 The copyright holders request that bug fixes and improvements to the code 174 should be forwarded to them so everyone can benefit from the modifications 175 in future versions. 176 177 Super NES and Super Nintendo Entertainment System are trademarks of 178 Nintendo Co., Limited and its subsidiary companies. 179 ***********************************************************************************/ 180 181/*********************************************************************************** 182 SNES9X for Mac OS (c) Copyright John Stiles 183 184 Snes9x for Mac OS X 185 186 (c) Copyright 2001 - 2011 zones 187 (c) Copyright 2002 - 2005 107 188 (c) Copyright 2002 PB1400c 189 (c) Copyright 2004 Alexander and Sander 190 (c) Copyright 2004 - 2005 Steven Seeger 191 (c) Copyright 2005 Ryan Vogt 192 ***********************************************************************************/ 193 194 195#include "snes9x.h" 196#include "apu.h" 197 198#include <Cocoa/Cocoa.h> 199#include <CoreAudio/CoreAudio.h> 200#include <AudioToolbox/AudioToolbox.h> 201#include <AudioUnit/AudioUnitCarbonView.h> 202#include <pthread.h> 203 204#include "mac-prefix.h" 205#include "mac-dialog.h" 206#include "mac-musicbox.h" 207#include "mac-os.h" 208#include "mac-snes9x.h" 209#include "mac-audio.h" 210 211#define kAUReverb (1 << 0) 212#define kAUGraphEQ (1 << 1) 213 214int cureffect = kAUReverb; 215 216static AUGraph agraph; 217static AUNode outNode, cnvNode, revNode, eqlNode; 218static AudioUnit outAU, cnvAU, revAU, eqlAU; 219static AudioUnitCarbonView carbonView = NULL; 220static EventHandlerUPP carbonViewEventUPP = NULL; 221static EventHandlerRef carbonViewEventRef = NULL; 222static WindowRef effectWRef; 223static HISize effectWSize; 224static pthread_mutex_t mutex; 225static UInt32 outStoredFrames, cnvStoredFrames, revStoredFrames, eqlStoredFrames, devStoredFrames; 226 227static void ConnectAudioUnits (void); 228static void DisconnectAudioUnits (void); 229static void SaveEffectPresets (void); 230static void LoadEffectPresets (void); 231static void SetAudioUnitSoundFormat (void); 232static void SetAudioUnitVolume (void); 233static void StoreBufferFrameSize (void); 234static void ChangeBufferFrameSize (void); 235static void ReplaceAudioUnitCarbonView (void); 236static void ResizeSoundEffectsDialog (HIViewRef); 237static void MacFinalizeSamplesCallBack (void *); 238static OSStatus MacAURenderCallBack (void *, AudioUnitRenderActionFlags *, const AudioTimeStamp *, UInt32, UInt32, AudioBufferList *); 239static pascal OSStatus SoundEffectsEventHandler (EventHandlerCallRef, EventRef, void *); 240static pascal OSStatus SoundEffectsCarbonViewEventHandler (EventHandlerCallRef, EventRef, void *); 241 242 243void InitMacSound (void) 244{ 245 OSStatus err; 246 247 err = NewAUGraph(&agraph); 248 249#ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT 250 AudioComponentDescription outdesc, cnvdesc, revdesc, eqldesc; 251#else 252 ComponentDescription outdesc, cnvdesc, revdesc, eqldesc; 253#endif 254 255 outdesc.componentType = kAudioUnitType_Output; 256 outdesc.componentSubType = kAudioUnitSubType_DefaultOutput; 257 outdesc.componentManufacturer = 0; 258 outdesc.componentFlags = 0; 259 outdesc.componentFlagsMask = 0; 260 261 cnvdesc.componentType = kAudioUnitType_FormatConverter; 262 cnvdesc.componentSubType = kAudioUnitSubType_AUConverter; 263 cnvdesc.componentManufacturer = kAudioUnitManufacturer_Apple; 264 cnvdesc.componentFlags = 0; 265 cnvdesc.componentFlagsMask = 0; 266 267 revdesc.componentType = kAudioUnitType_Effect; 268 revdesc.componentSubType = kAudioUnitSubType_MatrixReverb; 269 revdesc.componentManufacturer = kAudioUnitManufacturer_Apple; 270 revdesc.componentFlags = 0; 271 revdesc.componentFlagsMask = 0; 272 273 eqldesc.componentType = kAudioUnitType_Effect; 274 eqldesc.componentSubType = kAudioUnitSubType_GraphicEQ; 275 eqldesc.componentManufacturer = kAudioUnitManufacturer_Apple; 276 eqldesc.componentFlags = 0; 277 eqldesc.componentFlagsMask = 0; 278 279#ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT 280 err = AUGraphAddNode(agraph, &outdesc, &outNode); 281 err = AUGraphAddNode(agraph, &cnvdesc, &cnvNode); 282 err = AUGraphAddNode(agraph, &revdesc, &revNode); 283 err = AUGraphAddNode(agraph, &eqldesc, &eqlNode); 284#else 285 err = AUGraphNewNode(agraph, &outdesc, 0, NULL, &outNode); 286 err = AUGraphNewNode(agraph, &cnvdesc, 0, NULL, &cnvNode); 287 err = AUGraphNewNode(agraph, &revdesc, 0, NULL, &revNode); 288 err = AUGraphNewNode(agraph, &eqldesc, 0, NULL, &eqlNode); 289#endif 290 291 err = AUGraphOpen(agraph); 292 293#ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT 294 err = AUGraphNodeInfo(agraph, outNode, NULL, &outAU); 295 err = AUGraphNodeInfo(agraph, cnvNode, NULL, &cnvAU); 296 err = AUGraphNodeInfo(agraph, revNode, NULL, &revAU); 297 err = AUGraphNodeInfo(agraph, eqlNode, NULL, &eqlAU); 298#else 299 err = AUGraphGetNodeInfo(agraph, outNode, NULL, NULL, NULL, &outAU); 300 err = AUGraphGetNodeInfo(agraph, cnvNode, NULL, NULL, NULL, &cnvAU); 301 err = AUGraphGetNodeInfo(agraph, revNode, NULL, NULL, NULL, &revAU); 302 err = AUGraphGetNodeInfo(agraph, eqlNode, NULL, NULL, NULL, &eqlAU); 303#endif 304 305 SetAudioUnitSoundFormat(); 306 SetAudioUnitVolume(); 307 StoreBufferFrameSize(); 308 ChangeBufferFrameSize(); 309 310 err = AUGraphInitialize(agraph); 311 312 ConnectAudioUnits(); 313 LoadEffectPresets(); 314 315 pthread_mutex_init(&mutex, NULL); 316 S9xSetSamplesAvailableCallback(MacFinalizeSamplesCallBack, NULL); 317} 318 319void DeinitMacSound (void) 320{ 321 OSStatus err; 322 323 pthread_mutex_destroy(&mutex); 324 SaveEffectPresets(); 325 DisconnectAudioUnits(); 326 err = AUGraphUninitialize(agraph); 327 err = AUGraphClose(agraph); 328 err = DisposeAUGraph(agraph); 329} 330 331static void SetAudioUnitSoundFormat (void) 332{ 333 OSStatus err; 334 AudioStreamBasicDescription format; 335 336#ifdef __BIG_ENDIAN__ 337 UInt32 endian = kLinearPCMFormatFlagIsBigEndian; 338#else 339 UInt32 endian = 0; 340#endif 341 342 memset(&format, 0, sizeof(format)); 343 344 format.mSampleRate = (Float64) Settings.SoundPlaybackRate; 345 format.mFormatID = kAudioFormatLinearPCM; 346 format.mFormatFlags = endian | (Settings.SixteenBitSound ? kLinearPCMFormatFlagIsSignedInteger : 0); 347 format.mBytesPerPacket = 2 * (Settings.SixteenBitSound ? 2 : 1); 348 format.mFramesPerPacket = 1; 349 format.mBytesPerFrame = 2 * (Settings.SixteenBitSound ? 2 : 1); 350 format.mChannelsPerFrame = 2; 351 format.mBitsPerChannel = Settings.SixteenBitSound ? 16 : 8; 352 353 err = AudioUnitSetProperty(aueffect ? cnvAU : outAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, sizeof(format)); 354} 355 356static void SetAudioUnitVolume (void) 357{ 358 OSStatus err; 359 360 err = AudioUnitSetParameter(outAU, kAudioUnitParameterUnit_LinearGain, kAudioUnitScope_Output, 0, (float) macSoundVolume / 100.0f, 0); 361} 362 363static void StoreBufferFrameSize (void) 364{ 365 OSStatus err; 366 UInt32 size; 367 AudioDeviceID device; 368#ifndef MAC_PANTHER_SUPPORT 369 AudioObjectPropertyAddress address; 370 371 address.mSelector = kAudioDevicePropertyBufferFrameSize; 372 address.mScope = kAudioObjectPropertyScopeGlobal; 373 address.mElement = kAudioObjectPropertyElementMaster; 374#endif 375 376 size = sizeof(AudioDeviceID); 377 err = AudioUnitGetProperty(outAU, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device, &size); 378 379 size = sizeof(UInt32); 380#ifndef MAC_PANTHER_SUPPORT 381 err = AudioObjectGetPropertyData(device, &address, 0, NULL, &size, &devStoredFrames); 382#else 383 err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyBufferFrameSize, &size, &devStoredFrames); 384#endif 385 386 size = sizeof(UInt32); 387 err = AudioUnitGetProperty(outAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &outStoredFrames, &size); 388 size = sizeof(UInt32); 389 err = AudioUnitGetProperty(eqlAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &eqlStoredFrames, &size); 390 size = sizeof(UInt32); 391 err = AudioUnitGetProperty(revAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &revStoredFrames, &size); 392 size = sizeof(UInt32); 393 err = AudioUnitGetProperty(cnvAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &cnvStoredFrames, &size); 394} 395 396static void ChangeBufferFrameSize (void) 397{ 398 OSStatus err; 399 UInt32 numframes, size; 400 AudioDeviceID device; 401#ifndef MAC_PANTHER_SUPPORT 402 AudioObjectPropertyAddress address; 403 404 address.mSelector = kAudioDevicePropertyBufferFrameSize; 405 address.mScope = kAudioObjectPropertyScopeGlobal; 406 address.mElement = kAudioObjectPropertyElementMaster; 407#else 408 AudioTimeStamp ts; 409 410 ts.mFlags = 0; 411#endif 412 413 size = sizeof(AudioDeviceID); 414 err = AudioUnitGetProperty(outAU, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device, &size); 415 416 size = sizeof(UInt32); 417 418 if (macSoundInterval_ms == 0) 419 { 420 #ifndef MAC_PANTHER_SUPPORT 421 err = AudioObjectSetPropertyData(device, &address, 0, NULL, size, &devStoredFrames); 422 #else 423 err = AudioDeviceSetProperty(device, &ts, 0, false, kAudioDevicePropertyBufferFrameSize, size, &devStoredFrames); 424 #endif 425 426 err = AudioUnitSetProperty(outAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &outStoredFrames, size); 427 err = AudioUnitSetProperty(eqlAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &eqlStoredFrames, size); 428 err = AudioUnitSetProperty(revAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &revStoredFrames, size); 429 err = AudioUnitSetProperty(cnvAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &cnvStoredFrames, size); 430 431 printf("Interval: system, Frames: %d/%d/%d/%d/%d\n", (int) devStoredFrames, (int) outStoredFrames, (int) eqlStoredFrames, (int) revStoredFrames, (int) cnvStoredFrames); 432 } 433 else 434 { 435 numframes = macSoundInterval_ms * Settings.SoundPlaybackRate / 1000; 436 437 #ifndef MAC_PANTHER_SUPPORT 438 err = AudioObjectSetPropertyData(device, &address, 0, NULL, size, &numframes); 439 #else 440 err = AudioDeviceSetProperty(device, &ts, 0, false, kAudioDevicePropertyBufferFrameSize, size, &numframes); 441 #endif 442 443 err = AudioUnitSetProperty(outAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &numframes, size); 444 err = AudioUnitSetProperty(eqlAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &numframes, size); 445 err = AudioUnitSetProperty(revAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &numframes, size); 446 err = AudioUnitSetProperty(cnvAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &numframes, size); 447 448 printf("Interval: %dms, Frames: %d\n", (int) macSoundInterval_ms, (int) numframes); 449 } 450} 451 452static void ConnectAudioUnits (void) 453{ 454 OSStatus err; 455 AURenderCallbackStruct callback; 456 457 callback.inputProc = MacAURenderCallBack; 458 callback.inputProcRefCon = NULL; 459 460 if (systemVersion >= 0x1050) 461 err = AUGraphSetNodeInputCallback(agraph, aueffect ? cnvNode : outNode, 0, &callback); 462#ifdef MAC_TIGER_PANTHER_SUPPORT 463 else 464 err = AudioUnitSetProperty(aueffect ? cnvAU : outAU, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); 465#endif 466 467 if ((aueffect & kAUReverb) && (aueffect & kAUGraphEQ)) 468 { 469 err = AUGraphConnectNodeInput(agraph, cnvNode, 0, revNode, 0); 470 err = AUGraphConnectNodeInput(agraph, revNode, 0, eqlNode, 0); 471 err = AUGraphConnectNodeInput(agraph, eqlNode, 0, outNode, 0); 472 } 473 else 474 if (aueffect & kAUReverb) 475 { 476 err = AUGraphConnectNodeInput(agraph, cnvNode, 0, revNode, 0); 477 err = AUGraphConnectNodeInput(agraph, revNode, 0, outNode, 0); 478 } 479 else 480 if (aueffect & kAUGraphEQ) 481 { 482 err = AUGraphConnectNodeInput(agraph, cnvNode, 0, eqlNode, 0); 483 err = AUGraphConnectNodeInput(agraph, eqlNode, 0, outNode, 0); 484 } 485} 486 487static void DisconnectAudioUnits (void) 488{ 489 OSStatus err; 490 491 err = AUGraphClearConnections(agraph); 492} 493 494static OSStatus MacAURenderCallBack (void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData) 495{ 496 if (Settings.Mute) 497 { 498 memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize); 499 *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence; 500 } 501 else 502 if (Settings.Stereo) 503 { 504 unsigned int samples; 505 506 samples = ioData->mBuffers[0].mDataByteSize; 507 if (Settings.SixteenBitSound) 508 samples >>= 1; 509 510 pthread_mutex_lock(&mutex); 511 S9xMixSamples((uint8 *) ioData->mBuffers[0].mData, samples); 512 pthread_mutex_unlock(&mutex); 513 } 514 else // Manually map L to R 515 { 516 unsigned int monosmp; 517 518 monosmp = ioData->mBuffers[0].mDataByteSize >> 1; 519 if (Settings.SixteenBitSound) 520 monosmp >>= 1; 521 522 pthread_mutex_lock(&mutex); 523 S9xMixSamples((uint8 *) ioData->mBuffers[0].mData, monosmp); 524 pthread_mutex_unlock(&mutex); 525 526 if (Settings.SixteenBitSound) 527 { 528 for (int i = monosmp - 1; i >= 0; i--) 529 ((int16 *) ioData->mBuffers[0].mData)[i * 2 + 1] = ((int16 *) ioData->mBuffers[0].mData)[i * 2] = ((int16 *) ioData->mBuffers[0].mData)[i]; 530 } 531 else 532 { 533 for (int i = monosmp - 1; i >= 0; i--) 534 ((int8 *) ioData->mBuffers[0].mData)[i * 2 + 1] = ((int8 *) ioData->mBuffers[0].mData)[i * 2] = ((int8 *) ioData->mBuffers[0].mData)[i]; 535 } 536 } 537 538 return (noErr); 539} 540 541static void MacFinalizeSamplesCallBack (void *userData) 542{ 543 pthread_mutex_lock(&mutex); 544 S9xFinalizeSamples(); 545 pthread_mutex_unlock(&mutex); 546} 547 548static void SaveEffectPresets (void) 549{ 550 OSStatus err; 551 AUPreset preset; 552 CFPropertyListRef classData; 553 UInt32 size; 554 555 preset.presetNumber = -1; // User Preset 556 preset.presetName = CFSTR("SNES9X Preset"); 557 558 err = AudioUnitSetProperty(revAU, kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0, &preset, sizeof(preset)); 559 if (err == noErr) 560 { 561 size = sizeof(classData); 562 err = AudioUnitGetProperty(revAU, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, &size); 563 if (err == noErr) 564 { 565 CFPreferencesSetAppValue(CFSTR("Effect_Preset_Reverb"), classData, kCFPreferencesCurrentApplication); 566 CFRelease(classData); 567 } 568 } 569 570 err = AudioUnitSetProperty(eqlAU, kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0, &preset, sizeof(preset)); 571 if (err == noErr) 572 { 573 size = sizeof(classData); 574 err = AudioUnitGetProperty(eqlAU, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, &size); 575 if (err == noErr) 576 { 577 CFPreferencesSetAppValue(CFSTR("Effect_Preset_GraphEQ"), classData, kCFPreferencesCurrentApplication); 578 CFRelease(classData); 579 } 580 } 581 582 CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); 583} 584 585static void LoadEffectPresets (void) 586{ 587 OSStatus err; 588 CFPropertyListRef classData; 589 590 classData = CFPreferencesCopyAppValue(CFSTR("Effect_Preset_Reverb"), kCFPreferencesCurrentApplication); 591 if (classData) 592 { 593 err = AudioUnitSetProperty(revAU, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, sizeof(classData)); 594 CFRelease(classData); 595 } 596 597 classData = CFPreferencesCopyAppValue(CFSTR("Effect_Preset_GraphEQ"), kCFPreferencesCurrentApplication); 598 if (classData) 599 { 600 err = AudioUnitSetProperty(eqlAU, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, sizeof(classData)); 601 CFRelease(classData); 602 } 603} 604 605void MacStartSound (void) 606{ 607 OSStatus err; 608 Boolean r = false; 609 610 if (macQTRecord) 611 return; 612 613 err = AUGraphIsRunning(agraph, &r); 614 if (err == noErr && r == false) 615 { 616 err = AUGraphStart(agraph); 617 printf("AUGraph started.\n"); 618 } 619} 620 621void MacStopSound (void) 622{ 623 OSStatus err; 624 Boolean r = false; 625 626 if (macQTRecord) 627 return; 628 629 err = AUGraphIsRunning(agraph, &r); 630 if (err == noErr && r == true) 631 { 632 err = AUGraphStop(agraph); 633 printf("AUGraph stopped.\n"); 634 } 635} 636 637bool8 S9xOpenSoundDevice (void) 638{ 639 OSStatus err; 640 641 err = AUGraphUninitialize(agraph); 642 643 SetAudioUnitSoundFormat(); 644 SetAudioUnitVolume(); 645 ChangeBufferFrameSize(); 646 647 err = AUGraphInitialize(agraph); 648 649 return (true); 650} 651 652void PlayAlertSound (void) 653{ 654 if (systemVersion >= 0x1050) 655 AudioServicesPlayAlertSound(kUserPreferredAlert); 656#ifdef MAC_TIGER_PANTHER_SUPPORT 657 else 658 SysBeep(10); 659#endif 660} 661 662static void ReplaceAudioUnitCarbonView (void) 663{ 664 OSStatus err; 665 AudioUnit editau; 666 Component cmp; 667 ComponentDescription desc; 668 HIViewRef pane, contentview, ctl; 669 HIViewID cid; 670 Float32Point location, size; 671 Rect rct; 672 UInt32 psize; 673 674 if (carbonView) 675 { 676 err = RemoveEventHandler(carbonViewEventRef); 677 DisposeEventHandlerUPP(carbonViewEventUPP); 678 carbonViewEventRef = NULL; 679 carbonViewEventUPP = NULL; 680 681 CloseComponent(carbonView); 682 carbonView = NULL; 683 } 684 685 switch (cureffect) 686 { 687 case kAUGraphEQ: 688 editau = eqlAU; 689 break; 690 691 case kAUReverb: 692 default: 693 editau = revAU; 694 break; 695 } 696 697 desc.componentType = kAudioUnitCarbonViewComponentType; 698 desc.componentSubType = kAUCarbonViewSubType_Generic; 699 desc.componentManufacturer = kAudioUnitManufacturer_Apple; 700 desc.componentFlags = 0; 701 desc.componentFlagsMask = 0; 702 703 err = AudioUnitGetPropertyInfo(editau, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, &psize, NULL); 704 if (err == noErr) 705 { 706 ComponentDescription *editors; 707 int nEditors; 708 709 nEditors = psize / sizeof(ComponentDescription); 710 711 editors = new ComponentDescription[nEditors]; 712 713 err = AudioUnitGetProperty(editau, kAudioUnitProperty_GetUIComponentList, kAudioUnitScope_Global, 0, editors, &psize); 714 if (err == noErr) 715 desc = editors[0]; 716 717 delete [] editors; 718 } 719 720 HIViewFindByID(HIViewGetRoot(effectWRef), kHIViewWindowContentID, &contentview); 721 722 cmp = FindNextComponent(NULL, &desc); 723 if (cmp) 724 { 725 err = OpenAComponent(cmp, &carbonView); 726 if (err == noErr) 727 { 728 EventTypeSpec event[] = { { kEventClassControl, kEventControlBoundsChanged } }; 729 730 GetWindowBounds(effectWRef, kWindowContentRgn, &rct); 731 location.x = 20; 732 location.y = 96; 733 size.x = rct.right - rct.left; 734 size.y = rct.bottom - rct.top; 735 736 err = AudioUnitCarbonViewCreate(carbonView, editau, effectWRef, contentview, &location, &size, &pane); 737 738 carbonViewEventUPP = NewEventHandlerUPP(SoundEffectsCarbonViewEventHandler); 739 err = InstallControlEventHandler(pane, carbonViewEventUPP, GetEventTypeCount(event), event, (void *) effectWRef, &carbonViewEventRef); 740 741 ResizeSoundEffectsDialog(pane); 742 } 743 else 744 carbonView = NULL; 745 } 746 else 747 carbonView = NULL; 748 749 cid.id = 0; 750 cid.signature = 'Enab'; 751 HIViewFindByID(contentview, cid, &ctl); 752 SetControl32BitValue(ctl, (aueffect & cureffect) ? 1 : 0); 753} 754 755static void ResizeSoundEffectsDialog (HIViewRef view) 756{ 757 OSStatus err; 758 HIViewRef ctl, root; 759 HIViewID cid; 760 HIRect bounds; 761 Rect rv; 762 int w, h; 763 764 root = HIViewGetRoot(effectWRef); 765 766 cid.id = 0; 767 cid.signature = 'Enab'; 768 HIViewFindByID(root, cid, &ctl); 769 770 err = HIViewSetVisible(ctl, false); 771 err = HIViewSetVisible(view, false); 772 773 HIViewGetBounds(view, &bounds); 774 w = ((int) bounds.size.width + 30 > (int) effectWSize.width) ? ((int) bounds.size.width + 30) : (int) effectWSize.width; 775 h = (int) bounds.size.height + 122; 776#ifdef MAC_PANTHER_SUPPORT 777 if (systemVersion < 0x1040) 778 h += 16; 779#endif 780 GetWindowBounds(effectWRef, kWindowStructureRgn, &rv); 781 rv.right = rv.left + w; 782 rv.bottom = rv.top + h; 783 err = TransitionWindow(effectWRef, kWindowSlideTransitionEffect, kWindowResizeTransitionAction, &rv); 784 785 err = HIViewSetVisible(ctl, true); 786 err = HIViewSetVisible(view, true); 787 788#ifdef MAC_PANTHER_SUPPORT 789 if (systemVersion < 0x1040) 790 { 791 HIRect frame; 792 Rect rct; 793 794 GetWindowBounds(effectWRef, kWindowContentRgn, &rv); 795 796 cid.signature = 'SfUI'; 797 HIViewFindByID(root, cid, &ctl); 798 HIViewGetFrame(ctl, &frame); 799 frame.size.width = (float) (rv.right - rv.left); 800 HIViewSetFrame(ctl, &frame); 801 802 cid.signature = 'LINE'; 803 HIViewFindByID(root, cid, &ctl); 804 HIViewGetFrame(ctl, &frame); 805 frame.size.width = (float) (rv.right - rv.left - 24); 806 HIViewSetFrame(ctl, &frame); 807 808 rct.top = 0; 809 rct.left = 0; 810 rct.bottom = rv.bottom - rv.top; 811 rct.right = rv.right - rv.left; 812 err = InvalWindowRect(effectWRef, &rct); 813 } 814#endif 815} 816 817void ConfigureSoundEffects (void) 818{ 819 OSStatus err; 820 IBNibRef nibRef; 821 822 err = CreateNibReference(kMacS9XCFString, &nibRef); 823 if (err == noErr) 824 { 825 WindowRef uiparts; 826 827 err = CreateWindowFromNib(nibRef, CFSTR("SoundEffect"), &uiparts); 828 if (err == noErr) 829 { 830 EventHandlerUPP eventUPP; 831 EventHandlerRef eventHandler; 832 EventTypeSpec event[] = { { kEventClassWindow, kEventWindowClose }, 833 { kEventClassCommand, kEventCommandProcess }, 834 { kEventClassCommand, kEventCommandUpdateStatus } }; 835 HIViewRef ctl, userpane, contentview; 836 HIViewID cid; 837 CFStringRef str; 838 Rect rct; 839 WindowAttributes metal = 0; 840 841 cid.id = 0; 842 cid.signature = 'SfUI'; 843 HIViewFindByID(HIViewGetRoot(uiparts), cid, &userpane); 844 GetWindowBounds(uiparts, kWindowContentRgn, &rct); 845 846 if (systemVersion >= 0x1040) // AUs support compositing 847 { 848 HIRect frame; 849 850 str = CFCopyLocalizedString(CFSTR("CreateMetalDlg"), "NO"); 851 if (str) 852 { 853 if (CFStringCompare(str, CFSTR("YES"), 0) == kCFCompareEqualTo) 854 metal = kWindowMetalAttribute; 855 856 CFRelease(str); 857 } 858 859 frame = CGRectMake(0.0f, 0.0f, (float) (rct.right - rct.left), (float) (rct.bottom - rct.top)); 860 err = CreateNewWindow(kDocumentWindowClass, kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute | kWindowCompositingAttribute | metal, &rct, &effectWRef); 861 err = HIViewFindByID(HIViewGetRoot(effectWRef), kHIViewWindowContentID, &contentview); 862 err = HIViewAddSubview(contentview, userpane); 863 err = HIViewSetFrame(userpane, &frame); 864 } 865 #ifdef MAC_PANTHER_SUPPORT 866 else 867 { 868 err = CreateNewWindow(kDocumentWindowClass, kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute, &rct, &effectWRef); 869 err = CreateRootControl(effectWRef, &contentview); 870 err = EmbedControl(userpane, contentview); 871 MoveControl(userpane, 0, 0); 872 } 873 #endif 874 875 CFRelease(uiparts); 876 877 if (!metal) 878 err = SetThemeWindowBackground(effectWRef, kThemeBrushDialogBackgroundActive, false); 879 880 str = CFCopyLocalizedString(CFSTR("SoundEffectDlg"), "SoundEffect"); 881 if (str) 882 { 883 err = SetWindowTitleWithCFString(effectWRef, str); 884 CFRelease(str); 885 } 886 887 if (systemVersion >= 0x1040) // AUs support compositing 888 { 889 HILayoutInfo layoutinfo; 890 HIViewRef separator; 891 892 cid.signature = 'LINE'; 893 err = HIViewFindByID(userpane, cid, &separator); 894 895 layoutinfo.version = kHILayoutInfoVersionZero; 896 err = HIViewGetLayoutInfo(userpane, &layoutinfo); 897 898 layoutinfo.binding.top.toView = contentview; 899 layoutinfo.binding.top.kind = kHILayoutBindNone; 900 layoutinfo.binding.bottom.toView = contentview; 901 layoutinfo.binding.bottom.kind = kHILayoutBindNone; 902 layoutinfo.binding.left.toView = contentview; 903 layoutinfo.binding.left.kind = kHILayoutBindLeft; 904 layoutinfo.binding.right.toView = contentview; 905 layoutinfo.binding.right.kind = kHILayoutBindRight; 906 err = HIViewSetLayoutInfo(userpane, &layoutinfo); 907 908 layoutinfo.version = kHILayoutInfoVersionZero; 909 err = HIViewGetLayoutInfo(separator, &layoutinfo); 910 911 layoutinfo.binding.top.toView = userpane; 912 layoutinfo.binding.top.kind = kHILayoutBindNone; 913 layoutinfo.binding.bottom.toView = userpane; 914 layoutinfo.binding.bottom.kind = kHILayoutBindNone; 915 layoutinfo.binding.left.toView = userpane; 916 layoutinfo.binding.left.kind = kHILayoutBindLeft; 917 layoutinfo.binding.right.toView = userpane; 918 layoutinfo.binding.right.kind = kHILayoutBindRight; 919 err = HIViewSetLayoutInfo(separator, &layoutinfo); 920 } 921 922 eventUPP = NewEventHandlerUPP(SoundEffectsEventHandler); 923 err = InstallWindowEventHandler(effectWRef, eventUPP, GetEventTypeCount(event), event, (void *) effectWRef, &eventHandler); 924 925 GetWindowBounds(effectWRef, kWindowContentRgn, &rct); 926 effectWSize.width = (float) (rct.right - rct.left); 927 effectWSize.height = (float) (rct.bottom - rct.top ); 928 929 carbonView = NULL; 930 ReplaceAudioUnitCarbonView(); 931 932 cid.signature = 'Epop'; 933 HIViewFindByID(userpane, cid, &ctl); 934 switch (cureffect) 935 { 936 case kAUReverb: 937 SetControl32BitValue(ctl, 1); 938 break; 939 940 case kAUGraphEQ: 941 SetControl32BitValue(ctl, 2); 942 break; 943 } 944 945 MoveWindowPosition(effectWRef, kWindowSoundEffect, false); 946 ShowWindow(effectWRef); 947 err = RunAppModalLoopForWindow(effectWRef); 948 HideWindow(effectWRef); 949 SaveWindowPosition(effectWRef, kWindowSoundEffect); 950 951 if (carbonView) 952 { 953 err = RemoveEventHandler(carbonViewEventRef); 954 DisposeEventHandlerUPP(carbonViewEventUPP); 955 carbonViewEventRef = NULL; 956 carbonViewEventUPP = NULL; 957 958 CloseComponent(carbonView); 959 carbonView = NULL; 960 } 961 962 err = RemoveEventHandler(eventHandler); 963 DisposeEventHandlerUPP(eventUPP); 964 965 CFRelease(effectWRef); 966 } 967 968 DisposeNibReference(nibRef); 969 } 970} 971 972static pascal OSStatus SoundEffectsCarbonViewEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData) 973{ 974 OSStatus err, result = eventNotHandledErr; 975 HIViewRef ctl; 976 HIRect bounds; 977 978 switch (GetEventClass(inEvent)) 979 { 980 case kEventClassControl: 981 switch (GetEventKind(inEvent)) 982 { 983 case kEventControlBoundsChanged: 984 err = GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &ctl); 985 if (err == noErr) 986 { 987 err = GetEventParameter(inEvent, kEventParamCurrentBounds, typeHIRect, NULL, sizeof(HIRect), NULL, &bounds); 988 if (err == noErr) 989 { 990 if ((bounds.size.width > 0) && (bounds.size.height > 0)) 991 ResizeSoundEffectsDialog(ctl); 992 } 993 } 994 995 result = noErr; 996 break; 997 } 998 999 break; 1000 } 1001 1002 return (result); 1003} 1004 1005static pascal OSStatus SoundEffectsEventHandler (EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData) 1006{ 1007 OSStatus err, result = eventNotHandledErr; 1008 WindowRef tWindowRef = (WindowRef) inUserData; 1009 1010 switch (GetEventClass(inEvent)) 1011 { 1012 case kEventClassWindow: 1013 switch (GetEventKind(inEvent)) 1014 { 1015 case kEventWindowClose: 1016 QuitAppModalLoopForWindow(tWindowRef); 1017 result = noErr; 1018 break; 1019 } 1020 1021 break; 1022 1023 case kEventClassCommand: 1024 switch (GetEventKind(inEvent)) 1025 { 1026 HICommand tHICommand; 1027 1028 case kEventCommandUpdateStatus: 1029 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand); 1030 if (err == noErr && tHICommand.commandID == 'clos') 1031 { 1032 UpdateMenuCommandStatus(true); 1033 result = noErr; 1034 } 1035 1036 break; 1037 1038 case kEventCommandProcess: 1039 err = GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &tHICommand); 1040 if (err == noErr) 1041 { 1042 switch (tHICommand.commandID) 1043 { 1044 case 'Enab': 1045 { 1046 Boolean r = false; 1047 1048 mboxPause = true; 1049 1050 err = AUGraphIsRunning(agraph, &r); 1051 if (err == noErr && r) 1052 err = AUGraphStop(agraph); 1053 1054 DisconnectAudioUnits(); 1055 err = AUGraphUninitialize(agraph); 1056 1057 aueffect ^= cureffect; 1058 1059 SetAudioUnitSoundFormat(); 1060 ChangeBufferFrameSize(); 1061 1062 err = AUGraphInitialize(agraph); 1063 ConnectAudioUnits(); 1064 1065 if (r) 1066 err = AUGraphStart(agraph); 1067 1068 mboxPause = false; 1069 1070 result = noErr; 1071 break; 1072 } 1073 1074 case 'Revb': 1075 cureffect = kAUReverb; 1076 ReplaceAudioUnitCarbonView(); 1077 break; 1078 1079 case 'GrEQ': 1080 cureffect = kAUGraphEQ; 1081 ReplaceAudioUnitCarbonView(); 1082 break; 1083 } 1084 } 1085 1086 break; 1087 } 1088 1089 break; 1090 } 1091 1092 return (result); 1093} 1094