Implemented floating point sample format support into CogAudio and all relevant plug-ins

This commit is contained in:
Chris Moeller 2013-10-05 14:15:09 -07:00
parent b16ccd59f7
commit 74b6188772
17 changed files with 227 additions and 262 deletions

View file

@ -23,6 +23,7 @@
int bytesPerSample; int bytesPerSample;
int bytesPerFrame; int bytesPerFrame;
int volumeScale; int volumeScale;
BOOL floatingPoint;
BOOL swapEndian; BOOL swapEndian;
BOOL shouldSeek; BOOL shouldSeek;

View file

@ -54,6 +54,8 @@ static BOOL hostIsBigEndian()
swapEndian = NO; swapEndian = NO;
} }
floatingPoint = [[properties objectForKey:@"floatingPoint"] boolValue];
[self refreshVolumeScaling]; [self refreshVolumeScaling];
shouldContinue = YES; 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); 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 - (void)process
{ {
int amountInBuffer = 0; int amountInBuffer = 0;
@ -276,19 +306,70 @@ static int32_t swap_32(uint32_t input)
break; break;
case 4: case 4:
{ if (floatingPoint)
int32_t * samples = (int32_t *)inputBuffer;
for (int i = 0; i < totalFrames; i++)
{ {
int64_t sample = samples[i]; float * samples = (float *)inputBuffer;
if (swapEndian) sample = swap_32(sample); float scale = (float)volumeScale / 4096;
sample = (sample * volumeScale) >> 12; for (int i = 0; i < totalFrames; i++)
if ((unsigned)(sample + 0x80000000) & 0xffffffff00000000) sample = (sample >> 63) ^ 0x7fffffff; {
if (swapEndian) sample = swap_32(sample); float sample = samples[i];
samples[i] = sample; if (swapEndian) sample = swap_32f(sample);
sample *= scale;
if (swapEndian) sample = swap_32f(sample);
samples[i] = sample;
}
} }
} else
break; {
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;
} }
} }

View file

@ -47,6 +47,8 @@ AudioStreamBasicDescription propertiesToASBD(NSDictionary *properties)
asbd.mFramesPerPacket = 1; asbd.mFramesPerPacket = 1;
asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket; asbd.mBytesPerPacket = asbd.mBytesPerFrame * asbd.mFramesPerPacket;
asbd.mReserved = 0; asbd.mReserved = 0;
BOOL isFloat = [[properties objectForKey:@"floatingPoint"] boolValue];
if ([[properties objectForKey:@"endian"] isEqualToString:@"big"] || ([[properties objectForKey:@"endian"] isEqualToString:@"host"] && hostIsBigEndian() )) if ([[properties objectForKey:@"endian"] isEqualToString:@"big"] || ([[properties objectForKey:@"endian"] isEqualToString:@"host"] && hostIsBigEndian() ))
{ {
@ -54,9 +56,13 @@ AudioStreamBasicDescription propertiesToASBD(NSDictionary *properties)
asbd.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh; asbd.mFormatFlags |= kLinearPCMFormatFlagIsAlignedHigh;
} }
if ([[properties objectForKey:@"unsigned"] boolValue] == NO) { if (isFloat == NO && [[properties objectForKey:@"unsigned"] boolValue] == NO) {
asbd.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; asbd.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
} }
if (isFloat) {
asbd.mFormatFlags |= kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsPacked;
}
return asbd; return asbd;
} }

View file

@ -45,6 +45,7 @@
int bitrate; int bitrate;
int channels; int channels;
int bitsPerSample; int bitsPerSample;
BOOL floatingPoint;
float sampleRate; float sampleRate;
NSString *endian; NSString *endian;
@ -100,6 +101,7 @@
@property int bitrate; @property int bitrate;
@property int channels; @property int channels;
@property int bitsPerSample; @property int bitsPerSample;
@property BOOL floatingPoint;
@property float sampleRate; @property float sampleRate;
@property float replayGainAlbumGain; @property float replayGainAlbumGain;

View file

@ -38,6 +38,7 @@
@synthesize bitrate; @synthesize bitrate;
@synthesize channels; @synthesize channels;
@synthesize bitsPerSample; @synthesize bitsPerSample;
@synthesize floatingPoint;
@synthesize sampleRate; @synthesize sampleRate;
@synthesize replayGainAlbumGain; @synthesize replayGainAlbumGain;

View file

@ -31,6 +31,7 @@
int bitrate; int bitrate;
int bitsPerSample; int bitsPerSample;
BOOL floatingPoint;
int channels; int channels;
float frequency; float frequency;
long totalFrames; long totalFrames;

View file

@ -84,10 +84,12 @@
bitsPerSample = asbd.mBitsPerChannel; bitsPerSample = asbd.mBitsPerChannel;
channels = asbd.mChannelsPerFrame; channels = asbd.mChannelsPerFrame;
frequency = asbd.mSampleRate; frequency = asbd.mSampleRate;
floatingPoint = NO;
// mBitsPerChannel will only be set for lpcm formats // mBitsPerChannel will only be set for lpcm formats
if(0 == bitsPerSample) { if(0 == bitsPerSample) {
bitsPerSample = 16; bitsPerSample = 32;
floatingPoint = YES;
} }
// Set output format // Set output format
@ -96,7 +98,12 @@
bzero(&result, sizeof(AudioStreamBasicDescription)); bzero(&result, sizeof(AudioStreamBasicDescription));
result.mFormatID = kAudioFormatLinearPCM; result.mFormatID = kAudioFormatLinearPCM;
result.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian; if (floatingPoint) {
result.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
}
else {
result.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsBigEndian;
}
result.mSampleRate = frequency; result.mSampleRate = frequency;
result.mChannelsPerFrame = channels; result.mChannelsPerFrame = channels;
@ -177,11 +184,12 @@
return [NSDictionary dictionaryWithObjectsAndKeys: return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels],@"channels", [NSNumber numberWithInt:channels],@"channels",
[NSNumber numberWithInt:bitsPerSample],@"bitsPerSample", [NSNumber numberWithInt:bitsPerSample],@"bitsPerSample",
[NSNumber numberWithBool:floatingPoint],@"floatingPoint",
[NSNumber numberWithInt:bitrate],@"bitrate", [NSNumber numberWithInt:bitrate],@"bitrate",
[NSNumber numberWithFloat:frequency],@"sampleRate", [NSNumber numberWithFloat:frequency],@"sampleRate",
[NSNumber numberWithLong:totalFrames],@"totalFrames", [NSNumber numberWithLong:totalFrames],@"totalFrames",
[NSNumber numberWithBool:YES], @"seekable", [NSNumber numberWithBool:YES], @"seekable",
@"big", @"endian", floatingPoint ? @"host" : @"big", @"endian",
nil]; nil];
} }

View file

