// .scl to sunvox set pitch (sp) converter // by acheney // under mit license // NOTE: BE SURE THERE ARE NO DUPLICATE LINE ENDINGS IN YOUR .SCL FILE, OR ELSE THE SCRIPT WILL FAIL! // .scl files generated using sevish's scale workshop should work fine, as well as .scl files saved locally on your system // but if you download an .scl file from anywhere else, be sure to convert the line endings to those of your os // on linux/osx you can use dos2unix, and on windows unix2dos, or for both, any text editor that lets you convert line endings // - BEGIN CONFIG - // the frequency of the tuning center in hertz tuning_center_freq = 440 // the midi note to use as the tuning center. 57 = A4 tuning_center_midi = 57 // - END CONFIG - sv = sv_new() scl_filename = file_dialog( "load .scl file", "scl", "file.scl" ) scl_name = "" scl_size = 0 scl_list = new( 1024, 1, INT8 ) scl_pitches = new( 120, 1, INT16 ) clean( scl_list, 0 ) clean( scl_pitches, 0 ) scl_read( scl_filename ) logf( "name: %s\n", scl_name ) logf( "size: %d\n", scl_size ) resize( scl_list, scl_size ) if (scl_size > 0 ) { scl_write( ) sv_set_name( sv, scl_name ) sv_lock( sv ) sv_new_module( sv, "Analog generator", "Preview", 256, 512, 0 ) sv_connect_module( sv, 1, 0 ) pat = sv_new_pattern( sv, -1, 0, 0, 1, 120, 0, scl_name ) sv_unlock( sv ) i = 0 while i < 120 { sv_lock( sv ) sv_set_pattern_event( sv, pat, 0, i, NOTECMD_SET_PITCH, 00, 02, 0000, scl_pitches[ i ] ) sv_unlock( sv ) i = i + 1 } scl_name = sanitize( scl_name ) // logf( "sanitized filename: %s\n", scl_name ) strcat( scl_name, ".sunvox" ) if sv_save( sv, scl_name ) == 0 { logf( "file saved!\n" ) } } sv_remove( sv ) logf( "\n" ) show_log() fn scl_read( $scl_filename ) { $temp_string = new( 1024, 1, INT8 ) $length = 0 $metadata_counter = 0 $list_counter = 0 $is_comment = 0 logf( "file to load: %s\n", $scl_filename ) $scl_file = fopen( $scl_filename, "r" ) if $scl_file == 0 { ret( -1 ) } while 1 { $length = fgets( $temp_string, 2048, $scl_file ) if ( $length == -1 ) { break } if ( $length >= 0 ) { // logf( "read string: %s\n", $temp_string ) if ( $temp_string[ 0 ] == '!' ) { $is_comment = 1 } else { $is_comment = 0 } if ( $is_comment == 0 ) { if ( $metadata_counter >= 2 ) { scl_list[ $list_counter ] = strip_character( $temp_string, ' ' ) $list_counter = $list_counter + 1 } if ( $metadata_counter == 1 ) { $metadata_counter = 2 if ($length == 0) { logf("ERROR: no size specified\n") breakall } else { // logf( "number conversion: %d\n", str_to_num( strip_character( $temp_string, ' ' ) ) ) scl_size = str_to_num( strip_character( $temp_string, ' ' ) ) } } if ( $metadata_counter == 0 ) { $metadata_counter = 1 if ($length == 0) { logf("WARNING: no name found. defaulting to filename...\n") strcat( scl_name, basename( $scl_filename, 0 ) ) } else { strcat( scl_name, $temp_string ) } } } else { // logf( "comment found, skipping...\n" ) } } } remove( $temp_string ) fclose( $scl_file ) } fn strip_character( $input, $c ) { $non_char_count = 0 $dest = clone( $input ) $i = 0 while $i < get_xsize( $input ) + 1 { if ( $input[ $i ] != $c ) { $dest[ $non_char_count ] = $input[ $i ] $non_char_count = $non_char_count + 1 } $i = $i + 1 } ret( $dest ) } fn scl_write( ) { scl_multipliers = new( scl_size, 1, FLOAT ) current_midi = 0 multiplier_power = 1 i = 0 while i < get_xsize( scl_list ) { scl_multiplier = 0 current_midi = 0 if ( strstr( scl_list[ i ], "." ) != -1 ) { scl_multiplier = pow( 2, ( ( str_to_num( scl_list[ i ] ) / 100 ) / 12 ) ) } else { numerator = new( 256, 1, INT8 ) clean( numerator, 0 ) denominator = new( 256, 1, INT8 ) clean ( denominator, 0 ) slash_offset = 0 no_denominator = 0 j = 0 while 1 { if ( scl_list[ i ][ j ] == '/' || scl_list[ i ][ j ] == '\\' ) { break } if ( scl_list[ i ][ j ] == ' ' || scl_list[ i ][ j ] == 0 ) { no_denominator = 1 break } numerator[ j ] = scl_list[ i ][ j ] j = j + 1 slash_offset = slash_offset + 1 } if ( no_denominator == 0 ) { j = 0 while 1 { if ( scl_list[ i ][ j + slash_offset + 1 ] == 0 || scl_list[ i ][ j + slash_offset + 1 ] == ' ' ) { break; } denominator[ j ] = scl_list[ i ][ j + slash_offset + 1 ] j = j + 1 } } else { denominator[ 0 ] = '1' } scl_multiplier = str_to_num( numerator ) / str_to_num( denominator ) } scl_multipliers[ i ] = scl_multiplier // logf( "multiplier written to %d: %f\n", i, scl_multipliers[ i ] ) i = i + 1 } i = 0 while i < get_xsize( scl_multipliers ) { i = i + 1 } i = 0 while i < 120 { multiplier_power = floor( ( i - tuning_center_midi ) / scl_size ) // logf( "multiplier power: %d\n", multiplier_power ) center_offset = pow( scl_multipliers[ scl_size - 1 ], multiplier_power ) // logf( "center offset: %d\n", center_offset ) if ( i < tuning_center_midi ) { scl_pitches[ i ] = freq_to_sp( tuning_center_freq * scl_multipliers[ ( ( ( i - tuning_center_midi ) % scl_size ) - 1 ) + scl_size ] * center_offset ) } if ( i > tuning_center_midi ) { scl_pitches[ i ] = freq_to_sp( tuning_center_freq * scl_multipliers[ ( i - tuning_center_midi ) % ( scl_size ) - 1 ] * center_offset ) } if ( ( tuning_center_midi - i ) % scl_size == 0 ) { scl_pitches[ i ] = freq_to_sp( tuning_center_freq * center_offset ) } // logf( "pitch written to %d: %d\n", i, scl_pitches[ i ] ) i = i + 1 } } fn freq_to_sp( $freq ) { ret( 30720 - log2( $freq / 16.3339 ) * 3072 ) } fn sanitize( $input ) { $output = clone( $input ) i = 0 while i < get_xsize( $input ) { if $input[ i ] == '/' { $output[ i ] = '_' } if $input[ i ] == '\\' { $output[ i ] = '_' } if $input[ i ] == '\'' { $output[ i ] = '_' } if $input[ i ] == '\"' { $output[ i ] = '_' } if $input[ i ] == '\ ' { $output[ i ] = '_' } if $input[ i ] == ':' { $output[ i ] = '_' } if $input[ i ] == ',' { $output[ i ] = '_' } if $input[ i ] == '.' { $output[ i ] = '_' } i = i + 1 } ret( $output ) } fn strrchr( $s, $c ) { $i = 0 $k = 0 for( $i = strlen( $s ); $i >= 0; $i - 1 ) { if $s[ $i ] == $c { $k = 1 break } } if $k { ret( $i ) } else { ret( -1 ) } } fn basename( $p, $x ) { $n = "" strcat( $n, 0, $p, strrchr( $p, '/' ) + 1 ) if $x { ret( $n ) } else { $nnxl = strrchr( $n, '.' ) $nnx = new( $nnxl, 1, INT8 ) $i = 0 while $i < get_size( $nnx ) { $nnx[ $i ] = $n[ $i ] $i = $i + 1 } ret( $nnx ) } } fn show_log() { $l = get_system_log() clear() print( $l, 0, 0, WHITE, CENTER | CENTER ) frame() remove( $l ) while 1 { while( get_event() ) { if EVT[ EVT_TYPE ] == EVT_QUIT { halt } } frame() } }