//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AUMixer3DView::SetRenderingFlagsCheckboxes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void AUMixer3DView::SetRenderingFlagsCheckboxes() { // set the check boxes according to the current rendering flags UInt32 flags; UInt32 size = sizeof(flags); AudioUnitGetProperty( GetEditAudioUnit(), kAudioUnitProperty_3DMixerRenderingFlags, kAudioUnitScope_Input, 0, &flags, &size ); UInt32 usesReverb = 0; AudioUnitGetProperty( GetEditAudioUnit(), kAudioUnitProperty_UsesInternalReverb, kAudioUnitScope_Input, 0, &usesReverb, &size ); SetCheckbox('atr0', 1, flags & k3DMixerRenderingFlags_InterAuralDelay ); SetCheckbox('atr1', 2, flags & k3DMixerRenderingFlags_DopplerShift ); SetCheckbox('atr2', 3, flags & k3DMixerRenderingFlags_DistanceAttenuation ); SetCheckbox('atr3', 4, flags & k3DMixerRenderingFlags_DistanceFilter ); SetCheckbox('atr4', 5, flags & k3DMixerRenderingFlags_DistanceDiffusion ); SetCheckbox('rvrb', 6, usesReverb ); ::UpdateControls(GetCarbonWindow(), NULL ); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AUMixer3DView::SetCheckbox // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void AUMixer3DView::SetCheckbox(OSType inSig, SInt32 inID, SInt16 inValue ) { WindowRef window = GetCarbonWindow(); ControlID controlID; controlID.signature = inSig; controlID.id = inID; ControlRef control; OSStatus result = ::GetControlByID(window, &controlID, &control ); if(result == noErr) { SetControlValue(control, int(inValue != 0 ) ); ShowControl(control); } }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AUMixer3DView::SetRenderingAlgorithmControl // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void AUMixer3DView::SetRenderingAlgorithmControl(int inAlgorithm ) { WindowRef window = GetCarbonWindow(); ControlID controlID; controlID.signature = 'algo'; controlID.id = 0; ControlRef control; OSStatus result = ::GetControlByID(window, &controlID, &control ); if(result == noErr) { SetControlValue(control, inAlgorithm+1 ); ShowControl(control); } }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AUDiskStreamingCheckbox::AUDiskStreamingCheckbox // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AUDiskStreamingCheckbox::AUDiskStreamingCheckbox (AUCarbonViewBase *inBase, Point inLocation, ControlFontStyleRec & inFontStyle) : AUPropertyControl (inBase) { Rect r; r.top = inLocation.v; r.bottom = r.top; r.left = inLocation.h; r.right = r.left; // localize as necessary if (!sLocalized) { sLocalized = true; CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(kLocalizedStringBundle_AUView); if (mainBundle) { kStringStreamFromDisk = CFCopyLocalizedStringFromTableInBundle( kAUViewLocalizedStringKey_StreamFromDisk, kLocalizedStringTable_AUView, mainBundle, CFSTR("'Stream From Disk' checkbox title string")); } } verify_noerr(CreateCheckBoxControl( GetCarbonWindow(), &r, kStringStreamFromDisk, 0, true, &mControl)); verify_noerr (SetControlFontStyle (mControl, &inFontStyle)); ControlSize smallSize = kControlSizeSmall; verify_noerr (SetControlData (mControl, kControlEntireControl, kControlSizeTag, sizeof (ControlSize), &smallSize)); AUCarbonViewControl::SizeControlToFit(mControl, NULL, &mHeight); if (mHeight < 0) mHeight = 0; EmbedControl(mControl); UInt32 value = 0; UInt32 size = sizeof(value); verify_noerr (AudioUnitGetProperty (mView->GetEditAudioUnit(), kMusicDeviceProperty_StreamFromDisk, kAudioUnitScope_Global, 0, &value, &size)); HandlePropertyChange (value); RegisterEvents(); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AUMixer3DView::CreateUI // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OSStatus AUMixer3DView::CreateUI(Float32 inXOffset, Float32 inYOffset) { EventHandlerUPP handlerUPP = NewEventHandlerUPP(MyEventHandlerDispatch); EventTypeSpec eventTypes[] = { {kEventClassKeyboard, kEventRawKeyDown}, {kEventClassKeyboard, kEventRawKeyRepeat}, {kEventClassMouse, kEventMouseDown}, {kEventClassMouse, kEventMouseUp}, {kEventClassMouse, kEventMouseDragged}, {kEventClassCommand, kEventCommandProcess}, {kEventClassWindow, kEventWindowDrawContent}, {kEventClassWindow, kEventWindowUpdate}, }; SizeControl(mCarbonPane, 400, 400); InstallWindowEventHandler( GetCarbonWindow(), handlerUPP, sizeof(eventTypes) / sizeof(EventTypeSpec), eventTypes, this, NULL); RGBColor color1; color1.red = 65535; color1.green = 0; color1.blue = 0; gTrackers[0] = new TrackingLine(color1, (int)inXOffset, (int)inYOffset, 400, 400); RGBColor color2; color2.red = 0; color2.green = 65535; color2.blue = 0; gTrackers[1] = new TrackingLine(color2, (int)inXOffset, (int)inYOffset, 400, 400); RGBColor color3; color3.red = 0; color3.green = 0; color3.blue = 65535; gTrackers[2] = new TrackingLine(color3, (int)inXOffset, (int)inYOffset, 400, 400); RGBColor color4; color4.red = 20000; color4.green = 20000; color4.blue = 20000; gListener = new TrackingLine(color4, (int)inXOffset, (int)inYOffset, 400, 400); gListener->ScaleDistance(0.0); mOffsetX = (int)inXOffset; mOffsetY = (int)inYOffset; SetRenderingFlagsCheckboxes(); UInt32 algo; UInt32 size = sizeof(algo); AudioUnitGetProperty( GetEditAudioUnit(), kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, 0, &algo, &size ); SetRenderingAlgorithmControl(algo); mBackgroundColor.red = 50000; mBackgroundColor.green = 50000; mBackgroundColor.blue = 50000; TrackingLine::SetBackgroundColor(mBackgroundColor ); mIsTrackingMouse = false; EventLoopTimerUPP timerUPP = ::NewEventLoopTimerUPP(MixerTimerProc); //printf("timerUPP = %x\n", timerUPP ); EventLoopTimerRef timerRef; EventLoopRef mainEventLoop = GetMainEventLoop(); //printf("mainEventLoop = %x\n", mainEventLoop); //printf("this = %x\n", (int)this ); gAUMixer3DView = this; OSStatus timerResult = ::InstallEventLoopTimer( mainEventLoop, 0.005 /* delay */, 0.020 /* interval */, timerUPP, this, &timerRef ); //printf("timerResult = %d\n", timerResult ); //printf("timerRef = %x\n", timerRef ); return timerResult; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MyEventHandler // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OSStatus AUMixer3DView::MyEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent) { OSStatus result = noErr; UInt32 eventClass = GetEventClass(inEvent); UInt32 eventKind = GetEventKind(inEvent); // draw event if(eventClass == kEventClassWindow) { if(eventKind == kEventWindowDrawContent ) { Rect r = {mOffsetY, mOffsetX, mOffsetY + 400, mOffsetX + 400}; RGBForeColor(&mBackgroundColor ); PaintRect(&r); for(int i = 0; i < kNTrackers; i++) { gTrackers[i]->Draw(); } gListener->Draw(); return noErr; } } CGrafPtr gp = GetWindowPort(GetCarbonWindow()); CGrafPtr save; GetPort(&save); SetPort(gp ); const float kDistanceScale = 0.1 /*0.3*/; /* k3DMixerRenderingFlags_InterAuralDelay = (1L << 0), k3DMixerRenderingFlags_DopplerShift = (1L << 1), k3DMixerRenderingFlags_DistanceAttenuation = (1L << 2), k3DMixerRenderingFlags_DistanceFilter = (1L << 3), k3DMixerRenderingFlags_DistanceDiffusion = (1L << 4) */ if(eventClass == kEventClassCommand ) { HICommand command; GetEventParameter (inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &command); SInt16 value = ::GetControlValue((ControlRef)command.menu.menuRef ); //char *p = ((char*)&command.commandID ); //printf("%x command.commandID = %d : %d : %c%c%c%c\n", command.menu.menuRef, command.commandID, int(value), p[0],p[1],p[2],p[3] ); if(command.commandID == 'algo' ) { // set rendering algorithm UInt32 algo = value - 1; for(int i = 0; i < kNTrackers; i++) { AudioUnitSetProperty( GetEditAudioUnit(), kAudioUnitProperty_SpatializationAlgorithm, kAudioUnitScope_Input, i, &algo, sizeof(algo) ); } // rendering flags have changed with setting of rendering algorithm SetRenderingFlagsCheckboxes(); } else if(command.commandID == 'volm' ) { Float32 s = float(value) / 100.0; s = s*s; if(s == 0.0) { s = -96.0; } else { s = 20.0 * log10(s); } //printf("volume = %f dB\n", s); // set master gain in dB AudioUnitSetParameter(GetEditAudioUnit(), k3DMixerParam_Gain, kAudioUnitScope_Output, 0, s, 0 ); } else if(command.commandID == 'attn' ) { // volume attenuation curve Float64 s = float(value) / 100.0; //printf("volume atten curve= %f\n", s); // volume attenuation curve follows the law: 1.0 / (1.0 + s *(distance - 1.0) ) // // where distance is in meters, and s is generally between 0.1 and 1.0 (0.3 is good default) // // there is no attenuation if distance <= 1.0 meter for(int i = 0; i < kNTrackers; i++) { result = AudioUnitSetProperty( GetEditAudioUnit(), kAudioUnitProperty_3DMixerDistanceAtten, kAudioUnitScope_Input, i, &s, sizeof(s) ); } } else { UInt32 mask = 0; switch(command.commandID ) { case 'atr0': mask = k3DMixerRenderingFlags_InterAuralDelay; break; case 'atr1': mask = k3DMixerRenderingFlags_DopplerShift; break; case 'atr2': mask = k3DMixerRenderingFlags_DistanceAttenuation; break; case 'atr3': mask = k3DMixerRenderingFlags_DistanceFilter; break; case 'atr4': mask = k3DMixerRenderingFlags_DistanceDiffusion; break; case 'rvrb': { UInt32 usesReverb = value; AudioUnitSetProperty( GetEditAudioUnit(), kAudioUnitProperty_UsesInternalReverb, kAudioUnitScope_Input, 0, &usesReverb, sizeof(usesReverb) ); break; } } if(mask != 0) { for(int i = 0; i < kNTrackers; i++) { UInt32 flags; UInt32 size = sizeof(flags); AudioUnitGetProperty( GetEditAudioUnit(), kAudioUnitProperty_3DMixerRenderingFlags, kAudioUnitScope_Input, i, &flags, &size ); if(value > 0) { flags |= mask; } else { flags &= ~mask; } AudioUnitSetProperty( GetEditAudioUnit(), kAudioUnitProperty_3DMixerRenderingFlags, kAudioUnitScope_Input, i, &flags, size ); } return noErr; } } return eventNotHandledErr; } else if(eventClass == kEventClassMouse ) { HIPoint mousePos; result = GetEventParameter( inEvent, kEventParamMouseLocation, typeHIPoint, NULL, /* can be NULL */ sizeof(HIPoint), NULL, /* can be NULL */ &mousePos); UInt32 modifiers; result = GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, NULL, /* can be NULL */ sizeof(UInt32), NULL, /* can be NULL */ &modifiers); Point pt; pt.h = short(mousePos.x); pt.v = short(mousePos.y); Rect r2 = GetPortBitMapForCopyBits(gp)->bounds; GlobalToLocal(&pt); pt.h -= mOffsetX; pt.v -= mOffsetY; if(!mIsTrackingMouse && (pt.h < 0 || pt.v < 0) ) return eventNotHandledErr; // check for title bar if(pt.v < 0 && pt.v > -30 ) { return eventNotHandledErr; } Rect r1; GetPortBounds(gp, &r1 ); //int width = r1.right-r1.left; //int height = r1.bottom-r1.top; //!!@ hardcoded int width = 400; int height = 400; int centerx = int(0.5*width); int centery = int(0.5*height); static int currentLine = 0; float x = pt.h - centerx; float y = -(pt.v - centery); float rangle = atan2(x,y); float angle = 180.0 * rangle / 3.14159; static int hitx = 0; static int hity = 0; static float hitAngle = 0.0; switch(eventKind) { case kEventMouseDown: { mIsTrackingMouse = true; // determine the closest source float bestDistance = 100000.0; int bestIndex = 0; for(int i = 0; i < kNTrackers; i++) { if(gTrackers[i]->Distance(pt.h, pt.v) < bestDistance ) { bestIndex = i; bestDistance = gTrackers[i]->Distance(pt.h, pt.v); } } if(modifiers & (1L << shiftKeyBit)) { Float32 gain; AudioUnitGetParameter(GetEditAudioUnit(), k3DMixerParam_Gain, kAudioUnitScope_Input, bestIndex, &gain); if (gain > -120) gain = -120; else gain = 0; AudioUnitSetParameter(GetEditAudioUnit(), k3DMixerParam_Gain, kAudioUnitScope_Input, bestIndex, gain, 0); } currentLine = bestIndex; SetInput(currentLine); for(int i = 0; i < kNTrackers; i++) { if(i != currentLine) gTrackers[i]->Draw(); gTrackers[i]->Anchor(); } hitx = (int)x; hity = (int)y; hitAngle = angle; } case kEventMouseDragged: { if(modifiers & (1L << optionKeyBit) ) { for(int i = 0; i < kNTrackers; i++) { float newAngle = gTrackers[i]->Rotate(angle - hitAngle ); AudioUnitSetParameter(GetEditAudioUnit(), 0 /* azimuth */, kAudioUnitScope_Input, i, newAngle, 0 ); } gListener->Draw(); } else if(modifiers & (1L << cmdKeyBit) ) { for(int i = 0; i < kNTrackers; i++) { float angle; float pixelDistance; gTrackers[i]->Offset(x-hitx, -(y-hity), angle, pixelDistance ); float distance = kDistanceScale * pixelDistance; AudioUnitSetParameter(GetEditAudioUnit(), 0 /* azimuth */, kAudioUnitScope_Input, i, angle, 0 ); AudioUnitSetParameter(GetEditAudioUnit(), 2 /* distance */, kAudioUnitScope_Input, i, distance, 0 ); } gListener->Draw(); } else { TrackingLine *trackingLine = gTrackers[currentLine]; if(trackingLine) { trackingLine->Track(pt.h, pt.v); for(int i = 0; i < kNTrackers; i++) { if(i != currentLine) gTrackers[i]->Draw(); gTrackers[i]->Anchor(); } gListener->Draw(); } AudioUnitSetParameter(GetEditAudioUnit(), 0 /* azimuth */, kAudioUnitScope_Input, currentLine, angle, 0 ); float distance = kDistanceScale * sqrt( x*x + y*y); AudioUnitSetParameter(GetEditAudioUnit(), 2 /* distance */, kAudioUnitScope_Input, currentLine, distance, 0 ); } break; } case kEventMouseUp: mIsTrackingMouse = false; break; } SetPort(save); return noErr; } else { UInt8 keyCode; result = GetEventParameter( inEvent, kEventParamKeyMacCharCodes, typeChar, NULL, /* can be NULL */ sizeof(UInt8), NULL, /* can be NULL */ &keyCode); #if 1 switch(keyCode) { case 'q': SetFileInput(0); break; case 'w': SetFileInput(1); break; case 'e': SetFileInput(2); break; case 'r': SetFileInput(3); break; case 't': SetFileInput(4); break; case 'y': SetFileInput(5); break; case 'u': SetFileInput(6); break; case 'i': SetFileInput(7); break; case 'o': SetFileInput(8); break; case 'p': SetFileInput(9); break; case 'a': SetFileInput(10); break; case 's': SetFileInput(11); break; case 'd': SetFileInput(12); break; default: break; } #endif SetPort(save); return noErr; } return eventNotHandledErr; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // AURenderQualityPopup::AURenderQualityPopup // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AURenderQualityPopup::AURenderQualityPopup (AUCarbonViewBase *inBase, Point inLocation, int inRightEdge, ControlFontStyleRec & inFontStyle) : AUPropertyControl (inBase) { Rect r; r.top = inLocation.v; r.bottom = r.top + 17; r.left = inLocation.h; r.right = r.left + inRightEdge; ControlFontStyleRec fontStyle = inFontStyle; inFontStyle.just = teFlushRight; ControlRef ref; CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.audio.units.Components")); if (mainBundle != NULL) { CFMutableStringRef renderTitle = CFStringCreateMutable(NULL, 0); CFStringAppend(renderTitle, CFCopyLocalizedStringFromTableInBundle( CFSTR("Render Quality"), CFSTR("CustomUI"), mainBundle, CFSTR("The Render Quality Popup menu title"))); CFStringAppend(renderTitle, CFSTR(":")); OSErr theErr = CreateStaticTextControl (GetCarbonWindow(), &r, renderTitle, &inFontStyle, &ref); if (theErr == noErr) EmbedControl(ref); r.left = r.right + 8; r.right = r.left + 100; short bundleRef = CFBundleOpenBundleResourceMap (mainBundle); theErr = CreatePopupButtonControl (mView->GetCarbonWindow(), &r, NULL, /*kQualityMenuID*/ -12345, false, -1, 0, 0, &mControl); MenuRef menuRef; verify_noerr(CreateNewMenu(kQualityMenuID, 0, &menuRef)); verify_noerr(AppendMenuItemTextWithCFString (menuRef, CFCopyLocalizedStringFromTableInBundle(CFSTR("Maximum"), CFSTR("CustomUI"), mainBundle, CFSTR("")), 0, kChangeRenderQualityCmd, 0)); verify_noerr(AppendMenuItemTextWithCFString (menuRef, CFCopyLocalizedStringFromTableInBundle(CFSTR("High"), CFSTR("CustomUI"), mainBundle, CFSTR("")), 0, kChangeRenderQualityCmd, 0)); verify_noerr(AppendMenuItemTextWithCFString (menuRef, CFCopyLocalizedStringFromTableInBundle(CFSTR("Medium"), CFSTR("CustomUI"), mainBundle, CFSTR("")), 0, kChangeRenderQualityCmd, 0)); verify_noerr(AppendMenuItemTextWithCFString (menuRef, CFCopyLocalizedStringFromTableInBundle(CFSTR("Low"), CFSTR("CustomUI"), mainBundle, CFSTR("")), 0, kChangeRenderQualityCmd, 0)); verify_noerr(AppendMenuItemTextWithCFString (menuRef, CFCopyLocalizedStringFromTableInBundle(CFSTR("Minimum"), CFSTR("CustomUI"), mainBundle, CFSTR("")), 0, kChangeRenderQualityCmd, 0)); verify_noerr(SetControlData(mControl, 0, kControlPopupButtonMenuRefTag, sizeof(menuRef), &menuRef)); verify_noerr(SetControlFontStyle (mControl, &inFontStyle)); SetControl32BitMaximum(mControl, 5); UInt32 renderQuality; UInt32 size = sizeof(UInt32); AudioUnitGetProperty (mView->GetEditAudioUnit(), kAudioUnitProperty_RenderQuality, kAudioUnitScope_Global, 0, &renderQuality, &size); HandlePropertyChange(renderQuality); EmbedControl(mControl); theErr = AudioUnitAddPropertyListener(mView->GetEditAudioUnit(), kAudioUnitProperty_RenderQuality, RenderQualityListener, this); CFBundleCloseBundleResourceMap (mainBundle, bundleRef); CFRelease(renderTitle); } RegisterEvents(); }