「caf」形式で録音された個々のギターの音符を再生して、ランダムなギター音楽を生成する iPhone アプリを構築しています。これらのノートは、サステインの量に応じて、3 秒から 11 秒まで持続時間が異なります。
私はもともとAVAudioPlayerを再生に使用し、シミュレーターで120 bpmで16分音符を再生すると美しく歌われましたが、ハンドセットでテンポを60 bpm強に上げて1/4音符だけを再生するとすぐに、次のように実行されました犬で、間に合わない。私の高揚感は非常に短命でした。
遅延を減らすために、オーディオ エンジンのテンプレートとして Apple MixerHost プロジェクトを使用して Audio Units 経由の再生を実装しようとしましたが、ボルトで固定してすべてを接続した後も、不正なアクセス エラーが発生し続けました。
何時間も頭を悩ませた後、私はその道をあきらめ、代わりにNovocaineオーディオエンジンをボルトで固定しました.
モデルに接続しようとしてレンガの壁にぶつかりました。
最も基本的なレベルでは、私のモデルは Note オブジェクトの NSDictionary を含む Neck オブジェクトです。
各 Note オブジェクトは、それがギター ネックのどの弦とフレットにあるかを認識しており、独自の AVAudioPlayer を含んでいます。
ユーザー設定で選択したネック サイズに応じて、122 ノート (6 弦 x 22 フレット) または 144 ノート (6 弦 x 24 フレット) のいずれかを含むクロマティック ギター ネックを作成します。
私はこれらのノートを唯一の真実として使用しているため、音楽エンジンによって生成されたすべてのスカラー ノートは、このクロマティック ノート バケットへのポインタです。
@interface Note : NSObject <NSCopying>
{
NSString *name;
AVAudioPlayer *soundFilePlayer;
int stringNumber;
int fretNumber;
}
私は常に、選択したスケールのルート ノートまたはコードで再生を開始し、次に再生するノートを生成するので、生成されたノートの 1 つ後ろのノートを常に再生します。このようにして、次に再生するノートは常にキューに入れられ、すぐに使用できます。
これらのノートの再生制御は、次のコードで実現されます。
- (void)runMusicGenerator:(NSNumber *)counter
{
if (self.isRunning) {
Note *NoteToPlay;
// pulseRate is the time interval between beats
// staticNoteLength = 1/4 notes, 1/8th notes, 16th notes, etc.
float delay = self.pulseRate / [self grabStaticNoteLength];
// user setting to play single, double or triplet notes.
if (self.beatCounter == CONST_BEAT_COUNTER_INIT_VAL) {
NoteToPlay = [self.GuitarNeck generateNoteToPlayNext];
} else {
NoteToPlay = [self.GuitarNeck cloneNote:self.GuitarNeck.NoteToPlayNow];
}
self.GuitarNeck.NoteToPlayNow = NoteToPlay;
[self callOutNoteToPlay];
[self performSelector:@selector(runDrill:) withObject:NoteToPlay afterDelay:delay];
}
- (Note *)generateNoteToPlayNext
{
if ((self.musicPaused) || (self.musicStopped)) {
// grab the root note on the string to resume
self.NoteToPlayNow = [self grabRootNoteForString];
//reset the flags
self.musicPaused = NO;
self.musicStopped = NO;
} else {
// Set NoteRingingOut to NoteToPlayNow
self.NoteRingingOut = self.NoteToPlayNow;
// Set NoteToPlaNowy to NoteToPlayNext
self.NoteToPlayNow = self.NoteToPlayNext;
if (!self.NoteToPlayNow) {
self.NoteToPlayNow = [self grabRootNoteForString];
// now prep the note's audio player for playback
[self.NoteToPlayNow.soundFilePlayer prepareToPlay];
}
}
// Load NoteToPlayNext
self.NoteToPlayNext = [self generateRandomNote];
}
- (void)callOutNoteToPlay
{
self.GuitarNeck.NoteToPlayNow.soundFilePlayer.delegate = (id)self;
[self.GuitarNeck.NoteToPlayNow.soundFilePlayer setVolume:1.0];
[self.GuitarNeck.NoteToPlayNow.soundFilePlayer setCurrentTime:0];
[self.GuitarNeck.NoteToPlayNow.soundFilePlayer play];
}
各ノートの AVAudioPlayer は次のようにロードされます。
- (AVAudioPlayer *)buildStringNotePlayer:(NSString *)nameOfNote
{
NSString *soundFileName = @"S";
soundFileName = [soundFileName stringByAppendingString:[NSString stringWithFormat:@"%d", stringNumber]];
soundFileName = [soundFileName stringByAppendingString:@"F"];
if (fretNumber < 10) {
soundFileName = [soundFileName stringByAppendingString:@"0"];
}
soundFileName = [soundFileName stringByAppendingString:[NSString stringWithFormat:@"%d", fretNumber]];
NSString *soundPath = [[NSBundle mainBundle] pathForResource:soundFileName ofType:@"caf"];
NSURL *fileURL = [NSURL fileURLWithPath:soundPath];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
return notePlayer;
}
これが私がクロッパーになるところです。
ノボカインのGithubページによると……
オーディオの再生
Novocaine *audioManager = [Novocaine audioManager];
[audioManager setOutputBlock:^(float *audioToPlay, UInt32 numSamples, UInt32 numChannels) {
// All you have to do is put your audio into "audioToPlay".
}];
しかし、ダウンロードしたプロジェクトでは、次のコードを使用してオーディオをロードします...
// AUDIO FILE READING OHHH YEAHHHH
// ========================================
NSURL *inputFileURL = [[NSBundle mainBundle] URLForResource:@"TLC" withExtension:@"mp3"];
fileReader = [[AudioFileReader alloc]
initWithAudioFileURL:inputFileURL
samplingRate:audioManager.samplingRate
numChannels:audioManager.numOutputChannels];
[fileReader play];
fileReader.currentTime = 30.0;
[audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels)
{
[fileReader retrieveFreshAudio:data numFrames:numFrames numChannels:numChannels];
NSLog(@"Time: %f", fileReader.currentTime);
}];
最初の方法は float を使用し、2 番目の方法は URL を使用するため、ここで本当に混乱し始めます。
「caf」ファイルをフロートに渡すにはどうすればよいですか? Novocaine の実装方法がわかりません。まだ頭の中が曖昧です。
誰かが私を助けてくれることを願っている私の質問は次のとおりです...
Novocaine オブジェクトは AVAudioPlayer オブジェクトに似ていますか? つまり、自己完結型のオーディオ再生 (/録音/生成) ユニットですか?
ノボカインをそのままモデルに使用できますか? つまり、クロマチック ノートごとに 1 つのノボカイン オブジェクト、またはすべてのクロマチック ノートを含むノボカイン オブジェクトを 1 つ持つ必要がありますか? それとも、代わりにメモに URL を保存して、それを Novocaine プレーヤーに渡しますか?
オーディオが「caf」ファイルで、「audioToPlay」がフロートを取る場合、オーディオを「audioToPlay」に入れるにはどうすればよいですか?
Note.m に Novocaine プロパティを含めて宣言した場合、Novocaine オブジェクトを使用するには、クラスの名前を Note.mm に変更する必要がありますか?
和音と音程を再現するために、複数の Novocaine オブジェクトを同時に再生するにはどうすればよいですか?
Novocaine オブジェクトの再生をループできますか?
ノートの再生の長さを設定できますか? つまり、10 秒の音符を 1 秒間だけ再生しますか?
Novocaine を使用するように上記のコードを変更できますか?
私が runMusicGenerator に使用している方法は、プロの基準に達したテンポを維持するために使用する正しいものですか?