Implemented floating point sample format support into CogAudio and all relevant plug-ins
parent
b16ccd59f7
commit
74b6188772
|
@ -23,6 +23,7 @@
|
|||
int bytesPerSample;
|
||||
int bytesPerFrame;
|
||||
int volumeScale;
|
||||
BOOL floatingPoint;
|
||||
BOOL swapEndian;
|
||||
|
||||
BOOL shouldSeek;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
@synthesize bitrate;
|
||||
@synthesize channels;
|
||||
@synthesize bitsPerSample;
|
||||
@synthesize floatingPoint;
|
||||
@synthesize sampleRate;
|
||||
|
||||
@synthesize replayGainAlbumGain;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
int bitrate;
|
||||
int bitsPerSample;
|
||||
BOOL floatingPoint;
|
||||
int channels;
|
||||
float frequency;
|
||||
long totalFrames;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ extern DUMBFILE *dumbfile_open_memory_and_free(char *data, long size);
|
|||
@interface DumbDecoder : NSObject <CogDecoder> {
|
||||
DUH *duh;
|
||||
DUH_SIGRENDERER *dsr;
|
||||
|
||||
sample_t **sampptr;
|
||||
|
||||
id<CogSource> source;
|
||||
long length;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <CogDecoder>
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CogSource>)s;
|
||||
- (id<CogSource>)source;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
AVCodec *codec;
|
||||
|
||||
BOOL seekable;
|
||||
BOOL floatingPoint;
|
||||
int bitsPerSample;
|
||||
int bitrate;
|
||||
int channels;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue