From 40d9574015c8d295a6e87fac34d4af925fb62de8 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Fri, 28 Mar 2025 01:30:05 -0700 Subject: [PATCH] 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 --- Plugins/MIDI/MIDI.xcodeproj/project.pbxproj | 4 +++ Plugins/MIDI/MIDI/AUPlayer.mm | 32 ++++++++++++--------- Plugins/MIDI/MIDI/MIDIPlayer.cpp | 18 ++++++------ 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj b/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj index 7fe282cb3..472d06a0c 100644 --- a/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj +++ b/Plugins/MIDI/MIDI.xcodeproj/project.pbxproj @@ -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 = ""; }; 83C35703180EDD1C007E9DF0 /* MIDIMetadataReader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MIDIMetadataReader.mm; sourceTree = ""; }; 83C35704180EDD1C007E9DF0 /* MIDIMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIMetadataReader.h; sourceTree = ""; }; + 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 = ""; }; 83E973461C4378880007F413 /* AUPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AUPlayer.h; sourceTree = ""; }; 83EA54212A6A6CE200CD0580 /* libbass_mpc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbass_mpc.dylib; path = ../../ThirdParty/BASS/libbass_mpc.dylib; sourceTree = ""; }; @@ -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 */, diff --git a/Plugins/MIDI/MIDI/AUPlayer.mm b/Plugins/MIDI/MIDI/AUPlayer.mm index 464c36981..aaedd1f9a 100644 --- a/Plugins/MIDI/MIDI/AUPlayer.mm +++ b/Plugins/MIDI/MIDI/AUPlayer.mm @@ -1,6 +1,8 @@ -#include "AUPlayer.h" +#import "AUPlayer.h" -#include +#import + +#import #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; diff --git a/Plugins/MIDI/MIDI/MIDIPlayer.cpp b/Plugins/MIDI/MIDI/MIDIPlayer.cpp index ce3a125b8..57934f8a3 100644 --- a/Plugins/MIDI/MIDI/MIDIPlayer.cpp +++ b/Plugins/MIDI/MIDI/MIDIPlayer.cpp @@ -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