修订版 | 26 (tree) |
---|---|
时间 | 2012-08-15 13:05:46 |
作者 | toshinagata1964 |
Update Audio/MIDI Info menu command is implemented. The Audio settings window is improved.
@@ -34,6 +34,7 @@ | ||
34 | 34 | - (IBAction)openAudioSettingsPanel: (id)sender; |
35 | 35 | - (IBAction)openMetronomeSettingsPanel: (id)sender; |
36 | 36 | - (IBAction)openAboutWindow:(id)sender; |
37 | +- (IBAction)updateAudioAndMIDISettings:(id)sender; | |
37 | 38 | - (id)documentAtIndex: (int)idx; |
38 | 39 | |
39 | 40 | - (void)getRubyVersion:(NSString **)outVersion copyright:(NSString **)outCopyright; |
@@ -272,6 +272,12 @@ | ||
272 | 272 | [AboutWindowController showModalAboutWindow]; |
273 | 273 | } |
274 | 274 | |
275 | +- (IBAction)updateAudioAndMIDISettings:(id)sender | |
276 | +{ | |
277 | + MDAudioUpdateDeviceInfo(); | |
278 | + MDPlayerReloadDeviceInformation(); | |
279 | +} | |
280 | + | |
275 | 281 | - (BOOL)validateUserInterfaceItem: (id)anItem |
276 | 282 | { |
277 | 283 | SEL sel = [anItem action]; |
@@ -20,9 +20,11 @@ | ||
20 | 20 | |
21 | 21 | @interface AudioSettingsPanelController : NSWindowController { |
22 | 22 | NSTimer *timer; /* Refresh the display periodically during playing */ |
23 | + NSMutableArray *knobValues; /* The current knob values */ | |
23 | 24 | } |
24 | 25 | + (void)openAudioSettingsPanel; |
25 | 26 | - (void)updateDisplay; |
27 | +- (void)timerCallback:(NSTimer *)timer; | |
26 | 28 | - (IBAction)myPopUpAction:(id)sender; |
27 | 29 | - (IBAction)volumeSliderMoved:(id)sender; |
28 | 30 | - (IBAction)panKnobMoved:(id)sender; |
@@ -43,6 +43,8 @@ | ||
43 | 43 | sharedAudioSettingsPanelController = [[AudioSettingsPanelController alloc] initWithWindowNibName: @"AudioSettingsPanel"]; |
44 | 44 | } |
45 | 45 | [[sharedAudioSettingsPanelController window] makeKeyAndOrderFront: nil]; |
46 | + [sharedAudioSettingsPanelController updateDisplay]; | |
47 | + [sharedAudioSettingsPanelController timerCallback:nil]; | |
46 | 48 | } |
47 | 49 | |
48 | 50 | - (void)updateDisplay |
@@ -51,7 +53,12 @@ | ||
51 | 53 | NSMenu *menu; |
52 | 54 | MDAudioDeviceInfo *dp; |
53 | 55 | MDAudioMusicDeviceInfo *mp; |
54 | - | |
56 | + if (knobValues == nil) { | |
57 | + knobValues = [[NSMutableArray arrayWithCapacity:kMDAudioNumberOfStreams] retain]; | |
58 | + for (idx = 0; idx < kMDAudioNumberOfStreams; idx++) { | |
59 | + [knobValues addObject:[NSNumber numberWithFloat:0.0]]; | |
60 | + } | |
61 | + } | |
55 | 62 | for (idx = 0; idx < kMDAudioNumberOfStreams; idx++) { |
56 | 63 | id view; |
57 | 64 | int tagOffset; |
@@ -143,7 +150,9 @@ | ||
143 | 150 | ampRight = 100.0; |
144 | 151 | if (ampRight < 0.0) |
145 | 152 | ampRight = 0.0; |
146 | - [[self viewWithTag: kPanKnobBase + tagOffset] setFloatValue: pan * 100.0]; | |
153 | + /* The pan slider uses 60-100 (for 0 to 0.5) and 0-40 (for 0.5 to 1.0) */ | |
154 | + [[self viewWithTag: kPanKnobBase + tagOffset] setFloatValue: (pan - 0.5) * 80 + (pan < 0.5 ? 100 : 0)]; | |
155 | + [knobValues replaceObjectAtIndex:idx withObject:[NSNumber numberWithFloat:pan]]; | |
147 | 156 | [[self viewWithTag: kVolumeSliderBase + tagOffset] setFloatValue: volume * 100.0]; |
148 | 157 | [[self viewWithTag: kLeftLevelIndicatorBase + tagOffset] setFloatValue: ampLeft]; |
149 | 158 | [[self viewWithTag: kRightLevelIndicatorBase + tagOffset] setFloatValue: ampRight]; |
@@ -169,10 +178,20 @@ | ||
169 | 178 | } |
170 | 179 | - (IBAction)panKnobMoved:(id)sender |
171 | 180 | { |
181 | + float pan, opan; | |
172 | 182 | int idx = [sender tag] - kPanKnobBase; |
173 | 183 | if (idx >= kOutputTagOffset) |
174 | 184 | idx += (kMDAudioFirstIndexForOutputStream - kOutputTagOffset); |
175 | - MDAudioSetMixerPan(idx, [sender floatValue] * 0.01); | |
185 | + pan = [sender floatValue]; | |
186 | + pan = (pan >= 50.0 ? pan - 100.0 : pan) / 80.0 + 0.5; | |
187 | + opan = [[knobValues objectAtIndex:idx] floatValue]; | |
188 | + if (pan < 0.0 || pan > 1.0 || (opan < 0.25 && pan > 0.75) || (opan > 0.75 && pan < 0.25)) { | |
189 | + /* Do not change value */ | |
190 | + [sender setFloatValue:(opan - 0.5) * 80 + (opan < 0.5 ? 100 : 0)]; | |
191 | + return; | |
192 | + } | |
193 | + [knobValues replaceObjectAtIndex:idx withObject:[NSNumber numberWithFloat:pan]]; | |
194 | + MDAudioSetMixerPan(idx, pan); | |
176 | 195 | } |
177 | 196 | |
178 | 197 | - (IBAction)myPopUpAction: (id)sender |
@@ -405,9 +405,9 @@ | ||
405 | 405 | Component cmp = NULL; |
406 | 406 | Handle pName; |
407 | 407 | char *cName; |
408 | - int len, n; | |
408 | + int len, n, i; | |
409 | 409 | UInt32 propSize; |
410 | - MDAudioMusicDeviceInfo info; | |
410 | + MDAudioMusicDeviceInfo info, *ip; | |
411 | 411 | OSStatus err; |
412 | 412 | MDStatus status = kMDNoError; |
413 | 413 |
@@ -436,6 +436,15 @@ | ||
436 | 436 | strncpy(info.name, cName, len); |
437 | 437 | info.name[len] = 0; |
438 | 438 | HUnlock(pName); |
439 | + for (i = 0; (ip = MDArrayFetchPtr(gAudio->musicDeviceInfos, i)) != NULL; i++) { | |
440 | + if (ip->code == info.code && strncmp(ip->name, cName, len) == 0) { | |
441 | + free(info.name); | |
442 | + info.name = NULL; | |
443 | + break; | |
444 | + } | |
445 | + } | |
446 | + if (ip != NULL) | |
447 | + continue; /* This device is already known */ | |
439 | 448 | |
440 | 449 | MyAppCallback_startupMessage("Loading %s...", info.name); |
441 | 450 |
@@ -643,155 +652,153 @@ | ||
643 | 652 | dp = MDAudioDeviceInfoAtIndex(deviceIndex, 1); |
644 | 653 | newDeviceID = (dp != NULL ? (UInt64)(dp->deviceID) : kMDAudioMusicDeviceUnknown); |
645 | 654 | } |
646 | - if (ip->deviceID != newDeviceID) { | |
647 | - /* Disable the current input */ | |
648 | - if (ip->deviceID != kMDAudioMusicDeviceUnknown) { | |
649 | - if (ip->deviceIndex >= kMDAudioMusicDeviceIndexOffset) { | |
650 | - /* Music Device */ | |
651 | - CHECK_ERR(result, AUGraphDisconnectNodeInput(gAudio->graph, ip->converterNode, 0)); | |
652 | - CHECK_ERR(result, AUGraphDisconnectNodeInput(gAudio->graph, gAudio->mixer, idx)); | |
653 | - CHECK_ERR(result, AUGraphRemoveNode(gAudio->graph, ip->converterNode)); | |
654 | - CHECK_ERR(result, AUGraphRemoveNode(gAudio->graph, ip->node)); | |
655 | - /* It looks like the component is automatically closed when the AUNode is removed */ | |
656 | - /* CHECK_ERR(result, (OSStatus)CloseComponent(ip->unit)); */ | |
657 | - ip->node = ip->converterNode = 0; | |
658 | - ip->unit = ip->converterUnit = NULL; | |
659 | - if (ip->midiControllerName != NULL) { | |
660 | - free(ip->midiControllerName); | |
661 | - ip->midiControllerName = NULL; | |
662 | - } | |
663 | - if (ip->midiCon != NULL) { | |
664 | - CHECK_ERR(result, AUMIDIControllerDispose(ip->midiCon)); | |
665 | - ip->midiCon = NULL; | |
666 | - } | |
667 | - if (ip->bufferList != NULL) { | |
668 | - sMDAudioReleaseMyBufferList(ip->bufferList); | |
669 | - ip->bufferList = NULL; | |
670 | - } | |
671 | - if (ip->ring != NULL) { | |
672 | - MDRingBufferDeallocate(ip->ring); | |
673 | - ip->ring = NULL; | |
674 | - } | |
675 | - midiSetupChanged = 1; | |
676 | - } else { | |
677 | - /* Audio Device */ | |
678 | - /* Disable callback for the mixer input */ | |
679 | - callback.inputProc = NULL; | |
680 | - callback.inputProcRefCon = NULL; | |
681 | - CHECK_ERR(result, AudioUnitSetProperty(gAudio->mixerUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, idx, &callback, sizeof(AURenderCallbackStruct))); | |
682 | - /* Dispose the input AudioUnit */ | |
683 | - CHECK_ERR(result, (OSStatus)CloseComponent(ip->unit)); | |
655 | + /* Disable the current input */ | |
656 | + if (ip->deviceID != kMDAudioMusicDeviceUnknown) { | |
657 | + if (ip->deviceIndex >= kMDAudioMusicDeviceIndexOffset) { | |
658 | + /* Music Device */ | |
659 | + CHECK_ERR(result, AUGraphDisconnectNodeInput(gAudio->graph, ip->converterNode, 0)); | |
660 | + CHECK_ERR(result, AUGraphDisconnectNodeInput(gAudio->graph, gAudio->mixer, idx)); | |
661 | + CHECK_ERR(result, AUGraphRemoveNode(gAudio->graph, ip->converterNode)); | |
662 | + CHECK_ERR(result, AUGraphRemoveNode(gAudio->graph, ip->node)); | |
663 | + /* It looks like the component is automatically closed when the AUNode is removed */ | |
664 | + /* CHECK_ERR(result, (OSStatus)CloseComponent(ip->unit)); */ | |
665 | + ip->node = ip->converterNode = 0; | |
666 | + ip->unit = ip->converterUnit = NULL; | |
667 | + if (ip->midiControllerName != NULL) { | |
668 | + free(ip->midiControllerName); | |
669 | + ip->midiControllerName = NULL; | |
684 | 670 | } |
685 | - ip->deviceID = kMDAudioMusicDeviceUnknown; | |
686 | - ip->node = 0; | |
687 | - ip->unit = NULL; | |
688 | - ip->deviceIndex = -1; | |
689 | - ip->busIndex = -1; | |
671 | + if (ip->midiCon != NULL) { | |
672 | + CHECK_ERR(result, AUMIDIControllerDispose(ip->midiCon)); | |
673 | + ip->midiCon = NULL; | |
674 | + } | |
675 | + if (ip->bufferList != NULL) { | |
676 | + sMDAudioReleaseMyBufferList(ip->bufferList); | |
677 | + ip->bufferList = NULL; | |
678 | + } | |
679 | + if (ip->ring != NULL) { | |
680 | + MDRingBufferDeallocate(ip->ring); | |
681 | + ip->ring = NULL; | |
682 | + } | |
683 | + midiSetupChanged = 1; | |
684 | + } else { | |
685 | + /* Audio Device */ | |
686 | + /* Disable callback for the mixer input */ | |
687 | + callback.inputProc = NULL; | |
688 | + callback.inputProcRefCon = NULL; | |
689 | + CHECK_ERR(result, AudioUnitSetProperty(gAudio->mixerUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, idx, &callback, sizeof(AURenderCallbackStruct))); | |
690 | + /* Dispose the input AudioUnit */ | |
691 | + CHECK_ERR(result, (OSStatus)CloseComponent(ip->unit)); | |
690 | 692 | } |
691 | - if (newDeviceID != kMDAudioMusicDeviceUnknown) { | |
692 | - /* Enable the new input */ | |
693 | - if (deviceIndex >= kMDAudioMusicDeviceIndexOffset) { | |
694 | - int i, n, len; | |
695 | - MDAudioIOStreamInfo *ip2; | |
696 | - CFStringRef str; | |
697 | - /* Music Device */ | |
698 | - /* Create input node */ | |
699 | - desc.componentType = kAudioUnitType_MusicDevice; | |
700 | - desc.componentSubType = (UInt32)(newDeviceID >> 32); | |
701 | - desc.componentManufacturer = (UInt32)(newDeviceID); | |
702 | - desc.componentFlags = desc.componentFlagsMask = 0; | |
703 | - CHECK_ERR(result, AUGraphNewNode(gAudio->graph, &desc, 0, NULL, &ip->node)); | |
704 | - /* Create converter */ | |
705 | - desc.componentType = kAudioUnitType_FormatConverter; | |
706 | - desc.componentSubType = kAudioUnitSubType_AUConverter; | |
707 | - desc.componentManufacturer = kAudioUnitManufacturer_Apple; | |
708 | - desc.componentFlags = desc.componentFlagsMask = 0; | |
709 | - CHECK_ERR(result, AUGraphNewNode(gAudio->graph, &desc, 0, NULL, &ip->converterNode)); | |
710 | - /* Connect input node -> converter -> mixer */ | |
711 | - CHECK_ERR(result, AUGraphOpen(gAudio->graph)); | |
712 | - CHECK_ERR(result, AUGraphConnectNodeInput(gAudio->graph, ip->node, 0, ip->converterNode, 0)); | |
713 | - CHECK_ERR(result, AUGraphConnectNodeInput(gAudio->graph, ip->converterNode, 0, gAudio->mixer, idx)); | |
714 | - ip->deviceID = newDeviceID; | |
715 | - CHECK_ERR(result, AUGraphGetNodeInfo(gAudio->graph, ip->node, NULL, NULL, NULL, &ip->unit)); | |
716 | - CHECK_ERR(result, AUGraphGetNodeInfo(gAudio->graph, ip->converterNode, NULL, NULL, NULL, &ip->converterUnit)); | |
717 | - /* Input and output audio format for the converter */ | |
718 | - CHECK_ERR(result, AudioUnitSetProperty(ip->converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &mp->format, sizeof(AudioStreamBasicDescription))); | |
719 | - CHECK_ERR(result, AudioUnitSetProperty(ip->converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &gAudio->preferredFormat, sizeof(AudioStreamBasicDescription))); | |
720 | - /* Create the MIDI controller */ | |
721 | - len = strlen(mp->name) + 5; | |
722 | - ip->midiControllerName = (char *)malloc(len); | |
723 | - strcpy(ip->midiControllerName, mp->name); | |
724 | - /* Check the duplicate */ | |
725 | - for (i = 0, n = 2; i < kMDAudioNumberOfInputStreams; i++) { | |
726 | - ip2 = MDAudioGetIOStreamInfoAtIndex(i); | |
727 | - if (ip == ip2 || ip2->midiControllerName == NULL) | |
728 | - continue; | |
729 | - if (strcmp(ip->midiControllerName, ip2->midiControllerName) == 0) { | |
730 | - snprintf(ip->midiControllerName, len, "%s %d", mp->name, n); | |
731 | - n++; | |
732 | - i = -1; | |
733 | - continue; | |
734 | - } | |
693 | + ip->deviceID = kMDAudioMusicDeviceUnknown; | |
694 | + ip->node = 0; | |
695 | + ip->unit = NULL; | |
696 | + ip->deviceIndex = -1; | |
697 | + ip->busIndex = -1; | |
698 | + } | |
699 | + if (newDeviceID != kMDAudioMusicDeviceUnknown) { | |
700 | + /* Enable the new input */ | |
701 | + if (deviceIndex >= kMDAudioMusicDeviceIndexOffset) { | |
702 | + int i, n, len; | |
703 | + MDAudioIOStreamInfo *ip2; | |
704 | + CFStringRef str; | |
705 | + /* Music Device */ | |
706 | + /* Create input node */ | |
707 | + desc.componentType = kAudioUnitType_MusicDevice; | |
708 | + desc.componentSubType = (UInt32)(newDeviceID >> 32); | |
709 | + desc.componentManufacturer = (UInt32)(newDeviceID); | |
710 | + desc.componentFlags = desc.componentFlagsMask = 0; | |
711 | + CHECK_ERR(result, AUGraphNewNode(gAudio->graph, &desc, 0, NULL, &ip->node)); | |
712 | + /* Create converter */ | |
713 | + desc.componentType = kAudioUnitType_FormatConverter; | |
714 | + desc.componentSubType = kAudioUnitSubType_AUConverter; | |
715 | + desc.componentManufacturer = kAudioUnitManufacturer_Apple; | |
716 | + desc.componentFlags = desc.componentFlagsMask = 0; | |
717 | + CHECK_ERR(result, AUGraphNewNode(gAudio->graph, &desc, 0, NULL, &ip->converterNode)); | |
718 | + /* Connect input node -> converter -> mixer */ | |
719 | + CHECK_ERR(result, AUGraphOpen(gAudio->graph)); | |
720 | + CHECK_ERR(result, AUGraphConnectNodeInput(gAudio->graph, ip->node, 0, ip->converterNode, 0)); | |
721 | + CHECK_ERR(result, AUGraphConnectNodeInput(gAudio->graph, ip->converterNode, 0, gAudio->mixer, idx)); | |
722 | + ip->deviceID = newDeviceID; | |
723 | + CHECK_ERR(result, AUGraphGetNodeInfo(gAudio->graph, ip->node, NULL, NULL, NULL, &ip->unit)); | |
724 | + CHECK_ERR(result, AUGraphGetNodeInfo(gAudio->graph, ip->converterNode, NULL, NULL, NULL, &ip->converterUnit)); | |
725 | + /* Input and output audio format for the converter */ | |
726 | + CHECK_ERR(result, AudioUnitSetProperty(ip->converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &mp->format, sizeof(AudioStreamBasicDescription))); | |
727 | + CHECK_ERR(result, AudioUnitSetProperty(ip->converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &gAudio->preferredFormat, sizeof(AudioStreamBasicDescription))); | |
728 | + /* Create the MIDI controller */ | |
729 | + len = strlen(mp->name) + 5; | |
730 | + ip->midiControllerName = (char *)malloc(len); | |
731 | + strcpy(ip->midiControllerName, mp->name); | |
732 | + /* Check the duplicate */ | |
733 | + for (i = 0, n = 2; i < kMDAudioNumberOfInputStreams; i++) { | |
734 | + ip2 = MDAudioGetIOStreamInfoAtIndex(i); | |
735 | + if (ip == ip2 || ip2->midiControllerName == NULL) | |
736 | + continue; | |
737 | + if (strcmp(ip->midiControllerName, ip2->midiControllerName) == 0) { | |
738 | + snprintf(ip->midiControllerName, len, "%s %d", mp->name, n); | |
739 | + n++; | |
740 | + i = -1; | |
741 | + continue; | |
735 | 742 | } |
736 | - str = CFStringCreateWithCString(NULL, ip->midiControllerName, kCFStringEncodingUTF8); | |
737 | - result = AUMIDIControllerCreate(str, &ip->midiCon); | |
738 | - if (result == noErr) { | |
739 | - result = AUMIDIControllerMapChannelToAU(ip->midiCon, -1, ip->unit, -1, 0); | |
740 | - } | |
741 | - CFRelease(str); | |
742 | - midiSetupChanged = 1; | |
743 | - } else { | |
744 | - /* Audio Device */ | |
745 | - /* Create HAL input unit (not connected to AUGraph) */ | |
746 | - /* Cf. Apple Technical Note 2091 */ | |
747 | - Component comp; | |
748 | - UInt32 unum; | |
749 | - AURenderCallbackStruct callback; | |
750 | - desc.componentType = kAudioUnitType_Output; | |
751 | - desc.componentSubType = kAudioUnitSubType_HALOutput; | |
752 | - desc.componentManufacturer = kAudioUnitManufacturer_Apple; | |
753 | - desc.componentFlags = 0; | |
754 | - desc.componentFlagsMask = 0; | |
755 | - comp = FindNextComponent(NULL, &desc); | |
756 | - if (comp == NULL) | |
757 | - return kMDErrorCannotSetupAudio; | |
758 | - CHECK_ERR(result, OpenAComponent(comp, &ip->unit)); | |
759 | - /* Enable input */ | |
760 | - unum = 1; | |
761 | - CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &unum, sizeof(UInt32))); | |
762 | - /* Disable output */ | |
763 | - unum = 0; | |
764 | - CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &unum, sizeof(UInt32))); | |
765 | - /* Set the HAL AU output format to the canonical format */ | |
766 | - CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &gAudio->preferredFormat, sizeof(AudioStreamBasicDescription))); | |
767 | - /* Set the AU callback function (HAL input device) */ | |
768 | - callback.inputProc = sMDAudioInputProc; | |
769 | - callback.inputProcRefCon = ip; | |
770 | - CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(AURenderCallbackStruct))); | |
771 | - /* Set the AU callback function (mixer) */ | |
772 | - callback.inputProc = sMDAudioPassProc; | |
773 | - callback.inputProcRefCon = ip; | |
774 | - CHECK_ERR(result, AudioUnitSetProperty(gAudio->mixerUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, idx, &callback, sizeof(AURenderCallbackStruct))); | |
775 | - /* Set the input device */ | |
776 | - audioDeviceID = (AudioDeviceID)newDeviceID; | |
777 | - CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &audioDeviceID, sizeof(AudioDeviceID))); | |
778 | - /* Reallocate buffer list */ | |
779 | - ip->bufferSizeFrames = dp->bufferSizeFrames; /* The buffer size of the underlying audio device; NOTE: dp must be alive until here! */ | |
780 | - ip->bufferList = sMDAudioAllocateMyBufferList(gAudio->preferredFormat.mChannelsPerFrame, gAudio->preferredFormat.mBytesPerFrame, ip->bufferSizeFrames); | |
781 | - | |
782 | - /* Reallocate ring buffer */ | |
783 | - ip->ring = MDRingBufferNew(); | |
784 | - MDRingBufferAllocate(ip->ring, gAudio->preferredFormat.mChannelsPerFrame, gAudio->preferredFormat.mBytesPerFrame, ip->bufferSizeFrames * 20); | |
785 | - | |
786 | - ip->firstInputTime = ip->firstOutputTime = -1; | |
787 | - /* Initialize and start the AUHAL */ | |
788 | - CHECK_ERR(result, AudioUnitInitialize(ip->unit)); | |
789 | - CHECK_ERR(result, AudioOutputUnitStart(ip->unit)); | |
790 | 743 | } |
791 | - ip->deviceID = newDeviceID; | |
792 | - ip->deviceIndex = deviceIndex; | |
793 | - ip->busIndex = (idx % kMDAudioNumberOfOutputStreams); | |
744 | + str = CFStringCreateWithCString(NULL, ip->midiControllerName, kCFStringEncodingUTF8); | |
745 | + result = AUMIDIControllerCreate(str, &ip->midiCon); | |
746 | + if (result == noErr) { | |
747 | + result = AUMIDIControllerMapChannelToAU(ip->midiCon, -1, ip->unit, -1, 0); | |
748 | + } | |
749 | + CFRelease(str); | |
750 | + midiSetupChanged = 1; | |
751 | + } else { | |
752 | + /* Audio Device */ | |
753 | + /* Create HAL input unit (not connected to AUGraph) */ | |
754 | + /* Cf. Apple Technical Note 2091 */ | |
755 | + Component comp; | |
756 | + UInt32 unum; | |
757 | + AURenderCallbackStruct callback; | |
758 | + desc.componentType = kAudioUnitType_Output; | |
759 | + desc.componentSubType = kAudioUnitSubType_HALOutput; | |
760 | + desc.componentManufacturer = kAudioUnitManufacturer_Apple; | |
761 | + desc.componentFlags = 0; | |
762 | + desc.componentFlagsMask = 0; | |
763 | + comp = FindNextComponent(NULL, &desc); | |
764 | + if (comp == NULL) | |
765 | + return kMDErrorCannotSetupAudio; | |
766 | + CHECK_ERR(result, OpenAComponent(comp, &ip->unit)); | |
767 | + /* Enable input */ | |
768 | + unum = 1; | |
769 | + CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &unum, sizeof(UInt32))); | |
770 | + /* Disable output */ | |
771 | + unum = 0; | |
772 | + CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &unum, sizeof(UInt32))); | |
773 | + /* Set the HAL AU output format to the canonical format */ | |
774 | + CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &gAudio->preferredFormat, sizeof(AudioStreamBasicDescription))); | |
775 | + /* Set the AU callback function (HAL input device) */ | |
776 | + callback.inputProc = sMDAudioInputProc; | |
777 | + callback.inputProcRefCon = ip; | |
778 | + CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(AURenderCallbackStruct))); | |
779 | + /* Set the AU callback function (mixer) */ | |
780 | + callback.inputProc = sMDAudioPassProc; | |
781 | + callback.inputProcRefCon = ip; | |
782 | + CHECK_ERR(result, AudioUnitSetProperty(gAudio->mixerUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, idx, &callback, sizeof(AURenderCallbackStruct))); | |
783 | + /* Set the input device */ | |
784 | + audioDeviceID = (AudioDeviceID)newDeviceID; | |
785 | + CHECK_ERR(result, AudioUnitSetProperty(ip->unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &audioDeviceID, sizeof(AudioDeviceID))); | |
786 | + /* Reallocate buffer list */ | |
787 | + ip->bufferSizeFrames = dp->bufferSizeFrames; /* The buffer size of the underlying audio device; NOTE: dp must be alive until here! */ | |
788 | + ip->bufferList = sMDAudioAllocateMyBufferList(gAudio->preferredFormat.mChannelsPerFrame, gAudio->preferredFormat.mBytesPerFrame, ip->bufferSizeFrames); | |
789 | + | |
790 | + /* Reallocate ring buffer */ | |
791 | + ip->ring = MDRingBufferNew(); | |
792 | + MDRingBufferAllocate(ip->ring, gAudio->preferredFormat.mChannelsPerFrame, gAudio->preferredFormat.mBytesPerFrame, ip->bufferSizeFrames * 20); | |
793 | + | |
794 | + ip->firstInputTime = ip->firstOutputTime = -1; | |
795 | + /* Initialize and start the AUHAL */ | |
796 | + CHECK_ERR(result, AudioUnitInitialize(ip->unit)); | |
797 | + CHECK_ERR(result, AudioOutputUnitStart(ip->unit)); | |
794 | 798 | } |
799 | + ip->deviceID = newDeviceID; | |
800 | + ip->deviceIndex = deviceIndex; | |
801 | + ip->busIndex = (idx % kMDAudioNumberOfOutputStreams); | |
795 | 802 | } |
796 | 803 | } |
797 | 804 | exit: |