From 74b6188772a8b2a888387c93abe70802bba01d1f Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Sat, 5 Oct 2013 14:15:09 -0700 Subject: [PATCH] Implemented floating point sample format support into CogAudio and all relevant plug-ins --- Audio/Chain/InputNode.h | 1 + Audio/Chain/InputNode.m | 103 ++++++++++-- .../CoreAudioUtils/CoreAudioUtils.m | 8 +- Playlist/PlaylistEntry.h | 2 + Playlist/PlaylistEntry.m | 1 + Plugins/CoreAudio/CoreAudioDecoder.h | 1 + Plugins/CoreAudio/CoreAudioDecoder.m | 16 +- Plugins/Dumb/DumbDecoder.h | 3 +- Plugins/Dumb/DumbDecoder.m | 68 +++++--- Plugins/MAD/MADDecoder.h | 15 -- Plugins/MAD/MADDecoder.m | 154 ++---------------- Plugins/Musepack/MusepackDecoder.h | 2 +- Plugins/Musepack/MusepackDecoder.m | 31 ++-- Plugins/Opus/Opus/OpusDecoder.m | 14 +- Plugins/Vorbis/VorbisDecoder.m | 18 +- Plugins/WMA/WMADecoder.h | 1 + Plugins/WMA/WMADecoder.m | 51 ++---- 17 files changed, 227 insertions(+), 262 deletions(-) diff --git a/Audio/Chain/InputNode.h b/Audio/Chain/InputNode.h index 3834a7e93..c0da023de 100644 --- a/Audio/Chain/InputNode.h +++ b/Audio/Chain/InputNode.h @@ -23,6 +23,7 @@ int bytesPerSample; int bytesPerFrame; int volumeScale; + BOOL floatingPoint; BOOL swapEndian; BOOL shouldSeek; diff --git a/Audio/Chain/InputNode.m b/Audio/Chain/InputNode.m index 37102850c..9025b4aad 100644 --- a/Audio/Chain/InputNode.m +++ b/Audio/Chain/InputNode.m @@ -54,6 +54,8 @@ static BOOL hostIsBigEndian() swapEndian = NO; } + floatingPoint = [[properties objectForKey:@"floatingPoint"] boolValue]; + [self refreshVolumeScaling]; shouldContinue = YES; @@ -186,6 +188,34 @@ static int32_t swap_32(uint32_t input) return (input >> 24) | ((input >> 8) & 0xff00) | ((input << 8) & 0xff0000) | (input << 24); } +static float swap_32f(float input) +{ + union { + float f; + int32_t i; + } val; + val.f = input; + val.i = swap_32(val.i); + return val.f; +} + +static int64_t swap_64(uint64_t input) +{ + return (input >> 56) | ((input >> 40) & 0xff00) | ((input >> 24) & 0xff0000) | ((input >> 8) & 0xff000000) | + ((input << 8) & 0xff00000000) | ((input << 24) & 0xff0000000000) | ((input << 40) & 0xff000000000000) | (input << 56); +} + +static double swap_64f(double input) +{ + union { + double f; + int64_t i; + } val; + val.f = input; + val.i = swap_64(val.i); + return val.f; +} + - (void)process { int amountInBuffer = 0; @@ -276,19 +306,70 @@ static int32_t swap_32(uint32_t input) break; case 4: - { - int32_t * samples = (int32_t *)inputBuffer; - for (int i = 0; i < totalFrames; i++) + if (floatingPoint) { - int64_t sample = samples[i]; - if (swapEndian) sample = swap_32(sample); - sample = (sample * volumeScale) >> 12; - if ((unsigned)(sample + 0x80000000) & 0xffffffff00000000) sample = (sample >> 63) ^ 0x7fffffff; - if (swapEndian) sample = swap_32(sample); - samples[i] = sample; + float * samples = (float *)inputBuffer; + float scale = (float)volumeScale / 4096; + for (int i = 0; i < totalFrames; i++) + { + float sample = samples[i]; + if (swapEndian) sample = swap_32f(sample); + sample *= scale; + if (swapEndian) sample = swap_32f(sample); + samples[i] = sample; + } } - } - break; + else + { + int32_t * samples = (int32_t *)inputBuffer; + for (int i = 0; i < totalFrames; i++) + { + int64_t sample = samples[i]; + if (swapEndian) sample = swap_32(sample); + sample = (sample * volumeScale) >> 12; + if ((unsigned)(sample + 0x80000000) & 0xffffffff00000000) sample = (sample >> 63) ^ 0x7fffffff; + if (swapEndian) sample = swap_32(sample); + samples[i] = sample; + } + } + break; + + case 8: + if (floatingPoint) + { + double * samples = (double *)inputBuffer; + double scale = (double)volumeScale / 4096; + for (int i = 0; i < totalFrames; i++) + { + double sample = samples[i]; + if (swapEndian) sample = swap_64f(sample); + sample *= scale; + if (swapEndian) sample = swap_64f(sample); + samples[i] = sample; + } + } + else + { + int64_t * samples = (int64_t *)inputBuffer; + for (int i = 0; i < totalFrames; i++) + { + int64_t sample = samples[i]; + if (swapEndian) sample = swap_64(sample); + int64_t high_part = sample >> (32 + 12); + int64_t low_part = (sample & 0xffffffff) | (sample >> 31); + high_part *= volumeScale; + low_part = (low_part * volumeScale) >> 12; + if (((uint64_t)low_part + 0x100000000) & 0xfffffffe00000000) + high_part += low_part >> 32; + if (((uint64_t)high_part + 0x80000000) & 0xffffffff00000000) + sample = high_part >> 63; + else + sample = (high_part << 32) | (low_part & 0xffffffff); + if (swapEndian) sample = swap_64(sample); + samples[i] = sample; + } + } + break; } } diff --git a/Audio/ThirdParty/CoreAudioUtils/CoreAudioUtils.m b/Audio/ThirdParty/CoreAudioUtils/CoreAudioUtils.m index dfb280d00..9a697cf9a 100644 --- a/Audio/ThirdParty/CoreAudioUtils/CoreAudioUtils.m +++ b/Audio/ThirdParty/CoreAudioUtils/CoreAudioUtils.m @@ -47,6 +47,8 @@ AudioStreamBasicDescription propertiesToASBD(NSDictionary *properties) asbd.mFramesPerPacket = 1; asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket; asbd.mReserved = 0; + + BOOL isFloat = [[properties objectForKey:@"floatingPoint"] boolValue]; if ([[properties objectForKey:@"endian"] isEqualToString:@"big"] || ([[properties objectForKey:@"endian"] isEqualToString:@"host"] && hostIsBigEndian() )) { @@ -54,9 +56,13 @@ AudioStreamBasicDescription propertiesToASBD(NSDictionary *properties) asbd.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; } - if ([[properties objectForKey:@"unsigned"] boolValue] == NO) { + if (isFloat == NO && [[properties objectForKey:@"unsigned"] boolValue] == NO) { asbd.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; } + + if (isFloat) { + asbd.mFormatFlags |= kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsPacked; + } return asbd; } diff --git a/Playlist/PlaylistEntry.h b/Playlist/PlaylistEntry.h index 27ccd55a4..cbaec9c73 100644 --- a/Playlist/PlaylistEntry.h +++ b/Playlist/PlaylistEntry.h @@ -45,6 +45,7 @@ int bitrate; int channels; int bitsPerSample; + BOOL floatingPoint; float sampleRate; NSString *endian; @@ -100,6 +101,7 @@ @property int bitrate; @property int channels; @property int bitsPerSample; +@property BOOL floatingPoint; @property float sampleRate; @property float replayGainAlbumGain; diff --git a/Playlist/PlaylistEntry.m b/Playlist/PlaylistEntry.m index 667d86fd1..a530caba8 100644 --- a/Playlist/PlaylistEntry.m +++ b/Playlist/PlaylistEntry.m @@ -38,6 +38,7 @@ @synthesize bitrate; @synthesize channels; @synthesize bitsPerSample; +@synthesize floatingPoint; @synthesize sampleRate; @synthesize replayGainAlbumGain; diff --git a/Plugins/CoreAudio/CoreAudioDecoder.h b/Plugins/CoreAudio/CoreAudioDecoder.h index 0488ca02d..c6965af3e 100644 --- a/Plugins/CoreAudio/CoreAudioDecoder.h +++ b/Plugins/CoreAudio/CoreAudioDecoder.h @@ -31,6 +31,7 @@ int bitrate; int bitsPerSample; + BOOL floatingPoint; int channels; float frequency; long totalFrames; diff --git a/Plugins/CoreAudio/CoreAudioDecoder.m b/Plugins/CoreAudio/CoreAudioDecoder.m index 5226d05e8..8b25dcd9f 100644 --- a/Plugins/CoreAudio/CoreAudioDecoder.m +++ b/Plugins/CoreAudio/CoreAudioDecoder.m @@ -84,10 +84,12 @@ bitsPerSample = asbd.mBitsPerChannel; channels = asbd.mChannelsPerFrame; frequency = asbd.mSampleRate; - + floatingPoint = NO; + // mBitsPerChannel will only be set for lpcm formats if(0 == bitsPerSample) { - bitsPerSample = 16; + bitsPerSample = 32; + floatingPoint = YES; } // Set output format @@ -96,7 +98,12 @@ bzero(&result, sizeof(AudioStreamBasicDescription)); result.mFormatID = kAudioFormatLinearPCM; - result.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian; + if (floatingPoint) { + result.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; + } + else { + result.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian; + } result.mSampleRate = frequency; result.mChannelsPerFrame = channels; @@ -177,11 +184,12 @@ return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels],@"channels", [NSNumber numberWithInt:bitsPerSample],@"bitsPerSample", + [NSNumber numberWithBool:floatingPoint],@"floatingPoint", [NSNumber numberWithInt:bitrate],@"bitrate", [NSNumber numberWithFloat:frequency],@"sampleRate", [NSNumber numberWithLong:totalFrames],@"totalFrames", [NSNumber numberWithBool:YES], @"seekable", - @"big", @"endian", + floatingPoint ? @"host" : @"big", @"endian", nil]; } diff --git a/Plugins/Dumb/DumbDecoder.h b/Plugins/Dumb/DumbDecoder.h index 00c5b66e7..7760fe2c6 100755 --- a/Plugins/Dumb/DumbDecoder.h +++ b/Plugins/Dumb/DumbDecoder.h @@ -18,7 +18,8 @@ extern DUMBFILE *dumbfile_open_memory_and_free(char *data, long size); @interface DumbDecoder : NSObject { DUH *duh; DUH_SIGRENDERER *dsr; - + sample_t **sampptr; + id source; long length; diff --git a/Plugins/Dumb/DumbDecoder.m b/Plugins/Dumb/DumbDecoder.m index 0297f90d1..820f4aa1a 100755 --- a/Plugins/Dumb/DumbDecoder.m +++ b/Plugins/Dumb/DumbDecoder.m @@ -185,6 +185,8 @@ int callbackLoop(void *data) loops = 0; fadeTotal = fadeRemain = 44100 * 8; + sampptr = allocate_sample_buffer(2, 1024); + [self willChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"]; @@ -197,7 +199,8 @@ int callbackLoop(void *data) [NSNumber numberWithInt:0], @"bitrate", [NSNumber numberWithFloat:44100], @"sampleRate", [NSNumber numberWithDouble:((length / 65.536f)*44.1000)], @"totalFrames", - [NSNumber numberWithInt:16], @"bitsPerSample", //Samples are short + [NSNumber numberWithInt:32], @"bitsPerSample", //Samples are short + [NSNumber numberWithBool:YES], @"floatingPoint", [NSNumber numberWithInt:2], @"channels", //output from gme_play is in stereo [NSNumber numberWithBool:[source seekable]], @"seekable", @"host", @"endian", @@ -206,27 +209,49 @@ int callbackLoop(void *data) - (int)readAudio:(void *)buf frames:(UInt32)frames { - int rendered = duh_render(dsr, 16 /* shorts */, 0 /* not unsigned */, 1.0 /* volume */, 65536.0f / 44100.0f /* 65536 hz? */, frames, buf); - - if ( loops >= 2 ) { - int16_t * sampleBuf = ( int16_t * ) buf; - long fadeEnd = fadeRemain - rendered; - if ( fadeEnd < 0 ) - fadeEnd = 0; - for ( long fadePos = fadeRemain; fadePos > fadeEnd; --fadePos ) { - long offset = (fadeRemain - fadePos) * 2; - int64_t sampleLeft = sampleBuf[ offset + 0 ]; - int64_t sampleRight = sampleBuf[ offset + 1 ]; - sampleLeft = (sampleLeft * fadePos) / fadeTotal; - sampleRight = (sampleRight * fadePos) / fadeTotal; - sampleBuf[ offset + 0 ] = sampleLeft; - sampleBuf[ offset + 1 ] = sampleRight; + int total = 0; + while ( total < frames ) { + int framesToRender = 1024; + if ( framesToRender > frames ) + framesToRender = frames; + dumb_silence( sampptr[0], framesToRender * 2 ); + int rendered = duh_sigrenderer_generate_samples( dsr, 1.0, 65536.0f / 44100.0f, framesToRender, sampptr ); + + if (rendered <= 0) + break; + + for ( int i = 0; i < rendered * 2; i++ ) { + const float scale = 1.0 / 0x800000; + ((float *)buf)[(total * 2) + i] = (float)sampptr[0][i] * scale; } - rendered = fadeRemain - fadeEnd; - fadeRemain = fadeEnd; + + if ( loops >= 2 ) { + float * sampleBuf = ( float * ) buf; + long fadeEnd = fadeRemain - rendered; + if ( fadeEnd < 0 ) + fadeEnd = 0; + float fadePosf = (float)fadeRemain / fadeTotal; + const float fadeStep = 1.0 / fadeTotal; + for ( long fadePos = fadeRemain; fadePos > fadeEnd; --fadePos, fadePosf -= fadeStep ) { + long offset = (fadeRemain - fadePos) * 2; + float sampleLeft = sampleBuf[ offset + 0 ]; + float sampleRight = sampleBuf[ offset + 1 ]; + sampleLeft *= fadePosf; + sampleRight *= fadePosf; + sampleBuf[ offset + 0 ] = sampleLeft; + sampleBuf[ offset + 1 ] = sampleRight; + } + rendered = fadeRemain - fadeEnd; + fadeRemain = fadeEnd; + } + + total += rendered; + + if ( rendered < framesToRender ) + break; } - return rendered; + return total; } - (long)seek:(long)frame @@ -253,6 +278,11 @@ int callbackLoop(void *data) - (void)cleanUp { + if (sampptr) { + destroy_sample_buffer(sampptr); + sampptr = NULL; + } + if (dsr) { duh_end_sigrenderer(dsr); dsr = NULL; diff --git a/Plugins/MAD/MADDecoder.h b/Plugins/MAD/MADDecoder.h index aeb67ec41..97cdaa641 100644 --- a/Plugins/MAD/MADDecoder.h +++ b/Plugins/MAD/MADDecoder.h @@ -14,26 +14,12 @@ #define INPUT_BUFFER_SIZE 5*8192 -struct audio_dither { - mad_fixed_t error[3]; - mad_fixed_t random; -}; - -struct audio_stats { - unsigned long clipped_samples; - mad_fixed_t peak_clipping; - mad_fixed_t peak_sample; -}; - @interface MADDecoder : NSObject { struct mad_stream _stream; struct mad_frame _frame; struct mad_synth _synth; - struct audio_dither channel_dither[2]; - struct audio_stats stats; - unsigned char _inputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]; unsigned char *_outputBuffer; int _outputFrames; @@ -57,7 +43,6 @@ struct audio_stats { int bytesPerFrame; int channels; - int bitsPerSample; float sampleRate; int bitrate; long totalFrames; diff --git a/Plugins/MAD/MADDecoder.m b/Plugins/MAD/MADDecoder.m index b532b257e..bc9df836e 100644 --- a/Plugins/MAD/MADDecoder.m +++ b/Plugins/MAD/MADDecoder.m @@ -277,9 +277,7 @@ mad_frame_finish (&frame); mad_stream_finish (&stream); - bitsPerSample = 24; - - bytesPerFrame = (bitsPerSample/8) * channels; + bytesPerFrame = sizeof(float) * channels; [_source seek:0 whence:SEEK_SET]; inputEOF = NO; @@ -321,121 +319,6 @@ return [self scanFile]; } -/* - * NAME: prng() - * DESCRIPTION: 32-bit pseudo-random number generator - */ -static inline -unsigned long prng(unsigned long state) -{ - return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; -} - - -// Clipping and rounding code from madplay(audio.c): -/* - * madplay - MPEG audio decoder and player - * Copyright (C) 2000-2004 Robert Leslie - */ -static inline signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, - struct audio_dither *dither, - struct audio_stats *stats) -{ - unsigned int scalebits; - mad_fixed_t output, mask, random; - - enum { - MIN = -MAD_F_ONE, - MAX = MAD_F_ONE - 1 - }; - - /* noise shape */ - sample += dither->error[0] - dither->error[1] + dither->error[2]; - - dither->error[2] = dither->error[1]; - dither->error[1] = dither->error[0] / 2; - - /* bias */ - output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1)); - - scalebits = MAD_F_FRACBITS + 1 - bits; - mask = (1L << scalebits) - 1; - - /* dither */ - random = prng(dither->random); - output += (random & mask) - (dither->random & mask); - - dither->random = random; - - /* clip */ - if (output >= stats->peak_sample) { - if (output > MAX) { - ++stats->clipped_samples; - if (output - MAX > stats->peak_clipping) - stats->peak_clipping = output - MAX; - - output = MAX; - - if (sample > MAX) - sample = MAX; - } - stats->peak_sample = output; - } - else if (output < -stats->peak_sample) { - if (output < MIN) { - ++stats->clipped_samples; - if (MIN - output > stats->peak_clipping) - stats->peak_clipping = MIN - output; - - output = MIN; - - if (sample < MIN) - sample = MIN; - } - stats->peak_sample = -output; - } - - /* quantize */ - output &= ~mask; - - /* error feedback */ - dither->error[0] = sample - output; - - /* scale */ - return output >> scalebits; -} - -// Clipping and rounding code from madplay(audio.c): -/* - * madplay - MPEG audio decoder and player - * Copyright (C) 2000-2004 Robert Leslie - */ -#if 0 -static int32_t -audio_linear_round(unsigned int bits, - mad_fixed_t sample) -{ - enum { - MIN = -MAD_F_ONE, - MAX = MAD_F_ONE - 1 - }; - - /* round */ - sample += (1L << (MAD_F_FRACBITS - bits)); - - /* clip */ - if(MAX < sample) - sample = MAX; - else if(MIN > sample) - sample = MIN; - - /* quantize and scale */ - return sample >> (MAD_F_FRACBITS + 1 - bits); -} -#endif -// End madplay code - - - (void)writeOutput { unsigned int startingSample = 0; @@ -489,32 +372,19 @@ audio_linear_round(unsigned int bits, int ch; int i; - int stride = bitsPerSample/8; - unsigned char *outputPtr = _outputBuffer; - + float *outputPtr = (float *) _outputBuffer; + float scale = 1.0 / MAD_F_ONE; + // samples [0 ... n] for(i = startingSample; i < sampleCount; i++) { // channels [0 .. n] in this case LRLRLRLR for (ch = 0; ch < channels; ch++) { - signed long sample = audio_linear_dither(bitsPerSample, - _synth.pcm.samples[ch][i], - &channel_dither[ch], - &stats); - - if(bitsPerSample == 24) - { - outputPtr[0] = sample >> 16; - outputPtr[1] = sample >> 8; - outputPtr[2] = sample >> 0; - } - else - { - outputPtr[0] = sample >> 8; - outputPtr[1] = sample & 0xff; - } - outputPtr += stride; + float sample = _synth.pcm.samples[ch][i] * scale; + + outputPtr[0] = sample; + outputPtr++; } } @@ -607,8 +477,7 @@ audio_linear_round(unsigned int bits, if (![_source seekable]) { sampleRate = _frame.header.samplerate; channels = MAD_NCHANNELS(&_frame.header); - bitsPerSample = 16; - bytesPerFrame = (bitsPerSample/8) * channels; + bytesPerFrame = sizeof(float) * channels; [self willChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"]; @@ -701,12 +570,13 @@ audio_linear_round(unsigned int bits, { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels],@"channels", - [NSNumber numberWithInt:bitsPerSample],@"bitsPerSample", + [NSNumber numberWithInt:32],@"bitsPerSample", + [NSNumber numberWithBool:YES],@"floatingPoint", [NSNumber numberWithFloat:sampleRate],@"sampleRate", [NSNumber numberWithInt:bitrate],@"bitrate", [NSNumber numberWithLong:totalFrames - (_startPadding + _endPadding)],@"totalFrames", [NSNumber numberWithBool:[_source seekable]], @"seekable", - @"big", @"endian", + @"host", @"endian", nil]; } diff --git a/Plugins/Musepack/MusepackDecoder.h b/Plugins/Musepack/MusepackDecoder.h index ce29e5d6c..fc9f1b48f 100644 --- a/Plugins/Musepack/MusepackDecoder.h +++ b/Plugins/Musepack/MusepackDecoder.h @@ -24,7 +24,7 @@ float frequency; long totalFrames; } -- (BOOL)writeToBuffer:(uint16_t *)sample_buffer fromBuffer:(const MPC_SAMPLE_FORMAT *)p_buffer frames:(unsigned)frames; +- (BOOL)writeToBuffer:(float *)sample_buffer fromBuffer:(const MPC_SAMPLE_FORMAT *)p_buffer frames:(unsigned)frames; - (void)setSource:(id)s; - (id)source; diff --git a/Plugins/Musepack/MusepackDecoder.m b/Plugins/Musepack/MusepackDecoder.m index 8c971743f..3d845b02e 100644 --- a/Plugins/Musepack/MusepackDecoder.m +++ b/Plugins/Musepack/MusepackDecoder.m @@ -95,30 +95,24 @@ mpc_bool_t CanSeekProc(void *data) return YES; } -- (BOOL)writeToBuffer:(uint16_t *)sample_buffer fromBuffer:(const MPC_SAMPLE_FORMAT *)p_buffer frames:(unsigned)frames +- (BOOL)writeToBuffer:(float *)sample_buffer fromBuffer:(const MPC_SAMPLE_FORMAT *)p_buffer frames:(unsigned)frames { unsigned n; - int m_bps = 16; - int clip_min = - 1 << (m_bps - 1), - clip_max = (1 << (m_bps - 1)) - 1, - float_scale = 1 << (m_bps - 1); - unsigned p_size = frames * 2; //2 = bits per sample - + unsigned p_size = frames * 2; //2 = stereo +#ifdef MPC_FIXED_POINT + const float float_scale = 1.0 / MPC_FIXED_POINT_SCALE; +#endif + for (n = 0; n < p_size; n++) { - int val; + float val; #ifdef MPC_FIXED_POINT - val = shift_signed( p_buffer[n], m_bps - MPC_FIXED_POINT_SCALE_SHIFT ); + val = p_buffer[n] * float_scale; #else - val = (int)( p_buffer[n] * float_scale ); + val = p_buffer[n]; #endif - if (val < clip_min) - val = clip_min; - else if (val > clip_max) - val = clip_max; - // sample_buffer[n] = CFSwapInt16LittleToHost(val); sample_buffer[n] = val; } @@ -132,7 +126,7 @@ mpc_bool_t CanSeekProc(void *data) MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH]; int framesRead = 0; - int bytesPerFrame = 4; //bitsPerSample == 16, channels == 2 + int bytesPerFrame = sizeof(float) * 2; //bitsPerSample == 16, channels == 2 while (framesRead < frames) { //Fill from buffer, going by bufferFrames @@ -164,7 +158,7 @@ mpc_bool_t CanSeekProc(void *data) framesToRead = frames; } - [self writeToBuffer:((uint16_t*)(buf + (framesRead*bytesPerFrame))) fromBuffer:sampleBuffer frames: bufferFrames]; + [self writeToBuffer:((float*)(buf + (framesRead*bytesPerFrame))) fromBuffer:sampleBuffer frames: bufferFrames]; frames -= framesToRead; framesRead += framesToRead; @@ -209,7 +203,8 @@ mpc_bool_t CanSeekProc(void *data) [NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithFloat:frequency], @"sampleRate", [NSNumber numberWithDouble:totalFrames], @"totalFrames", - [NSNumber numberWithInt:16], @"bitsPerSample", + [NSNumber numberWithInt:32], @"bitsPerSample", + [NSNumber numberWithBool:YES], @"floatingPoint", [NSNumber numberWithInt:2], @"channels", [NSNumber numberWithBool:[source seekable]], @"seekable", @"host",@"endian", diff --git a/Plugins/Opus/Opus/OpusDecoder.m b/Plugins/Opus/Opus/OpusDecoder.m index 606e3966c..156c9e02d 100644 --- a/Plugins/Opus/Opus/OpusDecoder.m +++ b/Plugins/Opus/Opus/OpusDecoder.m @@ -6,6 +6,8 @@ // Copyright 2013 __NoWork, Inc__. All rights reserved. // +#import "Plugin.h" + #import "OpusDecoder.h" @@ -97,14 +99,14 @@ opus_int64 sourceTell(void *_stream) [self didChangeValueForKey:@"properties"]; } - int size = frames * sizeof(int16_t); + int size = frames * channels; do { lastSection = currentSection; - numread = op_read_stereo( opusRef, &((int16_t *)buf)[total], size - total); + numread = op_read_float_stereo( opusRef, &((float *)buf)[total], size - total); currentSection = op_current_link( opusRef ); if (numread > 0) { - total += numread * sizeof(int16_t); + total += numread * channels; } if (currentSection != lastSection) { @@ -113,7 +115,7 @@ opus_int64 sourceTell(void *_stream) } while (total != frames && numread != 0); - return total/sizeof(int16_t); + return total/channels; } - (void)close @@ -136,11 +138,13 @@ opus_int64 sourceTell(void *_stream) { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", - [NSNumber numberWithInt:16], @"bitsPerSample", + [NSNumber numberWithInt:32], @"bitsPerSample", + [NSNumber numberWithBool:YES], @"floatingPoint", [NSNumber numberWithFloat:48000], @"sampleRate", [NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithBool:([source seekable] && seekable)], @"seekable", + @"host", @"endian", nil]; } diff --git a/Plugins/Vorbis/VorbisDecoder.m b/Plugins/Vorbis/VorbisDecoder.m index 09c383086..fceb7883f 100644 --- a/Plugins/Vorbis/VorbisDecoder.m +++ b/Plugins/Vorbis/VorbisDecoder.m @@ -91,12 +91,16 @@ long sourceTell(void *datasource) [self didChangeValueForKey:@"properties"]; } - int size = frames * channels * 2; - do { lastSection = currentSection; - numread = ov_read(&vorbisRef, &((char *)buf)[total], size - total, 0, 2, 1, ¤tSection); + float ** pcm; + numread = ov_read_float(&vorbisRef, &pcm, frames - total, ¤tSection); if (numread > 0) { + for (int i = 0; i < channels; i++) { + for (int j = 0; j < numread; j++) { + ((float *)buf)[(total + j) * channels + i] = pcm[i][j]; + } + } total += numread; } @@ -104,9 +108,9 @@ long sourceTell(void *datasource) break; } - } while (total != size && numread != 0); + } while (total != frames && numread != 0); - return total/(channels * 2); + return total; } - (void)close @@ -128,11 +132,13 @@ long sourceTell(void *datasource) { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:channels], @"channels", - [NSNumber numberWithInt:16], @"bitsPerSample", + [NSNumber numberWithInt:32], @"bitsPerSample", + [NSNumber numberWithBool:YES], @"floatingPoint", [NSNumber numberWithFloat:frequency], @"sampleRate", [NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithBool:([source seekable] && seekable)], @"seekable", + @"host", @"endian", nil]; } diff --git a/Plugins/WMA/WMADecoder.h b/Plugins/WMA/WMADecoder.h index 047a72de9..088f3849f 100644 --- a/Plugins/WMA/WMADecoder.h +++ b/Plugins/WMA/WMADecoder.h @@ -28,6 +28,7 @@ AVCodec *codec; BOOL seekable; + BOOL floatingPoint; int bitsPerSample; int bitrate; int channels; diff --git a/Plugins/WMA/WMADecoder.m b/Plugins/WMA/WMADecoder.m index fffb43d78..f008ae650 100644 --- a/Plugins/WMA/WMADecoder.m +++ b/Plugins/WMA/WMADecoder.m @@ -129,6 +129,7 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op) channels = c->channels; bitrate = ic->bit_rate; + floatingPoint = NO; switch (c->sample_fmt) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: @@ -142,11 +143,19 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op) case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_S32P: + bitsPerSample = 32; + break; + case AV_SAMPLE_FMT_FLT: case AV_SAMPLE_FMT_FLTP: + bitsPerSample = 32; + floatingPoint = YES; + break; + case AV_SAMPLE_FMT_DBL: case AV_SAMPLE_FMT_DBLP: - bitsPerSample = 32; + bitsPerSample = 64; + floatingPoint = YES; break; default: @@ -251,44 +260,6 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op) numFrames = sampleBufferOffset / bytesPerFrame; samplePos = 0; - - if ( numFrames ) { - switch ( c->sample_fmt ) { - case AV_SAMPLE_FMT_FLT: - case AV_SAMPLE_FMT_FLTP: - { - float * input = (float *) sampleBuffer; - int32_t * output = (int32_t *) sampleBuffer; - - for (int i = 0; i < numFrames * channels; ++i) - { - float sample = input[i]; - if (sample > 1.0) sample = 1.0; - else if (sample < -1.0) sample = -1.0; - output[i] = sample * INT_MAX; - } - } - break; - - case AV_SAMPLE_FMT_DBL: - case AV_SAMPLE_FMT_DBLP: - { - double * input = (double *) sampleBuffer; - int32_t * output = (int32_t *) sampleBuffer; - - for (int i = 0; i < numFrames * channels; ++i) - { - double sample = input[i]; - if (sample > 1.0) sample = 1.0; - else if (sample < -1.0) sample = -1.0; - output[i] = sample * INT_MAX; - } - } - break; - - default: break; - } - } } } @@ -311,9 +282,11 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op) [NSNumber numberWithInt:channels], @"channels", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithFloat:frequency], @"sampleRate", + [NSNumber numberWithBool:floatingPoint], @"floatingPoint", [NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithBool:([source seekable] && seekable)], @"seekable", + @"host", @"endian", nil]; }