Small sunvox to wav converter based upon the example from the library archive
// | |
// * Using SunVox as a filter for some user-generated signal | |
// (with export to WAV) | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <dlfcn.h> | |
#include <signal.h> | |
#include <math.h> | |
#include <string.h> | |
#define SUNVOX_MAIN | |
#include "sunvox.h" | |
int g_sv_sampling_rate = 48000; //Hz | |
int g_sv_channels_num = 2; //1 - mono; 2 - stereo | |
int g_sv_buffer_size = 1024 * 4; //Audio buffer size (number of frames) | |
#define POST_GAP 1 //seconds | |
int keep_running = 1; | |
void int_handler( int param ) | |
{ | |
keep_running = 0; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
signal( SIGINT, int_handler ); | |
if(argc < 2) { | |
printf("Usage: %s <src.sunvox> <dest.wav>\n", argv[0]); | |
return 1; | |
} | |
if( sv_load_dll() ) | |
return 1; | |
int ver = sv_init( | |
0, | |
g_sv_sampling_rate, | |
g_sv_channels_num, | |
SV_INIT_FLAG_USER_AUDIO_CALLBACK | SV_INIT_FLAG_AUDIO_INT16 | SV_INIT_FLAG_ONE_THREAD | |
); | |
if( ver >= 0 ) | |
{ | |
int major = ( ver >> 16 ) & 255; | |
int minor1 = ( ver >> 8 ) & 255; | |
int minor2 = ( ver ) & 255; | |
printf( "SunVox lib version: %d.%d.%d\n", major, minor1, minor2 ); | |
sv_open_slot( 0 ); | |
if( sv_load( 0, argv[1] ) == 0 ) | |
printf( "Loaded.\n" ); | |
else { | |
printf( "Load error: %s\n", argv[1] ); | |
return 1; | |
} | |
const char * title_uns = sv_get_song_name( 0 ); | |
char * title = malloc(strlen(title_uns)+1); | |
int title_len = strlen(title_uns); | |
strncpy(title, title_uns, strlen(title_uns)); | |
for(int i = 0; i < strlen(title); ++i) { | |
if(!isprint(title[i])) { | |
title[i] = ' '; | |
title_len++; | |
} | |
} | |
printf("%s\n", title); | |
sv_set_autostop(0, 1); | |
//Saving the audio stream to the WAV file: | |
//(audio format: 16bit stereo interleaved (LRLRLRLR...)) | |
FILE* f = fopen( argv[2], "wb" ); | |
if( f ) | |
{ | |
signed short* buf = (signed short*)malloc( g_sv_buffer_size * g_sv_channels_num * sizeof( signed short ) ); //Output audio buffer | |
signed short* in_buf = (signed short*)malloc( g_sv_buffer_size * g_sv_channels_num * sizeof( signed short ) ); //Input audio buffer | |
unsigned int out_frames = sv_get_song_length_frames(0); | |
out_frames += g_sv_sampling_rate * POST_GAP; | |
unsigned int out_bytes = out_frames * sizeof( signed short ) * g_sv_channels_num; | |
unsigned int cur_frame = 0; | |
unsigned int val; | |
//WAV header: | |
fwrite( (void*)"RIFF", 1, 4, f ); | |
val = 4 + 24 + 8 + out_bytes; fwrite( &val, 4, 1, f ); | |
fwrite( (void*)"WAVE", 1, 4, f ); | |
//WAV FORMAT: | |
fwrite( (void*)"fmt ", 1, 4, f ); | |
val = 16; fwrite( &val, 4, 1, f ); | |
val = 1; fwrite( &val, 2, 1, f ); //format | |
val = g_sv_channels_num; fwrite( &val, 2, 1, f ); //channels | |
val = g_sv_sampling_rate; fwrite( &val, 4, 1, f ); //frames per second | |
val = g_sv_sampling_rate * g_sv_channels_num * sizeof( signed short ); fwrite( &val, 4, 1, f ); //bytes per second | |
val = g_sv_channels_num * sizeof( signed short ); fwrite( &val, 2, 1, f ); //block align | |
val = sizeof( signed short ) * 8; fwrite( &val, 2, 1, f ); //bits | |
// WAV Title: | |
fwrite( (void*)"LIST", 1, 4, f ); // chunk LIST | |
val = title_len+12; fwrite( &val, 4, 1, f ); // size of LIST: INFO+INAM+strlen | |
fwrite( (void*)"INFO", 1, 4, f ); // subtype INFO | |
fwrite( (void*)"INAM", 1, 4, f ); // tag INAM: Title of the subject of the file (name) | |
val = title_len; fwrite( &val, 4, 1, f ); // size of text | |
fwrite( (void*)title, 1, val, f ); // title text | |
//*/ | |
//WAV DATA: | |
fwrite( (void*)"data", 1, 4, f ); | |
fwrite( &out_bytes, 4, 1, f ); | |
int pos = 0; | |
sv_play_from_beginning(0); | |
while( keep_running && cur_frame < out_frames ) | |
{ | |
int size = g_sv_buffer_size; | |
if( cur_frame + size > out_frames ) | |
size = out_frames - cur_frame; | |
//Send it to SunVox and read the filtered output: | |
sv_audio_callback2( | |
buf, //output buffer | |
size, //output buffer length (frames) | |
0, //latency (frames) | |
sv_get_ticks(), //output time in system ticks | |
0, //input type: 0 - int16; 1 - float32 | |
g_sv_channels_num, //input channels | |
NULL //input buffer | |
); | |
cur_frame += size; | |
//Save this data to the file: | |
fwrite( buf, 1, size * g_sv_channels_num * sizeof( signed short ), f ); | |
//Print some info: | |
int new_pos = (int)( ( (float)cur_frame / (float)out_frames ) * 100 ); | |
if( pos != new_pos ) | |
{ | |
printf( "%d %%\n", pos ); | |
pos = new_pos; | |
} | |
} | |
fclose( f ); | |
free( buf ); | |
free( in_buf ); | |
} | |
else | |
{ | |
printf( "Can't open the file %s\n", argv[1] ); | |
} | |
sv_close_slot( 0 ); | |
sv_deinit(); | |
} | |
else | |
{ | |
printf( "sv_init() error %d\n", ver ); | |
} | |
sv_unload_dll(); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment