ひとつの 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
を使うと良い。
ちょっとしたときに、
あらかじめ用意されているシステム音を使いたい。
AudioServicesPlaySystemSound(1000)
👉 AudioServicesPlaySystemSound(_:) | Apple Developer Documentation
これだけで音が鳴る。
「1000」 は SystemSoundID というもののようなので、
「どんな音が鳴るのかリスト」を探すが、
公式で見つけられなかった。
以下にそれらしきもの。

👉 AudioServices - iPhone Development Wiki
結構、古そうなので今どきの状態を確認したい。
OSやバージョンなど環境によっても違うっぽい。
なので、コードからのぞいてみる。
ID は 2000 ぐらいまでの整数なのですが、
非公式のリストを見る限り、番号が歯抜け状態。
音声データの長さで「欠番らしき」を見分ける。
実際に再生してその時間を取得しました。
let start = Date()
AudioServicesPlaySystemSoundWithCompletion(1000) {
let elapsed = Date().timeIntervalSince(start)
print(elapsed)
}
// 1.566209077835083
👉 AudioServicesPlaySystemSoundWithCompletion(_:_:) | Apple Developer Documentation
おおまかに 再生時間 50ミリ秒 以下が欠番っぽい。
ボタンを並べて Preview や Simulator や 実機 でどんな音があるのか確かめます 。
極力、deprecated な関数は避けていきたいです。
実際に音声ファイルを作成する前に、雰囲気を確認したいときに使いたくなります。
しかし、ID が分からない。
そんな人用。
ファイルで探すなら、各環境内でディレクトリ名で走査するといいのですね !
Library/Audio/UISounds
❯ tree .
.
├── 3rd_party_critical.caf
├── AuthenticationMatch_Full.caf
├── AuthenticationMatch_Short.caf
...
├── ussd.caf
├── warsaw.caf
└── wheels_of_time.caf
4 directories, 321 files
あと、アプリとかショートカットもありました。
👉 「Play System Sounds」をApp Storeで
👉 System Sounds - Shortcuts
iOS は Android OS に比べて、ユーザーの最新バージョンへの移行が早い。

また、来月早々には更新したいと思います。