Replace TABS by 4 spaces
This commit is contained in:
parent
614e0518a7
commit
8f7e2cd179
1 changed files with 111 additions and 111 deletions
222
src/external/qoaplay.c
vendored
222
src/external/qoaplay.c
vendored
|
@ -35,22 +35,22 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// QOA streaming data descriptor
|
// QOA streaming data descriptor
|
||||||
typedef struct {
|
typedef struct {
|
||||||
qoa_desc info; // QOA descriptor data
|
qoa_desc info; // QOA descriptor data
|
||||||
|
|
||||||
FILE *file; // QOA file to read, if NULL, using memory buffer -> file_data
|
FILE *file; // QOA file to read, if NULL, using memory buffer -> file_data
|
||||||
unsigned char *file_data; // QOA file data on memory
|
unsigned char *file_data; // QOA file data on memory
|
||||||
unsigned int file_data_size; // QOA file data on memory size
|
unsigned int file_data_size; // QOA file data on memory size
|
||||||
unsigned int file_data_offset; // QOA file data on memory offset for next read
|
unsigned int file_data_offset; // QOA file data on memory offset for next read
|
||||||
|
|
||||||
unsigned int first_frame_pos; // First frame position (after QOA header, required for offset)
|
unsigned int first_frame_pos; // First frame position (after QOA header, required for offset)
|
||||||
unsigned int sample_position; // Current streaming sample position
|
unsigned int sample_position; // Current streaming sample position
|
||||||
|
|
||||||
unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding)
|
unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding)
|
||||||
unsigned int buffer_len; // Buffer length to read samples for streaming
|
unsigned int buffer_len; // Buffer length to read samples for streaming
|
||||||
|
|
||||||
short *sample_data; // Sample data decoded
|
short *sample_data; // Sample data decoded
|
||||||
unsigned int sample_data_len; // Sample data decoded length
|
unsigned int sample_data_len; // Sample data decoded length
|
||||||
unsigned int sample_data_pos; // Sample data decoded position
|
unsigned int sample_data_pos; // Sample data decoded position
|
||||||
|
|
||||||
} qoaplay_desc;
|
} qoaplay_desc;
|
||||||
|
|
||||||
|
@ -85,97 +85,97 @@ int qoaplay_get_frame(qoaplay_desc *qoa_ctx);
|
||||||
// Open QOA file, keep FILE pointer to keep reading from file
|
// Open QOA file, keep FILE pointer to keep reading from file
|
||||||
qoaplay_desc *qoaplay_open(char *path)
|
qoaplay_desc *qoaplay_open(char *path)
|
||||||
{
|
{
|
||||||
FILE *file = fopen(path, "rb");
|
FILE *file = fopen(path, "rb");
|
||||||
if (!file) return NULL;
|
if (!file) return NULL;
|
||||||
|
|
||||||
// Read and decode the file header
|
// Read and decode the file header
|
||||||
unsigned char header[QOA_MIN_FILESIZE];
|
unsigned char header[QOA_MIN_FILESIZE];
|
||||||
int read = fread(header, QOA_MIN_FILESIZE, 1, file);
|
int read = fread(header, QOA_MIN_FILESIZE, 1, file);
|
||||||
if (!read) return NULL;
|
if (!read) return NULL;
|
||||||
|
|
||||||
qoa_desc qoa;
|
qoa_desc qoa;
|
||||||
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
||||||
if (!first_frame_pos) return NULL;
|
if (!first_frame_pos) return NULL;
|
||||||
|
|
||||||
// Rewind the file back to beginning of the first frame
|
// Rewind the file back to beginning of the first frame
|
||||||
fseek(file, first_frame_pos, SEEK_SET);
|
fseek(file, first_frame_pos, SEEK_SET);
|
||||||
|
|
||||||
// Allocate one chunk of memory for the qoaplay_desc struct
|
// Allocate one chunk of memory for the qoaplay_desc struct
|
||||||
// + the sample data for one frame
|
// + the sample data for one frame
|
||||||
// + a buffer to hold one frame of encoded data
|
// + a buffer to hold one frame of encoded data
|
||||||
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
||||||
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
||||||
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
||||||
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
||||||
|
|
||||||
qoa_ctx->file = file;
|
qoa_ctx->file = file;
|
||||||
qoa_ctx->file_data = NULL;
|
qoa_ctx->file_data = NULL;
|
||||||
qoa_ctx->file_data_size = 0;
|
qoa_ctx->file_data_size = 0;
|
||||||
qoa_ctx->file_data_offset = 0;
|
qoa_ctx->file_data_offset = 0;
|
||||||
qoa_ctx->first_frame_pos = first_frame_pos;
|
qoa_ctx->first_frame_pos = first_frame_pos;
|
||||||
|
|
||||||
// Setup data pointers to previously allocated data
|
// Setup data pointers to previously allocated data
|
||||||
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
||||||
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
||||||
|
|
||||||
qoa_ctx->info.channels = qoa.channels;
|
qoa_ctx->info.channels = qoa.channels;
|
||||||
qoa_ctx->info.samplerate = qoa.samplerate;
|
qoa_ctx->info.samplerate = qoa.samplerate;
|
||||||
qoa_ctx->info.samples = qoa.samples;
|
qoa_ctx->info.samples = qoa.samples;
|
||||||
|
|
||||||
return qoa_ctx;
|
return qoa_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open QOA file from memory, no FILE pointer required
|
// Open QOA file from memory, no FILE pointer required
|
||||||
qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size)
|
qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size)
|
||||||
{
|
{
|
||||||
// Read and decode the file header
|
// Read and decode the file header
|
||||||
unsigned char header[QOA_MIN_FILESIZE];
|
unsigned char header[QOA_MIN_FILESIZE];
|
||||||
memcpy(header, data, QOA_MIN_FILESIZE);
|
memcpy(header, data, QOA_MIN_FILESIZE);
|
||||||
|
|
||||||
qoa_desc qoa;
|
qoa_desc qoa;
|
||||||
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
||||||
if (!first_frame_pos) return NULL;
|
if (!first_frame_pos) return NULL;
|
||||||
|
|
||||||
// Allocate one chunk of memory for the qoaplay_desc struct
|
// Allocate one chunk of memory for the qoaplay_desc struct
|
||||||
// + the sample data for one frame
|
// + the sample data for one frame
|
||||||
// + a buffer to hold one frame of encoded data
|
// + a buffer to hold one frame of encoded data
|
||||||
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
||||||
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
||||||
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
||||||
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
||||||
|
|
||||||
qoa_ctx->file = NULL;
|
qoa_ctx->file = NULL;
|
||||||
|
|
||||||
// Keep a copy of file data provided to be managed internally
|
// Keep a copy of file data provided to be managed internally
|
||||||
qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size);
|
qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size);
|
||||||
memcpy(qoa_ctx->file_data, data, data_size);
|
memcpy(qoa_ctx->file_data, data, data_size);
|
||||||
qoa_ctx->file_data_size = data_size;
|
qoa_ctx->file_data_size = data_size;
|
||||||
qoa_ctx->file_data_offset = 0;
|
qoa_ctx->file_data_offset = 0;
|
||||||
qoa_ctx->first_frame_pos = first_frame_pos;
|
qoa_ctx->first_frame_pos = first_frame_pos;
|
||||||
|
|
||||||
// Setup data pointers to previously allocated data
|
// Setup data pointers to previously allocated data
|
||||||
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
||||||
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
||||||
|
|
||||||
qoa_ctx->info.channels = qoa.channels;
|
qoa_ctx->info.channels = qoa.channels;
|
||||||
qoa_ctx->info.samplerate = qoa.samplerate;
|
qoa_ctx->info.samplerate = qoa.samplerate;
|
||||||
qoa_ctx->info.samples = qoa.samples;
|
qoa_ctx->info.samples = qoa.samples;
|
||||||
|
|
||||||
return qoa_ctx;
|
return qoa_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close QOA file (if open) and free internal memory
|
// Close QOA file (if open) and free internal memory
|
||||||
void qoaplay_close(qoaplay_desc *qoa_ctx)
|
void qoaplay_close(qoaplay_desc *qoa_ctx)
|
||||||
{
|
{
|
||||||
if (qoa_ctx->file) fclose(qoa_ctx->file);
|
if (qoa_ctx->file) fclose(qoa_ctx->file);
|
||||||
|
|
||||||
if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0))
|
if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0))
|
||||||
{
|
{
|
||||||
QOA_FREE(qoa_ctx->file_data);
|
QOA_FREE(qoa_ctx->file_data);
|
||||||
qoa_ctx->file_data_size = 0;
|
qoa_ctx->file_data_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QOA_FREE(qoa_ctx);
|
QOA_FREE(qoa_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode one frame from QOA data
|
// Decode one frame from QOA data
|
||||||
|
@ -189,90 +189,90 @@ unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx)
|
||||||
qoa_ctx->file_data_offset += qoa_ctx->buffer_len;
|
qoa_ctx->file_data_offset += qoa_ctx->buffer_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int frame_len;
|
unsigned int frame_len;
|
||||||
qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len);
|
qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len);
|
||||||
qoa_ctx->sample_data_pos = 0;
|
qoa_ctx->sample_data_pos = 0;
|
||||||
qoa_ctx->sample_data_len = frame_len;
|
qoa_ctx->sample_data_len = frame_len;
|
||||||
|
|
||||||
return frame_len;
|
return frame_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewind QOA file or memory pointer to beginning
|
// Rewind QOA file or memory pointer to beginning
|
||||||
void qoaplay_rewind(qoaplay_desc *qoa_ctx)
|
void qoaplay_rewind(qoaplay_desc *qoa_ctx)
|
||||||
{
|
{
|
||||||
if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET);
|
if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET);
|
||||||
else qoa_ctx->file_data_offset = 0;
|
else qoa_ctx->file_data_offset = 0;
|
||||||
|
|
||||||
qoa_ctx->sample_position = 0;
|
qoa_ctx->sample_position = 0;
|
||||||
qoa_ctx->sample_data_len = 0;
|
qoa_ctx->sample_data_len = 0;
|
||||||
qoa_ctx->sample_data_pos = 0;
|
qoa_ctx->sample_data_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode required QOA frames
|
// Decode required QOA frames
|
||||||
unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples)
|
unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples)
|
||||||
{
|
{
|
||||||
int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels;
|
int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels;
|
||||||
int dst_index = 0;
|
int dst_index = 0;
|
||||||
|
|
||||||
for (int i = 0; i < num_samples; i++)
|
for (int i = 0; i < num_samples; i++)
|
||||||
{
|
{
|
||||||
// Do we have to decode more samples?
|
// Do we have to decode more samples?
|
||||||
if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0)
|
if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0)
|
||||||
{
|
{
|
||||||
if (!qoaplay_decode_frame(qoa_ctx))
|
if (!qoaplay_decode_frame(qoa_ctx))
|
||||||
{
|
{
|
||||||
// Loop to the beginning
|
// Loop to the beginning
|
||||||
qoaplay_rewind(qoa_ctx);
|
qoaplay_rewind(qoa_ctx);
|
||||||
qoaplay_decode_frame(qoa_ctx);
|
qoaplay_decode_frame(qoa_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
src_index = 0;
|
src_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize to -1..1 floats and write to dest
|
// Normalize to -1..1 floats and write to dest
|
||||||
for (int c = 0; c < qoa_ctx->info.channels; c++)
|
for (int c = 0; c < qoa_ctx->info.channels; c++)
|
||||||
{
|
{
|
||||||
sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0;
|
sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qoa_ctx->sample_data_pos++;
|
qoa_ctx->sample_data_pos++;
|
||||||
qoa_ctx->sample_position++;
|
qoa_ctx->sample_position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_samples;
|
return num_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get QOA total time duration in seconds
|
// Get QOA total time duration in seconds
|
||||||
double qoaplay_get_duration(qoaplay_desc *qoa_ctx)
|
double qoaplay_get_duration(qoaplay_desc *qoa_ctx)
|
||||||
{
|
{
|
||||||
return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate;
|
return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get QOA current time position in seconds
|
// Get QOA current time position in seconds
|
||||||
double qoaplay_get_time(qoaplay_desc *qoa_ctx)
|
double qoaplay_get_time(qoaplay_desc *qoa_ctx)
|
||||||
{
|
{
|
||||||
return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate;
|
return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get QOA current audio frame
|
// Get QOA current audio frame
|
||||||
int qoaplay_get_frame(qoaplay_desc *qoa_ctx)
|
int qoaplay_get_frame(qoaplay_desc *qoa_ctx)
|
||||||
{
|
{
|
||||||
return qoa_ctx->sample_position/QOA_FRAME_LEN;
|
return qoa_ctx->sample_position/QOA_FRAME_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek QOA audio frame
|
// Seek QOA audio frame
|
||||||
void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame)
|
void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame)
|
||||||
{
|
{
|
||||||
if (frame < 0) frame = 0;
|
if (frame < 0) frame = 0;
|
||||||
|
|
||||||
if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN;
|
if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN;
|
||||||
|
|
||||||
qoa_ctx->sample_position = frame*QOA_FRAME_LEN;
|
qoa_ctx->sample_position = frame*QOA_FRAME_LEN;
|
||||||
qoa_ctx->sample_data_len = 0;
|
qoa_ctx->sample_data_len = 0;
|
||||||
qoa_ctx->sample_data_pos = 0;
|
qoa_ctx->sample_data_pos = 0;
|
||||||
|
|
||||||
unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info);
|
unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info);
|
||||||
|
|
||||||
if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET);
|
if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET);
|
||||||
else qoa_ctx->file_data_offset = offset;
|
else qoa_ctx->file_data_offset = offset;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue