Skip to content

Instantly share code, notes, and snippets.

@vladkorotnev
Last active May 28, 2023 00:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vladkorotnev/d5218a4c99bbb09951350dc8efaaf3fc to your computer and use it in GitHub Desktop.
Save vladkorotnev/d5218a4c99bbb09951350dc8efaaf3fc to your computer and use it in GitHub Desktop.
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