ひとつの View だけで
その端末の組み込みのシステム音を
確認できたらいいかも、
ということで。
GIF って音声出ませんでした ?
以下、音が出てます。
確認の範囲として、
SystemSoundID は 1 から 4000 まで。
実際に音を並列で鳴らして 0.0025 秒以下の音は無視してます。
非同期の処理はここでも難しい印象を受けます。
ひとつの View だけで
その端末の組み込みのシステム音を
確認できたらいいかも、
ということで。
GIF って音声出ませんでした ?
以下、音が出てます。
確認の範囲として、
SystemSoundID は 1 から 4000 まで。
実際に音を並列で鳴らして 0.0025 秒以下の音は無視してます。
非同期の処理はここでも難しい印象を受けます。
Audio MIDI 複数出力装置と仮想デバイス BlackHole を使って、QuickTime で聴きながらの音声付き録画。
なぜできないのか。
聴きながらができないんです。
シュミレータにも、Audio Output の設定があるので、
そこで、個別に BlackHole に向けてもダメ。
複数音声出力 から BlackHole 向きを外してもダメ。
シュミレータを音声付き録画するなら聴きながらはできない。
そういうものなの?
できても良さそうなのに。
Loopback など有料アプリならできるのですか ?
ビルトイン非同期関数の直列処理って自力でやるにはつらいですよね。
まず、ボタンを押して、音を鳴らします。
Button("Play1") {
AudioServicesPlaySystemSound(1000)
}
純粋なUIスレッドではないところで再生処理がされています。
いわゆる
「UIスレッドと非同期された処理」
ですね。
続いて、
Button("Play2") {
AudioServicesPlaySystemSound(SystemSoundID(1000))
}
これも同じ音が再生されます。
この組み込みシステム音声を鳴らす関数
func AudioServicesPlaySystemSound(_ inSystemSoundID: SystemSoundID)
👉 AudioServicesPlaySystemSound(_:) | Apple Developer Documentation
の引数の型は SystemSoundID ですので直しておきます。
中を見てみると、
/**
@typedef SystemSoundID
@abstract SystemSoundIDs are created by the System Sound client application
for playback of a provided AudioFile.
*/
public typealias SystemSoundID = UInt32
UInt32 の typealias であることが分かります。
この SystemSouldID は他にもたくさんいろいろあります。
が、端末やOSバージョンによって異なるので注意が必要なようですね。
【Swift】SystemSoundID 一覧がないのですが
👉 https://t.co/CWXAMi2MhA#Swift #ios #iphone pic.twitter.com/miBCIkCcrp— chanzmao (@maochanz) March 4, 2024
続いて、11個連続再生してみます。
Button("Play3") {
for i in 1000...1010 {
AudioServicesPlaySystemSound(SystemSoundID(i))
}
}
あれ。
残念なことに音が重なって同時に再生されます。
それぞれ、どんな音が鳴っているか分かりません。
非同期処理の関数が並列で処理されているのです。
連続で順番に音を再生したい。
言い換えれば、
非同期関数の直列処理
をしたいですよね。
まず、音声再生処理終了のタイミングから処理を実行できる
👉 AudioServicesPlaySystemSoundWithCompletion(_:_:) | Apple Developer Documentation
を使って音を1つだけ鳴らしてみます。
Button("Play4") {
AudioServicesPlaySystemSoundWithCompletion(SystemSoundID(1000)) {
print("completed.")
}
}
これで、終了のタイミングを取得できます。
続いて、これを連続で実行します。
今どきの Swift では、以下の関数を使うらしいです。
👉 withCheckedContinuation(function:_:) | Apple Developer Documentation
👉 withCheckedThrowingContinuation(function:_:) | Apple Developer Documentation
これを使って書き換えます。
Button("Play5") {
Task {
for i in 1000...1010 {
await withCheckedContinuation { continuation in
AudioServicesPlaySystemSoundWithCompletion(SystemSoundID(i)) {
continuation.resume()
}
}
}
}
}
クロージャー内は同期処理となって await が必要となりますので Task をかぶせてます。
音声なので、特にスレッドをメインに指定することなどは不要のようです。
以下、それぞれの実行音声動画です。
「非同期処理の直列化」は用意されている関数の
👉 withCheckedContinuation(function:_:) | Apple Developer Documentation
👉 withCheckedThrowingContinuation(function:_:) | Apple Developer Documentation
を使うと良い。