Skip to content

Instantly share code, notes, and snippets.

@alokprasad
Forked from ExternPointer/resampler.c
Created April 11, 2019 17:15
Show Gist options
  • Save alokprasad/6116f4e93c306e4965903bd0460659fe to your computer and use it in GitHub Desktop.
Save alokprasad/6116f4e93c306e4965903bd0460659fe to your computer and use it in GitHub Desktop.
Simply audio resampler, which allow to work in realtime (resample stream)
/*
* 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