ããã«ã¡ã¯ï¼é³å£°ä¿¡å·å¦çã¨ã³ã¸ãã¢ã® kaede-san ã§ãã
ç§äºã§ãããå æ¥ãæ°åã³ããã¦ã¤ã«ã¹ã®ã¯ã¯ãã³ãæã¡ã¾ãã¦ãããæ°æ¥å¯åå¿ã«è¦èããã¦ãããæ´æ°ãé ããªã£ã¦ãã¾ãã¾ããðââï¸
ä»åã¯ãMTAudioProcessingTapã使ã£ã¦ãAVPlayerã§ãªã¼ãã£ãªãã¼ã¿ãåå¾ããæ¹æ³ãç´¹ä»ãã¾ãï¼
- MTAudioProcessingTapã¨ã¯
- ãªããã®æè¡ãæ¡ç¨ããã
- æ´»ç¨ä¾
- å®è£ ä¾
- 課é¡
- 注æ
- ã¾ã¨ã
MTAudioProcessingTapã¨ã¯
Swiftã§ã¯MTAudioProcessingTapãObjective-Cï¼å³å¯ã«ã¯Cè¨èªï¼ã§ã¯MTAudioProcessingTapRefã¨ãã¦å®ç¾©ããã¦ãã¾ãã
å ¬å¼ããã¥ã¡ã³ãã§ã¯ä»¥ä¸ã®ããã«èª¬æãæ¸ããã¦ãã¾ãã
You can use the audio tap to access the trackâs audio data before it is played, read, or exported.
ç°¡åã«è¨³ãã¨ããªã¼ãã£ãªãã¼ã¿ãåçã»èªã¿åãã»ã¨ã¯ã¹ãã¼ãåã«èªã¿åããã¨ãã§ãããï¼ãã¨ã®ãã¨ã§ãã
AVAudioEngineã使ã£ããã¨ããæ¹ã¯ãåç¥ãã¨æãã¾ãããAVAudioEngineã«ã¯installTapã¨ããæ©è½ãããã¾ããï¼ãã®æ©è½ã¨èãæ¹ã¯ã»ã¼åãã§ãã
ã¾ããå é¨çã«AudioUnitãç¹ãã§ãåçãããé³æºã«ãªãã¼ããã¤ã³ã©ã¤ã¶ã¼ãªã©ã®ã¨ãã§ã¯ããããã¦å å·¥ãããã¨ãã§ãã¾ãã
ãªããã®æè¡ãæ¡ç¨ããã
ç®çã¯ããnanaã®åçç»é¢ã§ãã¸ã¥ã¢ã©ã¤ã¶ã¼ã表示ãããã¨ãã§ãã
ãã¸ã¥ã¢ã©ã¤ã¶ã¼ã¨ã¯ãé³æ¥½ã«åããã¦ããããããããåãã¢ã¬ã®ãã¨ã§ããããªã¼ãã£ãªã¹ãã¯ãã©ã ãã¨å¼ã°ãããã¨ãããã¾ãã
ã¿ãªãããä¸çªããç®ã«ãã¦ããã®ã¯ãé³æ¥½ã®å¨æ³¢æ°ã«åããã¦åããã¸ã¥ã¢ã©ã¤ã¶ã¼ã§ã¯ãªãã§ããããã
nanaã§ããå¨æ³¢æ°ã«å¿ãã¦ããããåãããã«ãªã£ã¦ãã¾ãã
é³æ¥½ãæµãã¦ããªã¢ã«ã¿ã¤ã ã§ãã¸ã¥ã¢ã©ã¤ã¶ã¼ãåããã«ã¯ããã®é³æ¥½ã®ãªã¼ãã£ãªãã¼ã¿ãåãåºãå¿ è¦ãããã¾ãã
iOSçnanaã§ã¯ãé³æºã®åçã«AVPlayerã使ã£ã¦ãããAVPlayerã§ãªã¼ãã£ãªãã¼ã¿ãåãåºãæ¹æ³ã«ã¤ãã¦èª¿ã¹ãã¨ãããMTAudioProcessingTapã使ãããï¼ã¨ããããããããæ¹æ³ããªãããï¼ãã¨ãããã¨ãåããã¾ããã
ããããå ¬å¼ã®ãµã³ãã«ã³ã¼ãï¼ä¸è¨åç §ï¼ä»¥å¤ãåèã«ã§ããããªæ å ±ãã³ã¼ãããªãããµã³ãã«ã³ã¼ããåèã«å®è£ ãã¦ã¿ãçµæãè¦äºæ³å®éãã«ãªã¼ãã£ãªã®ãã¼ã¿ãåãåºããã¨ãã§ããæ¡ç¨ã«è³ãã¾ããã
æ´»ç¨ä¾
nanaã§ã¯ãã¸ã¥ã¢ã©ã¤ã¶ã¼ç¨éã§MTAudioProcessingTapã使ã£ã¦ãã¾ããããã以å¤ã«ãæ§ã ãªç¨éãããã¾ãã
åºæ¬çãªç¨éã ã¨ã
- ã¬ãã«ã¡ã¼ã¿ã¼ï¼é³éã®å¯è¦åï¼
- SFSpeechRecognizerã¨é£æºããã¦é³å£°èªè
- AudioUnitã使ã£ã¦åçãããé³ãå å·¥ããï¼æ¹æ³ã¯å¾è¿°ï¼
ãªã©ãæãããã¾ãã
å¿ç¨çã«ã¯ããªã¼ãã£ãªãã¼ã¿ã解æãã¦ã§ãããã¨ã¯ãªãã§ãã§ããã®ã§ãä¾ãã°æ¥½æ²ã®ãã¼ã»ã³ã¼ãã»é³ç¨ã®æ¤åºãªã©ãããããªãã¨ã«ä½¿ãããã§ããï¼
å®è£ ä¾
å®è£ ã§ã¯ããã¡ãã®å ¬å¼ã®ãµã³ãã«ã³ã¼ãã大å¤åèã«ãªãã¾ããã
ãã ãããªãå¤ããä¸èº«ã¯Objective-Cã§æ¸ããã¦ãã¾ããå¤ããã¦ãã®ã¾ã¾ã§ã¯ããã¸ã§ã¯ãã®ãã«ãã«å¤±æããã®ã§ãstoryboardã®ãã«ããã¼ã¸ã§ã³ãå¤ããããé©åãªmovieURLãè¨å®ãã¦ããããããå¿ è¦ãããã¾ãã
https://developer.apple.com/library/archive/samplecode/AudioTapProcessor/Introduction/Intro.html
AVAudioEngineã§ã¯AVAudioPCMBufferãç¨æããã¦ãã¾ãããAVPlayerã§ã¯ãã®MTAudioProcessingTapã使ã£ã¦ãAudioBufferListãåãåºããã¨ãã§ãã¾ãã
å¼ã³åºãå ã®AVPlayerã¯ã©ã¹
ä¸ã®ãµã³ãã«ã³ã¼ãã¯Objective-Cã§ãããSwiftã§æ¸ãã¨ãããªæãã«ãã£ããæ¸ãã¾ãã
â»å®è¡ç°å¢: Xcode 12.5ã»Swift 5.4
let player = AVPlayer(url: soundURL) // ãã¸ã¥ã¢ã©ã¤ã¶ã¼ã®æºå if let track = player.currentItem?.asset.tracks(withMediaType: .audio).first { visualizer.audioAssetTrack = track player.currentItem?.audioMix = visualizer.audioMix } player.play()
ãã¸ã¥ã¢ã©ã¤ã¶ã¼ã®é³å£°è§£æã¯ã©ã¹
åºæ¬çã«ã¯ãµã³ãã«ã³ã¼ãã®éãã«ãªãã¾ããï¼Objective-Cã§æ¸ããå ´åã®è©±ã§ããï¼
MTAudioProcessingTapã§ã¯ãåæåã»ãã¡ã¤ãã©ã¤ãºã»æºåã»å¦çä¸ã»çµäºæã«åãã³ã¼ã«ããã¯ãããããè¨å®ãã¦ãããå¿ è¦ãããã¾ãã
static void tap_InitCallback(MTAudioProcessingTapRef tap, void *clientInfo, void **tapStorageOut); static void tap_FinalizeCallback(MTAudioProcessingTapRef tap); static void tap_PrepareCallback(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat); static void tap_ProcessCallback(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut); static void tap_UnprepareCallback(MTAudioProcessingTapRef tap);
ã¾ããä¸è¨5ã¤ã®ã³ã¼ã«ããã¯éã§ãã¼ã¿ãåã渡ãããã«ãä¸è¨ã®ãããªæ§é ä½ãæºåãã¾ãã
typedef struct AVAudioTapProcessorContext { Boolean supportedTapProcessingFormat; Boolean isNonInterleaved; Float64 sampleRate; AudioUnit audioUnit; Float64 sampleCount; void *self; } AVAudioTapProcessorContext;
åçããé³æºã«ã¨ãã§ã¯ããããã¦å å·¥ãããå ´åã¯ãå å·¥ç¨AudioUnitã®æºåã¨ãã®ã³ã¼ã«ããã¯é¢æ°ã®è¨å®ãtap_PrepareCallback
é¢æ°å
ã§è¡ãã¾ãã
èªåã§ä½ã£ãã¨ãã§ã¯ãããããããèªåã§ä¿¡å·å¦çãããå ´åã¯ãAU_RenderCallback
é¢æ°å
ã«å¦çãæ¸ããã¨ãã§ãã¾ãã
å å·¥ããªãå ´åã¯ãAudioUnitãAU_RenderCallback
é¢æ°ã®æºåã¯è¦ãã¾ããã
以ä¸ã®ã³ã¼ãã§ã¯ãä¾ã¨ãã¦åçããé³æºã«ãã³ããã¹ãã£ã«ã¿ããããã¨ãã§ã¯ããè¨å®ãã¦ãã¾ãã
static void tap_PrepareCallback(MTAudioProcessingTapRef tap, CMItemCount maxFrames, const AudioStreamBasicDescription *processingFormat) { AVAudioTapProcessorContext *context = (AVAudioTapProcessorContext *)MTAudioProcessingTapGetStorage(tap); context->sampleRate = processingFormat->mSampleRate; context->supportedTapProcessingFormat = true; // ~~ããããçç¥~~ // ã¨ãã§ã¯ãã®æºåï¼ãã³ããã¹ãã£ã«ã¿ï¼ AudioUnit audioUnit; AudioComponentDescription audioComponentDescription audioComponentDescription.componentType = kAudioUnitType_Effect; audioComponentDescription.componentSubType = kAudioUnitSubType_BandPassFilter; audioComponentDescription.componentManufacturer = kAudioUnitManufacturer_Apple; audioComponentDescription.componentFlags = 0; audioComponentDescription.componentFlagsMask = 0; AudioComponent audioComponent = AudioComponentFindNext(NULL, &audioComponentDescription); if (audioComponent) { if (noErr == AudioComponentInstanceNew(audioComponent, &audioUnit)) { OSStatus status = noErr; // ~~ããããçç¥~~ if (noErr == status) { AURenderCallbackStruct renderCallbackStruct; renderCallbackStruct.inputProc = AU_RenderCallback; renderCallbackStruct.inputProcRefCon = (void *)tap; status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallbackStruct, sizeof(AURenderCallbackStruct)); } // ~~ããããçç¥~~ } OSStatus AU_RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { return MTAudioProcessingTapGetSourceAudio(inRefCon, inNumberFrames, ioData, NULL, NULL, NULL); }
å®éã«ãªã¼ãã£ãªãã¼ã¿ãåãåºãã¦å¦çã»è§£æããã®ã¯tap_ProcessCallback
é¢æ°ã®é¨åã«ãªãã¾ãã
nanaã®å ´åãç®çã¯ãã¸ã¥ã¢ã©ã¤ã¶ã¼ = é³å£°ã®å¨æ³¢æ°ã®å¯è¦åãªã®ã§ããã®é¨åã§FFT(Fast Fourier Transformation)ãã¦ãã¾ããä»åã¯Accelerate.frameworkã®vDSPã使ã£ã¦ãã¾ãã
static void tap_ProcessCallback(MTAudioProcessingTapRef tap, CMItemCount numberFrames, MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut) { // ~~ ããããçç¥ ~~ for (UInt32 i = 0; i < bufferListInOut->mNumberBuffers; i++) { // ããã§ãªã¼ãã£ãªãã¼ã¿ãåãåºãã } }
課é¡
ãµã³ãã«ã³ã¼ããObjective-Cã ã£ããã¨ãã¾ãå½æå¼ã³åºãå ã®AVPlayerå®è£ ã¯ã©ã¹ãObjective-Cã§ãããSwiftãå¼ã³åºãã®ãé£ãããã ã£ããã¨ããã ãã¸ã¥ã¢ã©ã¤ã¶ã¼ã®é³å£°è§£æã¯ã©ã¹ã®ã¿Objective-Cã§å®è£ ãã¦ãã¾ãã
iOSçnanaã®ãªãã¸ããªã§ã¯ãéçºå¹çãå°æ¥æ§ã»ã¡ã³ããã¼ã®ä¸è¶³ãªã©ã®ãã¾ãã¾ãªçç±ãããéçºè¨èªãSwiftã«ä¸æ¬åãããã¨ãå³ã£ã¦ãããObjective-Cã®ã³ã¼ããSwiftã«æ¸ãæããããããããSwiftåããé²ãã¦ããæä¸ã§ãã
ã¨ããããä»åã®å®è£ ã«ãã£ã¦ãéã«Objective-Cã®ã³ã¼ããå¢ããã¦ãã¾ãã¾ããð±
ä¸æ¹ã§ãé³ã®ä¿¡å·å¦çï¼ç¹ã«ãªã¢ã«ã¿ã¤ã å¦çï¼ã§ã¯ãé 延ãå¦çé度ã¨ãã£ãçç±ãããSwiftãããObjective-CãC/C++ã§æ¸ããæ¹ãçµæã¨ãã¦è¯ãæ¹åã«ãªããã¨ãå¤ãã¨æãã¦ãã¾ãã
ä»å¾ããSwiftåãã試ã¿ãéã¯ãé 延ãå¦çé度ãªã©ã«å½±é¿ãåºãªãã¨ãããã¨ã確ããã¦ããå®è£ ãé²ãã¦ããããã¨èãã¦ãã¾ãã
注æ
AVPlayerã§ã¹ããªã¼ãã³ã°åçãè¡ãªã£ã¦ããæã¯ããã®æ¹æ³ã§ãªã¼ãã£ãªãã¼ã¿ãåå¾ãããã¨ã¯ã§ããªãããã§ãã
nanaã¯åçã«ããã°ã¬ãã·ããã¦ã³ãã¼ãã使ç¨ãã¦ããããããã®æ¹æ³ãæ¡ç¨ã§ãã¾ããã
ã¾ã¨ã
ä»åã¯MTAudioProcessingTapã使ã£ã¦ãAVPlayerã§åçä¸ã®ãªã¼ãã£ãªãã¼ã¿ãåå¾ããæ¹æ³ãç´¹ä»ãã¾ããã
MTAudioProcessingTapãç¥ã£ãæãAVAudioEngineç¹æã®æè¡ã ã¨æã£ã¦ãããã¨ãAVPlayerã§ãã§ãããã ï¼ã¨é©ããã®ãè¦ãã¦ãã¾ãã
ãããAVAudioEngineã®installTapã»ã©å°å ¥ã¯æ¥½ã§ã¯ãªããã¾ãMTAudioProcessingTapã®æ å ±ãã»ã¨ãã©åºåã£ã¦ããªããããå®è£ ã¯ã¡ãã£ã¨å¤§å¤ã§ããâ¦
ã©ããã¦ãAVPlayerä¸ã§ãªã¼ãã£ãªãã¼ã¿ãåå¾ãããï¼ã¨ãã§ã¯ããããããï¼ã¨ããæã«ããã®è¨äºãå°ãã§ãå®è£ ã®åèã«ãªãã°å¬ããã§ãï¼
nana musicã¯éçºã¡ã³ãã¼ãåéãã¦ãã¾ãï¼
æ°ã«ãªã£ã¦ããæ¹ã»èå³ã®ããæ¹ã¯ããã²ä¸åº¦ãé£çµ¡ãã ããð