Могу ли я немного помочь с этим?
В тестовом проекте у меня есть AUSampler -> MixerUnit -> ioUnit
и настроен обратный вызов рендеринга. Все работает. Я использую метод MusicDeviceMIDIEvent
, как определено в MusicDevice.h
, для воспроизведения миди-ноты On и noteOff. Таким образом, в приведенном ниже коде хакерского теста noteOn происходит в течение 0,5 секунды. каждые 2 секунды.
MusicDeviceMIDIEvent
(ниже) принимает параметр: inOffsetSampleFrame
для планирования события в будущем. Что я хотел бы сделать, так это воспроизвести noteOn и запланировать noteOff одновременно (без проверки времени взлома, которую я делаю ниже). Я просто не понимаю, каким должно быть значение inOffsetSampleFrame
(например, для воспроизведения ноты длительностью 0,5 или 0,2 секунды.(другими словами, я не понимаю основ синхронизации звука...).
Итак, если бы кто-нибудь мог объяснить мне арифметические действия, чтобы получить правильные значения из входящего AudioTimeStamp
, это было бы здорово! Также, возможно, поправьте меня/уточните что-либо из этого:
AudioTimeStamp->mSampleTime
- sampleTime - это время
текущий образец "кусочка"? Это в миллисекундах?
AudioTimeStamp->mHostTime
- ? хост - это компьютер, на котором запущено приложение, и это время (в миллисекундах?) с момента запуска компьютера? Это ОГРОМНОЕчисло. Не переворачивается и не вызывает проблем?
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);
}
}