2012-06-18 29 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秒內重新啓動它。謝謝 –