@ -18,7 +18,8 @@ extern DUMBFILE *dumbfile_open_memory_and_free(char *data, long size);
@interface DumbDecoder : NSObject <CogDecoder> { @interface DumbDecoder : NSObject <CogDecoder> {
DUH *duh; DUH *duh;
DUH_SIGRENDERER *dsr; DUH_SIGRENDERER *dsr;
sample_t **sampptr;
id<CogSource> source; id<CogSource> source;
long length; long length;

View file

@ -185,6 +185,8 @@ int callbackLoop(void *data)
loops = 0; loops = 0;
fadeTotal = fadeRemain = 44100 * 8; fadeTotal = fadeRemain = 44100 * 8;
sampptr = allocate_sample_buffer(2, 1024);
[self willChangeValueForKey:@"properties"]; [self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"];
@ -197,7 +199,8 @@ int callbackLoop(void *data)
[NSNumber numberWithInt:0], @"bitrate", [NSNumber numberWithInt:0], @"bitrate",
[NSNumber numberWithFloat:44100], @"sampleRate", [NSNumber numberWithFloat:44100], @"sampleRate",
[NSNumber numberWithDouble:((length / 65.536f)*44.1000)], @"totalFrames", [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 numberWithInt:2], @"channels", //output from gme_play is in stereo
[NSNumber numberWithBool:[source seekable]], @"seekable", [NSNumber numberWithBool:[source seekable]], @"seekable",
@"host", @"endian", @"host", @"endian",
@ -206,27 +209,49 @@ int callbackLoop(void *data)
- (int)readAudio:(void *)buf frames:(UInt32)frames - (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); int total = 0;
while ( total < frames ) {
if ( loops >= 2 ) { int framesToRender = 1024;
int16_t * sampleBuf = ( int16_t * ) buf; if ( framesToRender > frames )
long fadeEnd = fadeRemain - rendered; framesToRender = frames;
if ( fadeEnd < 0 ) dumb_silence( sampptr[0], framesToRender * 2 );
fadeEnd = 0; int rendered = duh_sigrenderer_generate_samples( dsr, 1.0, 65536.0f / 44100.0f, framesToRender, sampptr );
for ( long fadePos = fadeRemain; fadePos > fadeEnd; --fadePos ) {
long offset = (fadeRemain - fadePos) * 2; if (rendered <= 0)
int64_t sampleLeft = sampleBuf[ offset + 0 ]; break;
int64_t sampleRight = sampleBuf[ offset + 1 ];
sampleLeft = (sampleLeft * fadePos) / fadeTotal; for ( int i = 0; i < rendered * 2; i++ ) {
sampleRight = (sampleRight * fadePos) / fadeTotal; const float scale = 1.0 / 0x800000;
sampleBuf[ offset + 0 ] = sampleLeft; ((float *)buf)[(total * 2) + i] = (float)sampptr[0][i] * scale;
sampleBuf[ offset + 1 ] = sampleRight;
} }
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 - (long)seek:(long)frame
@ -253,6 +278,11 @@ int callbackLoop(void *data)
- (void)cleanUp - (void)cleanUp
{ {
if (sampptr) {
destroy_sample_buffer(sampptr);
sampptr = NULL;
}
if (dsr) { if (dsr) {
duh_end_sigrenderer(dsr); duh_end_sigrenderer(dsr);
dsr = NULL; dsr = NULL;

View file

@ -14,26 +14,12 @@
#define INPUT_BUFFER_SIZE 5*8192 #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 <CogDecoder> @interface MADDecoder : NSObject <CogDecoder>
{ {
struct mad_stream _stream; struct mad_stream _stream;
struct mad_frame _frame; struct mad_frame _frame;
struct mad_synth _synth; 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 _inputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD];
unsigned char *_outputBuffer; unsigned char *_outputBuffer;
int _outputFrames; int _outputFrames;
@ -57,7 +43,6 @@ struct audio_stats {
int bytesPerFrame; int bytesPerFrame;
int channels; int channels;
int bitsPerSample;
float sampleRate; float sampleRate;
int bitrate; int bitrate;
long totalFrames; long totalFrames;

View file

@ -277,9 +277,7 @@
mad_frame_finish (&frame); mad_frame_finish (&frame);
mad_stream_finish (&stream); mad_stream_finish (&stream);
bitsPerSample = 24; bytesPerFrame = sizeof(float) * channels;
bytesPerFrame = (bitsPerSample/8) * channels;
[_source seek:0 whence:SEEK_SET]; [_source seek:0 whence:SEEK_SET];
inputEOF = NO; inputEOF = NO;
@ -321,121 +319,6 @@
return [self scanFile]; 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 - (void)writeOutput
{ {
unsigned int startingSample = 0; unsigned int startingSample = 0;
@ -489,32 +372,19 @@ audio_linear_round(unsigned int bits,
int ch; int ch;
int i; int i;
int stride = bitsPerSample/8; float *outputPtr = (float *) _outputBuffer;
unsigned char *outputPtr = _outputBuffer; float scale = 1.0 / MAD_F_ONE;
// samples [0 ... n] // samples [0 ... n]
for(i = startingSample; i < sampleCount; i++) for(i = startingSample; i < sampleCount; i++)
{ {
// channels [0 .. n] in this case LRLRLRLR // channels [0 .. n] in this case LRLRLRLR
for (ch = 0; ch < channels; ch++) for (ch = 0; ch < channels; ch++)
{ {
signed long sample = audio_linear_dither(bitsPerSample, float sample = _synth.pcm.samples[ch][i] * scale;
_synth.pcm.samples[ch][i],
&channel_dither[ch], outputPtr[0] = sample;
&stats); outputPtr++;
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;
} }
} }
@ -607,8 +477,7 @@ audio_linear_round(unsigned int bits,
if (![_source seekable]) { if (![_source seekable]) {
sampleRate = _frame.header.samplerate; sampleRate = _frame.header.samplerate;
channels = MAD_NCHANNELS(&_frame.header); channels = MAD_NCHANNELS(&_frame.header);
bitsPerSample = 16; bytesPerFrame = sizeof(float) * channels;
bytesPerFrame = (bitsPerSample/8) * channels;
[self willChangeValueForKey:@"properties"]; [self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"];
@ -701,12 +570,13 @@ audio_linear_round(unsigned int bits,
{ {
return [NSDictionary dictionaryWithObjectsAndKeys: return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels],@"channels", [NSNumber numberWithInt:channels],@"channels",
[NSNumber numberWithInt:bitsPerSample],@"bitsPerSample", [NSNumber numberWithInt:32],@"bitsPerSample",
[NSNumber numberWithBool:YES],@"floatingPoint",
[NSNumber numberWithFloat:sampleRate],@"sampleRate", [NSNumber numberWithFloat:sampleRate],@"sampleRate",
[NSNumber numberWithInt:bitrate],@"bitrate", [NSNumber numberWithInt:bitrate],@"bitrate",
[NSNumber numberWithLong:totalFrames - (_startPadding + _endPadding)],@"totalFrames", [NSNumber numberWithLong:totalFrames - (_startPadding + _endPadding)],@"totalFrames",
[NSNumber numberWithBool:[_source seekable]], @"seekable", [NSNumber numberWithBool:[_source seekable]], @"seekable",
@"big", @"endian", @"host", @"endian",
nil]; nil];
} }

View file

@ -24,7 +24,7 @@
float frequency; float frequency;
long totalFrames; 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<CogSource>)s; - (void)setSource:(id<CogSource>)s;
- (id<CogSource>)source; - (id<CogSource>)source;

View file

@ -95,30 +95,24 @@ mpc_bool_t CanSeekProc(void *data)
return YES; 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; 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++) for (n = 0; n < p_size; n++)
{ {
int val; float val;
#ifdef MPC_FIXED_POINT #ifdef MPC_FIXED_POINT
val = shift_signed( p_buffer[n], m_bps - MPC_FIXED_POINT_SCALE_SHIFT ); val = p_buffer[n] * float_scale;
#else #else
val = (int)( p_buffer[n] * float_scale ); val = p_buffer[n];
#endif #endif
if (val < clip_min)
val = clip_min;
else if (val > clip_max)
val = clip_max;
// sample_buffer[n] = CFSwapInt16LittleToHost(val); // sample_buffer[n] = CFSwapInt16LittleToHost(val);
sample_buffer[n] = val; sample_buffer[n] = val;
} }
@ -132,7 +126,7 @@ mpc_bool_t CanSeekProc(void *data)
MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH]; MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH];
int framesRead = 0; int framesRead = 0;
int bytesPerFrame = 4; //bitsPerSample == 16, channels == 2 int bytesPerFrame = sizeof(float) * 2; //bitsPerSample == 16, channels == 2
while (framesRead < frames) while (framesRead < frames)
{ {
//Fill from buffer, going by bufferFrames //Fill from buffer, going by bufferFrames
@ -164,7 +158,7 @@ mpc_bool_t CanSeekProc(void *data)
framesToRead = frames; 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; frames -= framesToRead;
framesRead += framesToRead; framesRead += framesToRead;
@ -209,7 +203,8 @@ mpc_bool_t CanSeekProc(void *data)
[NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithInt:bitrate], @"bitrate",
[NSNumber numberWithFloat:frequency], @"sampleRate", [NSNumber numberWithFloat:frequency], @"sampleRate",
[NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithDouble:totalFrames], @"totalFrames",
[NSNumber numberWithInt:16], @"bitsPerSample", [NSNumber numberWithInt:32], @"bitsPerSample",
[NSNumber numberWithBool:YES], @"floatingPoint",
[NSNumber numberWithInt:2], @"channels", [NSNumber numberWithInt:2], @"channels",
[NSNumber numberWithBool:[source seekable]], @"seekable", [NSNumber numberWithBool:[source seekable]], @"seekable",
@"host",@"endian", @"host",@"endian",

View file

@ -6,6 +6,8 @@
// Copyright 2013 __NoWork, Inc__. All rights reserved. // Copyright 2013 __NoWork, Inc__. All rights reserved.
// //
#import "Plugin.h"
#import "OpusDecoder.h" #import "OpusDecoder.h"
@ -97,14 +99,14 @@ opus_int64 sourceTell(void *_stream)
[self didChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"];
} }
int size = frames * sizeof(int16_t); int size = frames * channels;
do { do {
lastSection = currentSection; 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 ); currentSection = op_current_link( opusRef );
if (numread > 0) { if (numread > 0) {
total += numread * sizeof(int16_t); total += numread * channels;
} }
if (currentSection != lastSection) { if (currentSection != lastSection) {
@ -113,7 +115,7 @@ opus_int64 sourceTell(void *_stream)
} while (total != frames && numread != 0); } while (total != frames && numread != 0);
return total/sizeof(int16_t); return total/channels;
} }
- (void)close - (void)close
@ -136,11 +138,13 @@ opus_int64 sourceTell(void *_stream)
{ {
return [NSDictionary dictionaryWithObjectsAndKeys: return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels", [NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:16], @"bitsPerSample", [NSNumber numberWithInt:32], @"bitsPerSample",
[NSNumber numberWithBool:YES], @"floatingPoint",
[NSNumber numberWithFloat:48000], @"sampleRate", [NSNumber numberWithFloat:48000], @"sampleRate",
[NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithDouble:totalFrames], @"totalFrames",
[NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithInt:bitrate], @"bitrate",
[NSNumber numberWithBool:([source seekable] && seekable)], @"seekable", [NSNumber numberWithBool:([source seekable] && seekable)], @"seekable",
@"host", @"endian",
nil]; nil];
} }

View file

@ -91,12 +91,16 @@ long sourceTell(void *datasource)
[self didChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"];
} }
int size = frames * channels * 2;
do { do {
lastSection = currentSection; lastSection = currentSection;
numread = ov_read(&vorbisRef, &((char *)buf)[total], size - total, 0, 2, 1, &currentSection); float ** pcm;
numread = ov_read_float(&vorbisRef, &pcm, frames - total, &currentSection);
if (numread > 0) { 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; total += numread;
} }
@ -104,9 +108,9 @@ long sourceTell(void *datasource)
break; break;
} }
} while (total != size && numread != 0); } while (total != frames && numread != 0);
return total/(channels * 2); return total;
} }
- (void)close - (void)close
@ -128,11 +132,13 @@ long sourceTell(void *datasource)
{ {
return [NSDictionary dictionaryWithObjectsAndKeys: return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:channels], @"channels", [NSNumber numberWithInt:channels], @"channels",
[NSNumber numberWithInt:16], @"bitsPerSample", [NSNumber numberWithInt:32], @"bitsPerSample",
[NSNumber numberWithBool:YES], @"floatingPoint",
[NSNumber numberWithFloat:frequency], @"sampleRate", [NSNumber numberWithFloat:frequency], @"sampleRate",
[NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithDouble:totalFrames], @"totalFrames",
[NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithInt:bitrate], @"bitrate",
[NSNumber numberWithBool:([source seekable] && seekable)], @"seekable", [NSNumber numberWithBool:([source seekable] && seekable)], @"seekable",
@"host", @"endian",
nil]; nil];
} }

View file

@ -28,6 +28,7 @@
AVCodec *codec; AVCodec *codec;
BOOL seekable; BOOL seekable;
BOOL floatingPoint;
int bitsPerSample; int bitsPerSample;
int bitrate; int bitrate;
int channels; int channels;

View file

@ -129,6 +129,7 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op)
channels = c->channels; channels = c->channels;
bitrate = ic->bit_rate; bitrate = ic->bit_rate;
floatingPoint = NO;
switch (c->sample_fmt) { switch (c->sample_fmt) {
case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P: 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_S32:
case AV_SAMPLE_FMT_S32P: case AV_SAMPLE_FMT_S32P:
bitsPerSample = 32;
break;
case AV_SAMPLE_FMT_FLT: case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP: case AV_SAMPLE_FMT_FLTP:
bitsPerSample = 32;
floatingPoint = YES;
break;
case AV_SAMPLE_FMT_DBL: case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP: case AV_SAMPLE_FMT_DBLP:
bitsPerSample = 32; bitsPerSample = 64;
floatingPoint = YES;
break; break;
default: default:
@ -251,44 +260,6 @@ int lockmgr_callback(void ** mutex, enum AVLockOp op)
numFrames = sampleBufferOffset / bytesPerFrame; numFrames = sampleBufferOffset / bytesPerFrame;
samplePos = 0; 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:channels], @"channels",
[NSNumber numberWithInt:bitsPerSample], @"bitsPerSample", [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample",
[NSNumber numberWithFloat:frequency], @"sampleRate", [NSNumber numberWithFloat:frequency], @"sampleRate",
[NSNumber numberWithBool:floatingPoint], @"floatingPoint",
[NSNumber numberWithDouble:totalFrames], @"totalFrames", [NSNumber numberWithDouble:totalFrames], @"totalFrames",
[NSNumber numberWithInt:bitrate], @"bitrate", [NSNumber numberWithInt:bitrate], @"bitrate",
[NSNumber numberWithBool:([source seekable] && seekable)], @"seekable", [NSNumber numberWithBool:([source seekable] && seekable)], @"seekable",
@"host", @"endian",
nil]; nil];
} }