質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

1028閲覧

ピアノアプリで音を鳴らす際に生じるノイズ音を除去したい

masa1101

総合スコア5

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2023/03/10 05:24

編集2023/03/11 04:21

アプリ開発初心者です.SwiftUIで簡易的なピアノアプリを作成しています.

  • キーをタップすると音が鳴る
  • キー上でドラッグすると音が変わる
  • ピッチを変えるとキーの音が変わる

という仕様を実装することが目標です.これらの仕様を満たすように作ってみたのですが,動画のとおり,処理方法の問題なのか音がなる際にノイズ音が発生しています.このノイズ音が鳴らないようにするための解決策・改善方法などあれば教えていただけると幸いです.

デモ動画のリンク

ソースコード

SwiftUI

1 @State private var noteNum: UInt8 = 0 2 @State private var soundKey: UInt8 = 9 3 @State private var location: CGPoint = .zero 4 5 var body: some View { 6 let sampler = Sampler(noteNum: noteNum) 7 let drag = DragGesture(minimumDistance: 0.0, coordinateSpace: .local) 8 .onChanged({ drag in 9 self.location = drag.location 10 if (self.location.y >= 70 && self.location.y <= 180) { 11 switch (self.location.x) { 12 case (34 ... 97): 13 noteNum = upperKeySound[0] + self.soundKey 14 case (100 ... 163): 15 noteNum = upperKeySound[1] + self.soundKey 16 case (166 ... 229): 17 noteNum = upperKeySound[2] + self.soundKey 18 case(232 ... 295): 19 noteNum = upperKeySound[3] + self.soundKey 20 case(298 ... 361): 21 noteNum = upperKeySound[4] + self.soundKey 22 case(364 ... 427): 23 noteNum = upperKeySound[5] + self.soundKey 24 case(430 ... 493): 25 noteNum = upperKeySound[6] + self.soundKey 26 case(496 ... 559): 27 noteNum = upperKeySound[7] + self.soundKey 28 case(562 ... 625): 29 noteNum = upperKeySound[8] + self.soundKey 30 default: 31 noteNum = 0 32 } 33 } else if (self.location.y >= 190 && self.location.y <= 300) { 34 switch (self.location.x) { 35 case (1 ... 64): 36 noteNum = lowerKeySound[0] + self.soundKey 37 case (67 ... 130): 38 noteNum = lowerKeySound[1] + self.soundKey 39 case (133 ... 196): 40 noteNum = lowerKeySound[2] + self.soundKey 41 case(199 ... 262): 42 noteNum = lowerKeySound[3] + self.soundKey 43 case(265 ... 328): 44 noteNum = lowerKeySound[4] + self.soundKey 45 case(331 ... 394): 46 noteNum = lowerKeySound[5] + self.soundKey 47 case(397 ... 460): 48 noteNum = lowerKeySound[6] + self.soundKey 49 case(463 ... 526): 50 noteNum = lowerKeySound[7] + self.soundKey 51 case(529 ... 592): 52 noteNum = lowerKeySound[8] + self.soundKey 53 case(595 ... 658): 54 noteNum = lowerKeySound[9] + self.soundKey 55 default: 56 noteNum = 0 57 } 58 } 59 sampler.play() 60 }) 61 .onEnded({ _ in 62 sampler.stop() 63 noteNum = 0 64 self.location = .zero 65 })

DragGestureでドラッグしている座標を取得して,あるキー上に座標がきたとき,そのキーの音が鳴ります.
sampler.play()で音が鳴り,sampler.stop()で停止します.
noteNumはMIDIのノートナンバーで,Samplerクラスに渡すことでそのノートナンバーの音が鳴ります.
soundKeyは音調です.

teratailの利用も初めてなので情報の不足等あるかもしれませんが,アドバイスよろしくお願いします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

解決した方法

sampler.play() ですでに音を鳴らしている状態であるとき sampler.stop() を実行しないというようにすることで,ノイズが発生しなくなりました.音が鳴っている状態は論理値 isPlaying で取得しています.

↓元のSampler

Swift

1class Sampler { 2 let audioEngine = AVAudioEngine() 3 let unitSampler = AVAudioUnitSampler() 4 let noteNum: UInt8 5 6 init(noteNum: UInt8) { 7 self.noteNum = noteNum // self.noteNum == Sampler().noteNum 8 audioEngine.attach(unitSampler) 9 audioEngine.connect(unitSampler, to: audioEngine.mainMixerNode, format: nil) 10 if let _ = try? audioEngine.start() { 11 loadSoundFont() 12 } // if let はオプショナルバインディング 13 } 14 15 deinit { 16 if audioEngine.isRunning { 17 audioEngine.disconnectNodeOutput(unitSampler) 18 audioEngine.detach(unitSampler) 19 audioEngine.stop() 20 } 21 } 22 23 func loadSoundFont() { 24 guard let url = Bundle.main.url(forResource: "SGM-V2.01.sf2", withExtension: "sf2") else { return } 25 try? unitSampler.loadSoundBankInstrument( 26 at: url, program: 0, 27 bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB), 28 bankLSB: UInt8(kAUSampler_DefaultBankLSB) 29 ) 30 } 31 32 func play() { 33 // 一つ目の引数はMIDIのNote番号60は基本のド 34 // withVelocityは音量に関係する値 0 ~ 127 35 // onChannelはチャンネルを構成しないなら基本0 36 unitSampler.startNote(noteNum, withVelocity: 80, onChannel: 0) 37 } 38 39 func stop() { 40 unitSampler.stopNote(noteNum, onChannel: 0) 41 } 42}

↓解決したSampler

Swift

1class Sampler { 2 let audioEngine = AVAudioEngine() 3 let unitSampler = AVAudioUnitSampler() 4 let noteNum: UInt8 5 var isPlaying: Bool = false 6 7 init(noteNum: UInt8) { 8 self.noteNum = noteNum // self.noteNum == Sampler().noteNum 9 audioEngine.attach(unitSampler) 10 audioEngine.connect(unitSampler, to: audioEngine.mainMixerNode, format: nil) 11 if let _ = try? audioEngine.start() { 12 loadSoundFont() 13 } // if let はオプショナルバインディング 14 } 15 16 deinit { 17 if audioEngine.isRunning { 18 audioEngine.disconnectNodeOutput(unitSampler) 19 audioEngine.detach(unitSampler) 20 audioEngine.stop() 21 } 22 } 23 24 func loadSoundFont() { 25 guard let url = Bundle.main.url(forResource: "SGM-V2.01.sf2", withExtension: "sf2") else { return } 26 try? unitSampler.loadSoundBankInstrument( 27 at: url, program: 0, 28 bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB), 29 bankLSB: UInt8(kAUSampler_DefaultBankLSB) 30 ) 31 } 32 33 func play() { 34 // 一つ目の引数はMIDIのNote番号60は基本のド 35 // withVelocityは音量に関係する値 0 ~ 127 36 // onChannelはチャンネルを構成しないなら基本0 37 if (isPlaying == false) { 38 isPlaying = true 39 unitSampler.startNote(noteNum, withVelocity: 60, onChannel: 0) 40 } 41 } 42 43 func stop() { 44 if (isPlaying == true) { 45 isPlaying = false 46 unitSampler.stopNote(noteNum, onChannel: 0) 47 } 48 } 49}

投稿2023/03/17 03:34

編集2023/03/17 03:36
masa1101

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

DragGestureの.onChangedは、ドラッグで指の位置が僅かに変わるたびに呼び出されますから、このコードだとsampler.play() は、ドラッグ中にミリ秒単位の間隔で何度も連続で呼び出しされます。

Samplerの内容がどのようになっているのかよくわかりませんが、 sampler.play() が再生をやり直す形になっているのであれば、やり直す間に音が途切れてノイズが入ったようになる可能性があると思います。

onChangedの中で新しいnoteNumを取得した時に、以前のnoteNumと値が変わった場合だけ sampler.play() を呼び出すようにすればよいのかもしれません。

投稿2023/03/12 01:57

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masa1101

2023/03/13 07:25

回答いただきありがとうございます.ノイズが鳴る原因が理解できました. 回答内容を基に修正してみます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問