Delta calculation between MIDIPackets do not seem to be right

こ雲淡風輕ζ 提交于 2020-01-03 04:03:41

问题


I am trying to read a midi file, and play all the midi events with a synthesizer. The way the synth works is, it has a circular buffer which you write midi data to, and then call GenerateSamples() on it, and it will process that midi data, and give you back the number of samples you want. I'm using AudioToolbox's music player, and have setup a MidiReadProc where I write those midi packets to a buffer, and then have a separate thread polling that buffer, and writing the data to the ring buffer, and generating the appropriate number of samples. I'm taking the delta of the timestamp of the current MIDIPacket, and the previous MIDIPacket. The result is, for the most part, the duration of all note events are wrong, and note events start at the wrong time-- which can only mean the deltas between the timestamps are wrong.. And I don't understand how that can be.

My MidiReadProc is:

static void midiReadProc(const MIDIPacketList *pktlist,
                         void *refCon,
                         void *connRefCon) {

    struct MidiData *midiData = (struct MidiData *)refCon;

    MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
    for (int i = 0; i < pktlist->numPackets; i++) {
        NSUInteger channel = packet->data[0] & 0xf;
        FMInstrument *fmInstrument = midiData->fmInstruments[channel];
        [fmInstrument enqueueMidiPacket:*packet];
        packet = MIDIPacketNext(packet);
    }
}

And FMInstrument's enqueueMidiPacket: does:

-(void)enqueueMidiPacket:(MIDIPacket)packet {
    _midiPackets[_midiPacketWriteIndex] = packet;
    _midiPacketWriteIndex += 1;
}

Meanwhile, when FMInstrument is initialized, it kicks off a poller thread:

-(instancetype)init {
    if (self = [super init]) {
        _ringBuffer       = new RingBuffer();
        _synthUnit        = new SynthUnit(_ringBuffer);
        _maxBufferIndex   = (int)([self sampleRate] * 45) - 1;
        _generatedSamples = (short *)calloc(_maxBufferIndex + 1, sizeof(short));
        _midiPackets      = (MIDIPacket *)calloc(1024, sizeof(MIDIPacket));
        _bufferReadIndex  = 0;
        _bufferWriteIndex = 0;
        _midiPacketReadIndex  = 0;
        _midiPacketWriteIndex = 0;
        _lastMidiPacket       = {0};
        mach_timebase_info_data_t sTimebaseInfo;
        mach_timebase_info(&sTimebaseInfo);

        _nanoSecondsToSeconds = sTimebaseInfo.numer / sTimebaseInfo.denom / 1000000000.0;

        [NSThread detachNewThreadSelector:@selector(startPolling) toTarget:self withObject:nil];
    }
    return self;
}

and the polling method:

-(void)startPolling {
    while ([self shouldPoll]) {
        @autoreleasepool {
            if (_midiPacketWriteIndex <= _midiPacketReadIndex) continue;
            MIDIPacket midiPacket     = _midiPackets[_midiPacketReadIndex];
            MIDIPacket lastMidiPacket = _lastMidiPacket;

            _ringBuffer->Write(midiPacket.data, midiPacket.length);
            BOOL isFirstEvent = !_lastMidiPacket.timeStamp;
            _lastMidiPacket = midiPacket;
            if (isFirstEvent) continue;

            _midiPacketReadIndex += 1;
            double delta = (midiPacket.timeStamp * _nanoSecondsToSeconds) - (lastMidiPacket.timeStamp *_nanoSecondsToSeconds);

            int numberOfSamplesToGenerate = ceil([self sampleRate] * delta);
            short *tempBuffer = (short *)malloc(sizeof(short) * numberOfSamplesToGenerate);
            _synthUnit->GetSamples(numberOfSamplesToGenerate, tempBuffer);

            for (int i = 0; i < numberOfSamplesToGenerate && _bufferWriteIndex <= _maxBufferIndex; i++) {
                _generatedSamples[_bufferWriteIndex] = tempBuffer[i];
                _bufferWriteIndex += 1;
            }

            free(tempBuffer);
            [NSThread sleepForTimeInterval:0.05f];
        }
    }
}

So I am assuming, these two lines must be incorrect:

double delta = (midiPacket.timeStamp * _nanoSecondsToSeconds) - (lastMidiPacket.timeStamp *_nanoSecondsToSeconds);
int numberOfSamplesToGenerate = ceil([self sampleRate] * delta);

Can anyone tell me what I am doing wrong?

来源:https://stackoverflow.com/questions/37328670/delta-calculation-between-midipackets-do-not-seem-to-be-right

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!