6

とりわけ、音楽をフェードインおよびフェードアウトできるプログラムを作成しています。問題は、他のスレッド/キューが音楽を一時停止できることです。つまり、フェードインとフェードアウトも一時停止するだけでなく、保留する必要があります。dispatch_after で「タイマー」を一時停止できるようにする必要があります (これは音楽の再生が開始されたときに呼び出され、フェードアウトを開始するタイミングを伝えるためです。一時停止した場合は遅延する必要があります)。キューを一時停止します。それ自体 (フェードインまたはフェードアウト中にフェードインまたはフェードアウトを一時停止するため)

コードは次のとおりです (fadeIn と delayFadeOut は両方ともプログラムの開始時に呼び出されます)。

- (void) doFadeIn: (float) incriment to: (int) volume with: (AVAudioPlayer*) thisplayer on: (dispatch_queue_t) queue{
    dispatch_async(queue, ^{
        double delayInSeconds = .1;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, queue, ^(void){
            thisplayer.volume = (thisplayer.volume + incriment) < volume ? thisplayer.volume + incriment : volume;
            NSLog([[[NSNumber alloc] initWithFloat:thisplayer.volume] stringValue]);
            if (thisplayer.volume < volume) {
                [self doFadeIn:incriment to:volume with:thisplayer on:queue];
            }
        });
    });    
}

-(void) doDelayFadeOut: (float) incriment with: (AVAudioPlayer*) thisplayer on: (dispatch_queue_t) queue
{
    dispatch_async(queue, ^{
        double delayInSeconds = .1;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, queue, ^(void){
            thisplayer.volume = (thisplayer.volume - incriment) > 0 ? thisplayer.volume - incriment : 0;
            NSLog([[[NSNumber alloc] initWithFloat:thisplayer.volume] stringValue]);
            if (thisplayer.volume > 0.0) {
                [self doDelayFadeOut:incriment with:thisplayer on:queue];
            }
        });
    });
}

-(void) fadeIn: (AVAudioPlayer*) dFade {
    if (dFade == nil) {
        return;
    }
    dispatch_queue_t queue = dispatch_queue_create("com.cue.MainFade", NULL);
    dispatch_async( queue, ^(void){
        if(dFade !=nil){
            double incriment = ([self relativeVolume] / [self fadeIn]) / 10; //incriment per .1 seconds.
            [self doFadeIn: incriment to: [self relativeVolume] with:dFade on:dispatch_queue_create("com.cue.MainFade", 0)];
        }

    });
}

- (void) delayFadeOut: (AVAudioPlayer*) dFade { //d-fade should be independent of other threads
    if (dFade == nil) {
        return;
    }
    int timeRun = self.duration - self.fadeOut;
    dispatch_queue_t queue = dispatch_queue_create("com.cue.MainFade", NULL);
    dispatch_time_t mainPopTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeRun * NSEC_PER_SEC));
    printf("test");
    dispatch_after(mainPopTime, queue, ^(void){
        if(dFade !=nil){
            double incriment = ([dFade volume] / [self fadeOut])/10; //incriment per .1 seconds.
            [self doDelayFadeOut:incriment with:dFade on:dispatch_queue_create("com.cue.MainFade", 0)];
        }

    });
    if (self.cueType == 2) {
        [self callNext];
    }
}
4

2 に答える 2

10

あなたの一般的な質問に対して、電話はdispatch_suspend()(と一緒にdispatch_resume())です。これにより、特定のキューの新しいブロックがスケジュールされなくなります。すでに実行中のブロックには影響しません。すでにスケジュールされて実行中のブロックを一時停止する場合は、条件を確認して一時停止するのはコード次第です。

ただし、これを使用する際に理解しておくべき重要な点は、「dispatch_after で「タイマー」を一時停止」できるものはないということです。1 秒後に何かをディスパッチしたいと言えば、絶対に 1 秒後にディスパッチされます。しかし、「派遣」は「走る」という意味ではありません。「行列に並ぶ」という意味です。そのキューが一時停止されている場合、ブロックはキューが再開されるまでハングアウトします。注意すべきことは、一連のフェード ブロックがキューに蓄積されないようにすることです。その場合、キューを再開すると、すべて連続してスケジュールされます。あなたのコードを見ると、それはおそらく起こらないので、これでうまくいくかもしれません。ディスパッチは「キューに入れる」ことを意味することに注意してください。また、中断されていないキューには、ブロックが順番にスケジュールされています。

于 2013-03-17T23:52:58.903 に答える
6

キューの一時停止/操作のキャンセルには、GCD の代わりにNSOperationandを使用する必要があります。ここNSOperationQueueを参照してください。

于 2013-03-17T21:02:15.863 に答える