MIDI: Fix Audio Unit player in several ways

Improve rendering functions of Audio Unit player, and also fix looping
for the Audio Unit player, and any other possible future players which
use blocked decoding with timestamped events.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-03-28 01:30:05 -07:00
parent 8337dee1d1
commit a3ef8c6764
3 changed files with 33 additions and 21 deletions

View file

@ -37,6 +37,7 @@
83B06722180D70FE008E3612 /* MIDIDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83B06721180D70FE008E3612 /* MIDIDecoder.mm */; };
83C35702180EDB74007E9DF0 /* MIDIContainer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35700180EDB74007E9DF0 /* MIDIContainer.mm */; };
83C35705180EDD1C007E9DF0 /* MIDIMetadataReader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */; };
83E83F7B2D9654470054365C /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83E83F7A2D9654470054365C /* Accelerate.framework */; };
83E973471C4378880007F413 /* AUPlayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83E973451C4378880007F413 /* AUPlayer.mm */; };
83EA54232A6A6CF400CD0580 /* libbass_mpc.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83EA54212A6A6CE200CD0580 /* libbass_mpc.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
/* End PBXBuildFile section */
@ -155,6 +156,7 @@
83C35701180EDB74007E9DF0 /* MIDIContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIContainer.h; sourceTree = "<group>"; };
83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MIDIMetadataReader.mm; sourceTree = "<group>"; };
83C35704180EDD1C007E9DF0 /* MIDIMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIMetadataReader.h; sourceTree = "<group>"; };
83E83F7A2D9654470054365C /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
83E973451C4378880007F413 /* AUPlayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AUPlayer.mm; sourceTree = "<group>"; };
83E973461C4378880007F413 /* AUPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUPlayer.h; sourceTree = "<group>"; };
83EA54212A6A6CE200CD0580 /* libbass_mpc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbass_mpc.dylib; path = ../../ThirdParty/BASS/libbass_mpc.dylib; sourceTree = "<group>"; };
@ -168,6 +170,7 @@
buildActionMask = 2147483647;
files = (
834D190C2D7F954100F13B89 /* CogAudio.framework in Frameworks */,
83E83F7B2D9654470054365C /* Accelerate.framework in Frameworks */,
8398F2E01C438C7D00EB9639 /* AudioUnit.framework in Frameworks */,
83686AB11C5C783000671C7A /* CoreAudioKit.framework in Frameworks */,
83B06701180D5747008E3612 /* midi_processing.framework in Frameworks */,
@ -281,6 +284,7 @@
83B06689180D5668008E3612 /* Frameworks */ = {
isa = PBXGroup;
children = (
83E83F7A2D9654470054365C /* Accelerate.framework */,
834D190B2D7F954100F13B89 /* CogAudio.framework */,
83686AB01C5C783000671C7A /* CoreAudioKit.framework */,
83686AAE1C5C780500671C7A /* AudioToolbox.framework */,

View file

@ -1,6 +1,8 @@
#include "AUPlayer.h"
#import "AUPlayer.h"
#include <stdlib.h>
#import <stdlib.h>
#import <Accelerate/Accelerate.h>
#define SF2PACK
@ -82,29 +84,33 @@ void AUPlayer::send_sysex_time(const uint8_t *data, size_t size, size_t port, un
}
void AUPlayer::render(float *out, unsigned long count) {
float *ptrL, *ptrR;
memset(out, 0, count * sizeof(float) * 2);
const float *ptrL, *ptrR;
bzero(out, count * sizeof(float) * 2);
while(count) {
UInt32 numberFrames = count > BLOCK_SIZE ? BLOCK_SIZE : (UInt32)count;
for(unsigned long i = 0; i < 3; ++i) {
AudioUnitRenderActionFlags ioActionFlags = 0;
bufferList->mNumberBuffers = 2;
for(unsigned long j = 0; j < 2; j++) {
bufferList->mBuffers[j].mNumberChannels = 1;
bufferList->mBuffers[j].mDataByteSize = (UInt32)(numberFrames * sizeof(float));
bufferList->mBuffers[j].mData = audioBuffer + j * BLOCK_SIZE;
memset(bufferList->mBuffers[j].mData, 0, numberFrames * sizeof(float));
bzero(bufferList->mBuffers[j].mData, numberFrames * sizeof(float));
}
AudioUnitRender(samplerUnit[i], &ioActionFlags, &mTimeStamp, 0, numberFrames, bufferList);
ptrL = (float *)bufferList->mBuffers[0].mData;
ptrR = (float *)bufferList->mBuffers[1].mData;
for(unsigned long j = 0; j < numberFrames; ++j) {
out[j * 2 + 0] += ptrL[j];
out[j * 2 + 1] += ptrR[j];
}
ptrL = (const float *)bufferList->mBuffers[0].mData;
ptrR = (const float *)bufferList->mBuffers[1].mData;
size_t numBytesL = bufferList->mBuffers[0].mDataByteSize;
size_t numBytesR = bufferList->mBuffers[1].mDataByteSize;
size_t numBytes = MIN(numBytesL, numBytesR);
size_t numFrames = numBytes / sizeof(float);
numFrames = MIN(numFrames, numberFrames);
vDSP_vadd(ptrL, 1, out, 2, out, 2, numFrames);
vDSP_vadd(ptrR, 1, out + 1, 2, out + 1, 2, numFrames);
}
out += numberFrames * 2;
@ -214,7 +220,7 @@ static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioAct
int k = inNumberFrames * sizeof(float);
if(k > ioData->mBuffers[i].mDataByteSize)
k = ioData->mBuffers[i].mDataByteSize;
memset(ioData->mBuffers[i].mData, 0, k);
bzero(ioData->mBuffers[i].mData, k);
}
}
@ -222,7 +228,7 @@ static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioAct
}
bool AUPlayer::startup() {
if(bufferList) return true;
if(initialized) return true;
AudioComponentDescription cd = { 0 };
cd.componentType = kAudioUnitType_MusicDevice;

View file

@ -148,8 +148,8 @@ unsigned long MIDIPlayer::Play(float *out, unsigned long count) {
for(; uStreamPosition < stream_end; uStreamPosition++) {
const midi_stream_event &me = mStream.at(uStreamPosition);
unsigned long samples_todo = me.m_timestamp - uTimeCurrent - into_block;
if(samples_todo) {
ssize_t samples_todo = me.m_timestamp - uTimeCurrent - into_block;
if(samples_todo > 0) {
if(samples_todo > count - done) {
uSamplesRemaining = samples_todo - (count - done);
samples_todo = count - done;
@ -167,12 +167,14 @@ unsigned long MIDIPlayer::Play(float *out, unsigned long count) {
}
if(needs_block_size) {
into_block += samples_todo;
while(into_block >= needs_block_size) {
render(out + done * 2, needs_block_size);
done += needs_block_size;
into_block -= needs_block_size;
uTimeCurrent += needs_block_size;
if(samples_todo > 0) {
into_block += samples_todo;
while(into_block >= needs_block_size) {
render(out + done * 2, needs_block_size);
done += needs_block_size;
into_block -= needs_block_size;
uTimeCurrent += needs_block_size;
}
}
send_event_time_filtered(me.m_event, into_block);
} else