2012-06-18 25 views
2

我在iOS 5上使用CoreAudio播放MIDI文件。我有一切设置,它的工作,一切都桃色,除非我想在播放播放期间从开始开始的序列。 要做到这一点我很自然地叫:iOS&CoreAudio:调用MusicPlayerSetTime()停止MusicPlayer

if (MusicPlayerSetTime(musicPlayer, (MusicTimeStamp)0.0) != noErr) 
     [NSException raise:@"playMIDI" format:@"Can't reset the player"]; 

我没有得到任何错误,但在进行此调用完全停止播放,而不是(如文档中说)继续在新的位置继续播放。 我已经试过这也(同类型等多种组合):

Boolean isPlaying = NO; 
if (MusicPlayerIsPlaying(musicPlayer, &isPlaying) != noErr) 
    [NSException raise:@"playMIDI:" format:@"Can't get MusicPlayer play state"]; 

if (isPlaying) { 
    if (MusicPlayerStop(musicPlayer) != noErr) 
     [NSException raise:@"playMIDI:" format:@"Can't stop MusicPlayer"]; 
} 

if (MusicPlayerSetSequence(musicPlayer, musicSequence) != noErr) 
    [NSException raise:@"playMIDI:" format:@"Can't set sequence for MusicPlayer"]; 

if (MusicPlayerSetTime(musicPlayer, (MusicTimeStamp)0.0) != noErr) 
    [NSException raise:@"playMIDI" format:@"Can't reset the player"]; 

if (MusicPlayerSetPlayRateScalar(musicPlayer, 1.0) != noErr) 
    [NSException raise:@"playMIDI" format:@"Can't set speed"]; 

if (MusicPlayerStart(musicPlayer) != noErr) 
    [NSException raise:@"playMIDI" format:@"Can't start MusicPlayer"]; 

没有快乐,同样的效果。

但是,如果我更改MusicSequence,那么新的MusicSequence播放效果会很好。所以我已经到了从同一个MIDI文件创建两个MusicSequence并从一个切换到另一个的极端了。没有快乐,iOS知道我想两次播放同一个文件并禁止它。我必须等到序列完全播放后才能再次播放。扑朔迷离。

有什么想法?

感谢

回答

0

OK,这就是我认为正在发生的:核心音频是拉式,即,当一个单位需要的数据,它从源头请求它。现在,当我在MusicPlayer上重置时间时,它会在特定时间完成,比如t0。之后不久,在时间t1,由该MusicPlayer馈送的AU节点要求输入数据。 MusicPlayer需要t1并计算它在事件顺序中的位置。由于它总是大于t0,所以任何准确开始于t0的事件(例如,以MIDI节拍0开始的事件)被认为是播放的,因此根本不播放。换句话说,MIDI文件的第一个音符不播放。

现在,由于我的文件非常短,实际上只包含从0开始的和弦,所以没有任何音符被播放,我得到了沉默。

为什么当我打开一个新的序列或启动时,它是不是已经打了顺序,我不清楚这是不会发生......

无论如何,一个可能的解决办法是:停止播放器,设置序列,将时间设置为0,然后通过例如延迟播放器的开始为25ms。这对于响应速度并不理想,但它很有用。

一个解决这个问题稍微令人费解的方法如下:
- 建立在使音乐播放器是喂养音频单元上的回调(AudioUnitAddRenderNotify())
- 在的复位时间序列,不要重置播放器上的时间,但设置一个布尔标志
- 在渲染回调中,如果设置了该标志,则重置播放器上的时间并取消设置标志
没有延迟引入,它也是作品,这往往会验证我对问题的理解。

2

我没有注意到在t0开始/停止/重新启动序列时出现任何问题。你确信序列中的音符是在你认为他们是的时候?还是别的什么?

下面的代码(错误检查删除)快速测试停止+重新启动罚款。或者我误解了你所描述的问题。 Fwiw - 没有停止/开始玩家的呼叫,它也可以工作,但短暂的音符仍然会响起,所以它不是一个干净的跳跃。

- (void)jump 
{ 
    if (player) { 
     MusicPlayerStop(player) 
     MusicPlayerSetTime(player, 0.0f); 
     MusicPlayerStart(player); 
    } 
} 

UPDATE

我接过一看。中旬文件并进行了测试。这是MusicPlayer如何看待您的文件(使用功能CAShow(nameOfYourSequence)

Sequence @0x68ad7c0 
NumTracks = 1, Type = beats 
* * TempoTrack * * 
SequenceTrack @0x68ab250 
    Num Events: 3, Track Length: 0.00 beats 
    0.000: Time Sig:4/4, 24 clks/qtr, 8 32nds/clk 
    0.000: SMPTE Offset [33:0:0:0.0] 
    0.000: Tempo:120.000 

* * Track 1 * * 
SequenceTrack @0x6a815e0 
    Num Events: 9, Track Length: 4.11 beats 
    0.000: MetaEvent:03 
     0: 30 31 30 31 30 31 31 31       01010111   
    0.000: MetaEvent:04 
     0: 30 31 20 43          01 C    
    0.000: MetaEvent:59 
     0: 00 00            ..    
    0.000: MetaEvent:06 
     0: 31 20 4D 41 4A 45 55 52 53      1 MAJEURS  
    0.000: MetaEvent:06 
     0: 31 31            11    
    0.000: Note:Ch:0 36 121 (4.113) 
    0.000: Note:Ch:0 60 116 (3.931) 
    0.000: Note:Ch:0 64 110 (3.931) 
    0.000: Note:Ch:0 67 105 (3.931) 

我能够与文件摄制问题 - 之前还没有看到,但后来我的工作文件是更长的时间。不知道你在做什么,但是一种解决方法可能会在0.000之后开始你的事件。

在另一方面,你有没有考虑直接管理你的noteOn + noteOff事件使用:

MusicDeviceMIDIEvent (self.samplerUnit, noteCommand, noteNum, onVelocity, 0); 
+0

是的,我查了一下,音符从0开始(我用http://www.fourmilab.ch/ webtools/midicsv /转储文件的内容,并且我也与Aria Maestosa进行了检查)。我必须说,除了我在下面给出的解释外,我无法解释这种行为。 –

+0

我已经与MusicPlayer摔跤了很多,所以我明白感觉不知所措!有关节奏,比赛率的不寻常情况?想不到别的。 –

+0

midi文件非常简单,它很难有任何错误,但在这里,请自己判断:https://dl.dropbox.com/u/3916368/01010111.mid。让我知道你是否能够在第一次播放它后1秒内重新启动它。谢谢 –