diff --git a/Audio/Chain/AudioChunk.h b/Audio/Chain/AudioChunk.h index 5e9ac5f61..bc56986f2 100644 --- a/Audio/Chain/AudioChunk.h +++ b/Audio/Chain/AudioChunk.h @@ -84,6 +84,7 @@ enum { - (id)initWithProperties:(NSDictionary *)properties; - (void)assignSamples:(const void *)data frameCount:(size_t)count; +- (void)assignData:(NSData *)data; - (NSData *)removeSamples:(size_t)frameCount; diff --git a/Audio/Chain/AudioChunk.m b/Audio/Chain/AudioChunk.m index e119e3597..679864b60 100644 --- a/Audio/Chain/AudioChunk.m +++ b/Audio/Chain/AudioChunk.m @@ -148,13 +148,19 @@ static const uint32_t AudioChannelConfigTable[] = { } } +- (void)assignData:(NSData *)data { + [chunkData appendData:data]; +} + - (NSData *)removeSamples:(size_t)frameCount { if(formatAssigned) { - const size_t bytesPerPacket = format.mBytesPerPacket; - const size_t byteCount = bytesPerPacket * frameCount; - NSData *ret = [chunkData subdataWithRange:NSMakeRange(0, byteCount)]; - [chunkData replaceBytesInRange:NSMakeRange(0, byteCount) withBytes:NULL length:0]; - return ret; + @autoreleasepool { + const size_t bytesPerPacket = format.mBytesPerPacket; + const size_t byteCount = bytesPerPacket * frameCount; + NSData *ret = [chunkData subdataWithRange:NSMakeRange(0, byteCount)]; + [chunkData replaceBytesInRange:NSMakeRange(0, byteCount) withBytes:NULL length:0]; + return ret; + } } return [NSData data]; } diff --git a/Audio/Chain/ChunkList.m b/Audio/Chain/ChunkList.m index 4ccb88da4..04df44bcc 100644 --- a/Audio/Chain/ChunkList.m +++ b/Audio/Chain/ChunkList.m @@ -464,7 +464,7 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes AudioChunk *ret = [[AudioChunk alloc] init]; [ret setFormat:[chunk format]]; [ret setChannelConfig:[chunk channelConfig]]; - [ret assignSamples:[removedData bytes] frameCount:maxFrameCount]; + [ret assignData:removedData]; listDuration -= [ret duration]; inRemover = NO; return ret; diff --git a/Audio/Output/FSurroundFilter.mm b/Audio/Output/FSurroundFilter.mm index 2b6f0e31b..24e02de82 100644 --- a/Audio/Output/FSurroundFilter.mm +++ b/Audio/Output/FSurroundFilter.mm @@ -126,6 +126,12 @@ struct freesurround_params { freesurround_decoder *_decoder = (freesurround_decoder *)decoder; float tempInput[4096 * 2]; + uint32_t zeroCount = 0; + + if(count > 4096) { + zeroCount = count - 4096; + count = 4096; + } if(count < 4096) { cblas_scopy(count * 2, samplesIn, 1, &tempInput[0], 1); @@ -138,6 +144,9 @@ struct freesurround_params { for(unsigned c = 0, num = channelCount; c < num; c++) { unsigned idx = [AudioChunk channelIndexFromConfig:channelConfig forFlag:_params->chanmap[c]]; cblas_scopy(count, src + c, num, samplesOut + idx, num); + if(zeroCount) { + vDSP_vclr(samplesOut + idx + count, num, zeroCount); + } } } diff --git a/Audio/Output/OutputAVFoundation.h b/Audio/Output/OutputAVFoundation.h index 7dc443e44..bbf9c64d4 100644 --- a/Audio/Output/OutputAVFoundation.h +++ b/Audio/Output/OutputAVFoundation.h @@ -114,6 +114,7 @@ using std::atomic_long; FSurroundFilter *fsurround; float *samplePtr; + float tempBuffer[512 * 32]; float inputBuffer[4096 * 32]; // 4096 samples times maximum supported channel count float fsurroundBuffer[4096 * 6]; float hrtfBuffer[4096 * 2]; diff --git a/Audio/Output/OutputAVFoundation.m b/Audio/Output/OutputAVFoundation.m index fd42b6ccc..9c7a9aca7 100644 --- a/Audio/Output/OutputAVFoundation.m +++ b/Audio/Output/OutputAVFoundation.m @@ -745,7 +745,10 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons int bytesRendered = 0; do { int maxToRender = MIN(4096 - inputRendered, 512); - int rendered = [self renderInput:maxToRender toBuffer:(float *)(((uint8_t *)inputBuffer) + bytesRendered)]; + int rendered = [self renderInput:maxToRender toBuffer:&tempBuffer[0]]; + if(rendered > 0) { + memcpy((((uint8_t *)inputBuffer) + bytesRendered), &tempBuffer[0], rendered * newFormat.mBytesPerPacket); + } inputRendered += rendered; bytesRendered += rendered * newFormat.mBytesPerPacket; if(streamFormatChanged) { @@ -886,6 +889,8 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons commandStop = NO; audioFormatDescription = NULL; + + enableFSurround = YES; running = NO; stopping = NO; diff --git a/Audio/ThirdParty/fsurround/freesurround_decoder.cpp b/Audio/ThirdParty/fsurround/freesurround_decoder.cpp index bd38036fa..361dfb59b 100755 --- a/Audio/ThirdParty/fsurround/freesurround_decoder.cpp +++ b/Audio/ThirdParty/fsurround/freesurround_decoder.cpp @@ -63,19 +63,19 @@ class decoder_impl { public: // instantiate the decoder with a given channel setup and processing block size (in samples) decoder_impl(channel_setup setup, unsigned N) - : N(N), log2N(log2n(N)), Nover2((N + 1) / 2), + : N(N), log2N(log2n(N)), wnd(N), inbuf(3 * N), setup(setup), C((unsigned)chn_alloc[setup].size()), buffer_empty(true), lt(N), rt(N), dst(N), dstf(N), dftsetupF(vDSP_DFT_zrop_CreateSetupD(0, N, vDSP_DFT_FORWARD)), dftsetupB(vDSP_DFT_zrop_CreateSetupD(0, N, vDSP_DFT_INVERSE)) { - _dsp_complexalloc(&lf, Nover2); - _dsp_complexalloc(&rf, Nover2); + _dsp_complexalloc(&lf, N/2 + 1); + _dsp_complexalloc(&rf, N/2 + 1); // allocate per-channel buffers outbuf.resize((N + N / 2) * C); signal.resize(C); for(unsigned k = 0; k < C; k++) - _dsp_complexalloc(&signal[k], N); + _dsp_complexalloc(&signal[k], N/2 + 1); // init the window function for(unsigned k = 0; k < N; k++) @@ -209,8 +209,8 @@ class decoder_impl { vDSP_vmulD(&rt[0], 1, &wnd[0], 1, &rt[0], 1, N); // map into spectral domain - vDSP_ctozD((DSPDoubleComplex *)(<[0]), 2, &lf, 1, Nover2); - vDSP_ctozD((DSPDoubleComplex *)(&rt[0]), 2, &rf, 1, Nover2); + vDSP_ctozD((DSPDoubleComplex *)(<[0]), 2, &lf, 1, N / 2); + vDSP_ctozD((DSPDoubleComplex *)(&rt[0]), 2, &rf, 1, N / 2); vDSP_DFT_ExecuteD(dftsetupF, lf.realp, lf.imagp, lf.realp, lf.imagp); vDSP_DFT_ExecuteD(dftsetupF, rf.realp, rf.imagp, rf.realp, rf.imagp); @@ -218,6 +218,8 @@ class decoder_impl { for(unsigned c = 0; c < C; c++) { signal[c].realp[0] = 0; signal[c].imagp[0] = 0; + signal[c].realp[N/2] = 0; + signal[c].imagp[N/2] = 0; } // compute multichannel output signal in the spectral domain @@ -253,7 +255,7 @@ class decoder_impl { // map position to channel volumes for(unsigned c = 0; c < C - 1; c++) { // look up channel map at respective position (with bilinear interpolation) and build the signal - vector &a = chn_alloc[setup][c]; + const vector &a = chn_alloc[setup][c]; polar(amp_total * ((1 - x) * (1 - y) * a[q][p] + x * (1 - y) * a[q][p + 1] + (1 - x) * y * a[q + 1][p] + x * y * a[q + 1][p + 1]), phase_of[1 + (int)sign(chn_xsf[setup][c])], signal[c], f); } @@ -275,14 +277,14 @@ class decoder_impl { } // shift the last 2/3 to the first 2/3 of the output buffer - memcpy(&outbuf[0], &outbuf[C * N / 2], N * C * 4); + memmove(&outbuf[0], &outbuf[C * N / 2], N * C * 4); // and clear the rest memset(&outbuf[C * N], 0, C * 4 * N / 2); // backtransform each channel and overlap-add for(unsigned c = 0; c < C; c++) { // back-transform into time domain vDSP_DFT_ExecuteD(dftsetupB, signal[c].realp, signal[c].imagp, signal[c].realp, signal[c].imagp); - vDSP_ztocD(&signal[c], 1, (DSPDoubleComplex *)(&dst[0]), 2, Nover2); + vDSP_ztocD(&signal[c], 1, (DSPDoubleComplex *)(&dst[0]), 2, N / 2); // add the result to the last 2/3 of the output buffer, windowed (and remultiplex) vDSP_vmulD(&dst[0], 1, &wnd[0], 1, &dst[0], 1, N); vDSP_vdpsp(&dst[0], 1, &dstf[0], 1, N); @@ -334,7 +336,7 @@ class decoder_impl { // constants unsigned N, C; // number of samples per input/output block, number of output channels - unsigned log2N, Nover2; // derivations of the block size + unsigned log2N; // derivations of the block size channel_setup setup; // the channel setup // parameters