Last active
May 28, 2023 00:57
-
-
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
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
// | |
// * 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