Problems using AEBlockChannel on iPhone device
Hi Michael,
thanks for this awesome framework. I'm having some issues using AEBlockChannel. The following code uses frame-level timing in a "FOR loop" to keep transitions accurate, this snippet is based in the metronome script concept and triggers drum loops, which are audio channels made of AEAudioFilePlayers, one per each drum part (snare, toms, hi-hat, kick and cymbals). The first loop is triggered once the countdown time has ended, and calculates switching time (in frames) to the next drum loop.
- (void)startPlaybackBlockChannel { // the metronome and playback control self.metronomeBlockChannel = [AEBlockChannel channelWithBlock:^(const AudioTimeStamp *time, UInt32 frames, AudioBufferList *audio) { static int next_beat_frame = 0; // meter counter static int meterCount = 1; // checks for _isPlaying flag if (!_isPlaying) { frames = 0; next_beat_frame = 0; meterCount = 1; if (_total_frames > 0) { [self stop]; } } else { // counting frames for (int i=0; i<=frames; i++) { // countdown to start if (_total_frames < (int)_start) { _low.volume = 1; _high.volume = 1; } else { if (_metronomeButton.selected == NO) { _low.volume = 0; _high.volume = 0; } else { _low.volume = 1; _high.volume = 1; } } if (_total_frames == (int)_start) { // removes countdown signal [self setCountdownAnimation:-1]; // this function changes drums' pieces (currently 4 or 5 AEAudioPlayers so far), // basically a FOR loop setting channelIsPlaying property to YES. [_currentLoop startInstrumentPlayback]; // setting _isPlaying to YES, and getting into this block from now on till it returns to NO. _isPlaying = YES; } // if we reach the current tempo, the next drum will be triggered if (_changeTempoAt == _total_frames) { // this index controls if this block should playing the full session int index = [session.slots indexOfObject:_currentLoop] + 1; // stop if session has ended if (index == [session.slots count] && _sessionCounter == 0) { _isPlaying = NO; break; } // this index restarts if we repeat the session and we reached the end if (index == [session.slots count] && _sessionCounter > 0) { index = 0; _sessionCounter--; } // stop current drum parts. FOR loop setting channelIsPlaying property to NO [_currentLoop stopInstrumentPlayback]; // gets next drums _currentLoop = [session.slots objectAtIndex:index]; next_beat_frame = _total_frames; // start next drum parts [_currentLoop startInstrumentPlayback]; // updating descriptive labels [self animateLabels]; // calculates frames n-times to enable repeating _changeTempoAt += _currentLoop.frameLength; // calculates metronome ticks _frames_between_beats = 44100/(_currentLoop.tempo/60.); // check meter _meter = [self calculateMeter:_currentLoop.meter]; meterCount = 1; } // beat handling and initial countdown animations if (next_beat_frame == _total_frames) { if (meterCount == 1) { _high.currentTime = 0; _high.channelIsPlaying = YES; } else { _low.currentTime = 0; _low.channelIsPlaying = YES; } if (_total_frames < (int)_start) [self setCountdownAnimation:_meter - meterCount]; meterCount++; if (meterCount == _meter+1) { meterCount = 1; } next_beat_frame += _frames_between_beats; } // increment the count _total_frames++; } } }]; // adding the block channel to the audio controller [_audioController addChannels:[NSArray arrayWithObject:_metronomeBlockChannel]]; }
At the beginning, I was using AEBlockScheduler to coordinate loop switching and UI updates based on time events. Using AEBlockChannel for this process makes more sense, and my UI events and track transitions are really accurate.
The problem is that my app runs perfectly on the iPhone simulator, but there's no sound on my iPhone 5 device. I assume the problem is not preparing the AEAudioFilePlayers, because I triggered them from outside the frame loop and they are playing correctly.
Do you have any idea what could be causing this?
Thanks.
Comments
By the way, the UI events are also out of time using AEBlockChannel on the device, but works perfectly on the simulator.
Did anybody figure this out yet? I'm having a very similar issue
One thing with the above code, you aren't supposed to make Objective-C calls from within the block if you want to avoid thread locks (http://atastypixel.com/blog/four-common-mistakes-in-audio-development/)