-
-
Save alokprasad/6116f4e93c306e4965903bd0460659fe to your computer and use it in GitHub Desktop.
Simply audio resampler, which allow to work in realtime (resample stream)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* File format: raw, PCM s16le | |
* Resample 44100 Hz ./audio.raw to 16000 Hz ./audio_resampled.raw: | |
* gcc -g resampler.c -o resampler | |
* ./resampler | |
*/ | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <memory.h> | |
#include <math.h> | |
typedef float float32; | |
typedef short int int16; | |
typedef int BOOL; | |
#define FALSE 0 | |
#define TRUE 1 | |
typedef struct pcm_s16le_chunk_s | |
{ | |
int16 *samples; | |
int size; | |
} pcm_chunk_t; | |
pcm_chunk_t *PcmChunk_Create( char *buf, int sz ); | |
void PcmChunk_Concat( pcm_chunk_t *dst, pcm_chunk_t *src ); | |
void PcmChunk_Destroy( pcm_chunk_t *chunk ); | |
pcm_chunk_t *PcmChunk_Create( char *buf, int sz ) | |
{ | |
if( sz <= 0 ) | |
return NULL; | |
pcm_chunk_t *chunk = ( pcm_chunk_t * )malloc( sizeof( pcm_chunk_t ) ); | |
chunk->size = sz / sizeof( int16 ); | |
chunk->samples = ( int16 * )malloc( chunk->size * sizeof( int16 ) ); | |
memcpy( chunk->samples, buf, sz ); | |
return chunk; | |
} | |
pcm_chunk_t *PcmChunk_Copy( pcm_chunk_t *chunk ) | |
{ | |
return PcmChunk_Create( ( char * )chunk->samples, chunk->size * sizeof( int16 ) ); | |
} | |
/* Write samples from src to the end of dst chunk */ | |
void PcmChunk_Concat( pcm_chunk_t *dst, pcm_chunk_t *src ) | |
{ | |
dst->size += src->size; | |
dst->samples = ( int16 * )realloc( dst->samples, dst->size * sizeof( int16 ) ); | |
memcpy( &dst->samples[dst->size - src->size], &src->samples[0], src->size * sizeof( int16 ) ); | |
} | |
void PcmChunk_Destroy( pcm_chunk_t *chunk ) | |
{ | |
if( chunk == NULL ) | |
return; | |
free( chunk->samples ); | |
free( chunk ); | |
} | |
typedef struct resampler_s | |
{ | |
int srcSampleRate; | |
int dstSampleRate; | |
pcm_chunk_t *prevChunk; | |
float pos; | |
} resampler_t; | |
resampler_t *Resampler_Create( int srcSampleRate, int dstSampleRate ) | |
{ | |
resampler_t *r = ( resampler_t * )malloc( sizeof( resampler_t ) ); | |
r->srcSampleRate = srcSampleRate; | |
r->dstSampleRate = dstSampleRate; | |
r->prevChunk = NULL; | |
r->pos = 1.0f; | |
return r; | |
} | |
/* Resample input chunk. Return the new object of pcm_chunk_t. You need to free memory */ | |
/* This can return NULL if needs more chunks */ | |
pcm_chunk_t *Resampler_Proc( resampler_t *r, pcm_chunk_t *input ) | |
{ | |
if( r->prevChunk == NULL ) | |
r->prevChunk = PcmChunk_Copy( input ); | |
else | |
PcmChunk_Concat( r->prevChunk, input ); | |
input = r->prevChunk; | |
float ratio = (float)r->srcSampleRate / (float)r->dstSampleRate; | |
int16 *outputSamples = ( int16 * )malloc( input->size * sizeof( int16 ) ); | |
int cnt = 0; | |
while( r->pos < input->size - 1 ) | |
{ | |
float w = 1.0f - (r->pos - (int)r->pos); | |
outputSamples[cnt++] = input->samples[ (int)r->pos ] * w + | |
input->samples[ (int)r->pos + 1 ] * (1.0f - w); | |
r->pos += ratio; | |
} | |
int lastIdx = (int)r->pos; | |
if( lastIdx >= input->size ) | |
{ | |
r->pos -= r->prevChunk->size; | |
PcmChunk_Destroy( r->prevChunk ); | |
r->prevChunk = NULL; | |
} | |
else | |
{ | |
r->pos -= lastIdx; | |
pcm_chunk_t *prev = PcmChunk_Create( ( char * )&input->samples[lastIdx], | |
(input->size - lastIdx)*sizeof(int16) ); | |
PcmChunk_Destroy( r->prevChunk ); | |
r->prevChunk = prev; | |
} | |
pcm_chunk_t *resampled = PcmChunk_Create( ( char * )outputSamples, cnt * sizeof( int16 ) ); | |
free( outputSamples ); | |
return resampled; | |
} | |
void Resampler_Destroy( resampler_t *r ) | |
{ | |
PcmChunk_Destroy( r->prevChunk ); | |
free( r ); | |
} | |
int main() | |
{ | |
int i; | |
FILE *f = fopen( "audio.raw", "r" ); | |
fseek( f, 0, SEEK_END ); | |
int len = ftell( f ); | |
fseek( f, 0, SEEK_SET ); | |
char *audio = ( char * )malloc( len ); | |
fread( audio, len, 1, f ); | |
fclose( f ); | |
f = fopen( "audio_resampled.raw", "w" ); | |
const int chunkSize = 32; | |
resampler_t *resampler = Resampler_Create( 44100, 16000 ); | |
/* Simulation of stream. We proccessing chunks of chunkSize bytes */ | |
for( i = 0; i < len; i += chunkSize ) | |
{ | |
int size = chunkSize; | |
if( size + i > len ) | |
size = len - i; | |
pcm_chunk_t *chunk = PcmChunk_Create( audio + i, size ); /* Create chunk from bytes */ | |
pcm_chunk_t *r = Resampler_Proc( resampler, chunk ); /* Resample current chunk */ | |
if( r ) /* Check result for NULL */ | |
{ /* r == NULL if needs next chunk for resampling */ | |
fwrite( ( char * )r->samples, r->size * sizeof( int16 ), 1, f ); /* */ | |
PcmChunk_Destroy( r ); /* free result of Resamole_Proc */ | |
} | |
PcmChunk_Destroy( chunk ); | |
} | |
Resampler_Destroy( resampler ); | |
fclose( f ); | |
free( audio ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment