Могу ли я получить небольшую помощь с этим?
В тестовом проекте у меня есть AUSampler -> MixerUnit -> ioUnit
и настроен обратный вызов рендеринга. Все работает Я использую метод MusicDeviceMIDIEvent
, как определено в MusicDevice.h
, для воспроизведения midi noteOn & noteOff. Таким образом, в коде хакерского теста ниже, noteOn происходит в течение .5 сек. каждые 2 секунды.
MusicDeviceMIDIEvent
(ниже) принимает параметр: inOffsetSampleFrame
, чтобы запланировать событие на будущее. То, что я хотел бы сделать, это сыграть noteOn и запланировать noteOff одновременно (без проверки времени взлома, которую я делаю ниже). Я просто не понимаю, каким должно быть значение inOffsetSampleFrame
(например, чтобы воспроизвести ноту в 0,5 секунды или 0,2 секунды. (Другими словами, я не понимаю основы звуковой синхронизации ...).
Так что, если бы кто-то мог провести меня через арифметику, чтобы получить правильные значения из входящего AudioTimeStamp
, это было бы здорово! Также, возможно, поправьте меня / уточните любой из этих:
AudioTimeStamp->mSampleTime
- sampleTime - время
текущий образец "ломтик"? Это в миллисекундах?
AudioTimeStamp->mHostTime
-? host - компьютер, на котором запущено приложение, и это время (в миллисекундах?) с момента запуска компьютера? Это ОГРОМНОЕ число. Разве это не переворачивается, а затем вызывает проблемы?
inNumberFrames
- похоже, это 512 на iOS5 (устанавливается через
kAudioUnitProperty_MaximumFramesPerSlice
). Итак, образец сделан
до 512 кадров?
Я видел много предупреждений, чтобы не перегружать рендеринг.
функция - в частности, чтобы избежать вызовов Objective C - я понимаю
причина, но как тогда сообщать пользовательский интерфейс или делать другие
обработка
Полагаю, все. Спасибо за терпение со мной!
inOffsetSampleFrame
Если вы планируете MIDI-событие из потока рендеринга аудиоустройства, вы можете указать
Смещение сэмпла, которое аудиоустройство может применить, применяя то событие в его следующем рендере аудиоустройства.
Это позволяет вам планировать к образцу время, когда применяется команда MIDI, и особенно
важно при запуске новых заметок. Если вы не планируете в потоке рендеринга аудиоустройства,
тогда вы должны установить это значение на 0
// Функция MusicDeviceMIDIEvent def:
extern OSStatus
MusicDeviceMIDIEvent( MusicDeviceComponent inUnit,
UInt32 inStatus,
UInt32 inData1,
UInt32 inData2,
UInt32 inOffsetSampleFrame)
// мой обратный вызов
OSStatus MyCallback( void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
Float64 sampleTime = inTimeStamp->mSampleTime;
UInt64 hostTime = inTimeStamp->mHostTime;
[(__bridge Audio*)inRefCon audioEvent:sampleTime andHostTime:hostTime];
return 1;
}
// Метод OBJ-C
- (void)audioEvent:(Float64) sampleTime andHostTime:(UInt64)hostTime
{
OSStatus result = noErr;
Float64 nowTime = (sampleTime/self.graphSampleRate); // sample rate: 44100.0
if (nowTime - lastTime > 2) {
UInt32 noteCommand = kMIDIMessage_NoteOn << 4 | 0;
result = MusicDeviceMIDIEvent (mySynthUnit, noteCommand, 60, 120, 0);
lastTime = sampleTime/self.graphSampleRate;
}
if (nowTime - lastTime > .5) {
UInt32 noteCommand = kMIDIMessage_NoteOff << 4 | 0;
result = MusicDeviceMIDIEvent (mySynthUnit, noteCommand, 60, 0, 0);
}
}