Browse Source

add files

master
acheney 6 months ago
parent
commit
fb6d62f1d2
  1. 2
      LICENSE
  2. 15
      README.md
  3. 526
      scl_to_curve3.pixi
  4. 414
      scl_to_set_pitch.pixi

2
LICENSE

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
MIT License
Copyright (c) <year> <copyright holders>
Copyright (c) 2023 A Cheney
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

15
README.md

@ -1,2 +1,15 @@ @@ -1,2 +1,15 @@
# scl_to_sunvox_converters
# abstract
here are two files for converting `.scl` files to sunvox's own pitch format
they are:
- `scl_to_curve3.pixi`: converts `.scl` files to a `.curve16bit` file for the multisynth's curve3. you can also specify a scale to map to 12 notes; details are in the file
- `scl_to_set_pitch.pixi`: converts `.scl` files to a sunvox project with all of the notes in the tuning laid out as SP (set pitch) commands
to use these, download pixilang and run the `.pixi` file of your choosing. all of the information in the log will be displayed on the screen
# credits
the program was written by me, except for the `show_log()` function, which was originally written by nightradio and modified by me

526
scl_to_curve3.pixi

@ -0,0 +1,526 @@ @@ -0,0 +1,526 @@
// .scl to sunvox curve3 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
// enables mapping the tuning to 12 notes
// the notes will be mapped according to brensenham's line algorithm
map_to_12_notes = 0
// if map_to_12_notes is enabled, change the below declaration to your desired mapping
// the indices of the tuning start at 0
// the below example is a ten-note tuning mapped to 12 notes
map_scale = new( 10, 1, INT16 )
map_scale[ 0 ] = 0
map_scale[ 1 ] = 1
map_scale[ 2 ] = 2
map_scale[ 3 ] = 3
map_scale[ 4 ] = 4
map_scale[ 5 ] = 5
map_scale[ 6 ] = 6
map_scale[ 7 ] = 7
map_scale[ 8 ] = 8
map_scale[ 9 ] = 9
// - END CONFIG -
scl_filename = file_dialog( "load .scl file", "scl", "file.scl" )
scl_name = ""
scl_size = 0
scl_list = new( 1024, 1, INT8 )
scl_pitches = new( 128, 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( )
if map_to_12_notes
{
scl_pitches = scl_map( map_scale, scl_pitches, scl_size )
if scl_pitches != -1
{
scl_save( scl_name, scl_pitches )
}
} else {
scl_save( scl_name, scl_pitches )
}
}
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 < 128 {
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_pitch( 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_pitch( 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_pitch( tuning_center_freq * center_offset )
}
// logf( "pitch written to %d: %d\n", i, scl_pitches[ i ] )
i = i + 1
}
}
fn freq_to_pitch( $freq ) {
ret( log2( $freq / 16.333984375 ) * 3072 + 16384 )
}
fn scl_save( $name, $pitches )
{
$name = sanitize( $name )
// logf( "sanitized filename: %s\n", $name )
strcat( $name, ".curve16bit" )
if save( $pitches, $name, FORMAT_RAW ) == 0 { logf( "file saved!\n" ) }
}
fn scl_map( $scale, $tuning, $tuning_length )
{
$tuning_dest = clone( $tuning )
$scale_length = get_size( $scale )
if $scale_length > $tuning_length
{
logf( "ERROR: scale length is greater than tuning size\n" )
ret( -1 )
}
if $scale_length > 12
{
logf( "ERROR: scale length is greater than 12\n" )
ret( -1 )
}
if $scale[ $scale_length - 1 ] > ( $tuning_length - 1 )
{
logf( "ERROR: scale degrees are greater than tuning size\n" )
ret( -1 )
}
$i = 0 while $i < 128 {
// logf( "i: %d\n", $i )
$mod_keyboard_index = ( ( $i + 12 ) - ( ( tuning_center_midi ) % 12 ) ) % 12
// logf( "mod keyboard index: %f\n", $mod_keyboard_index )
$mod_period = floor( ( $i - ( tuning_center_midi ) ) / 12 )
// logf( "mod period: %f\n", $mod_period )
$mod_tuning_index = brensenham( 0, 0, 11, $scale_length - 1 , $mod_keyboard_index )
// logf( "mod tuning index: %f\n", $mod_tuning_index )
$mod_scale_index = $scale[ $mod_tuning_index ]
// logf( "mod scale index: %f\n", $mod_scale_index )
$mod_tuning_lookup = $mod_scale_index + ( ( $tuning_length ) * $mod_period ) + tuning_center_midi
// logf( "mod tuning lookup: %f\n", $mod_tuning_lookup )
$tuning_dest[ $i ] = $tuning[ $mod_tuning_lookup ]
$i = $i + 1
}
ret( $tuning_dest )
}
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 brensenham( $x0, $y0, $x1, $y1, $xi )
{
$dx = $x1 - $x0
$dy = $y1 - $y0
$d = 2 * $dy - $dx
$y = $y0
$x = $x0 while $x < $xi {
if $d > 0
{
$y = $y + 1
$d = $d - 2 * $dx
}
$d = $d + 2 * $dy
$x = $x + 1
}
ret( $y )
}
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()
}
}

414
scl_to_set_pitch.pixi

@ -0,0 +1,414 @@ @@ -0,0 +1,414 @@
// .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()
}
}
Loading…
Cancel
Save