its similar to FM/ AM, but requires less parameters.
Sounds much like a n acoustic piano ( if it does not, and sounds like a buzz you need to restart..)
especially surprising is the dynamic and natural evolution of the deacy
it works like this: the oscillator spins on x, y and z axis, with different speeds,
while the radius decays
the ouput is the radius projected on x,y
( with dc offset you need to filter which I have omitted fior clarity )
Code: Select all
//################ 3D oscillatir demo
// spins in 3d with different speeds of x,y,and z axis
// very similar to fm/am, but more easy to use
// there is some initialisation bug, if it doesnt sound
// like a decent acoustic piano, retry
sample_rate = 44100
num_channels = 2 //stereo output
test=""
scr = get_screen()
xsize = get_xsize( scr )
ysize = get_ysize( scr )
hxsize = xsize / 2
hysize = ysize / 2
ratios = new( 34,1, FLOAT32) // modulation ratios
ratios[ 0 ] = 1
ratios[ 1 ] = 6/5
ratios[ 2 ] = 4/5
ratios[ 3 ] = 4/3
ratios[ 4 ] = 1.5
ratios[ 5 ] = 5/3
ratios[ 6 ] = 1.75
ratios[ 7 ] = 1.8
for ( i = 8; i<24; i+1){
ratios[ i ] = ratios[ i % 8 ] * (i div 8 +1)
}
samplerate = 44100
pi2 = 2 * M_PI
voices = 4
unis = 1
voicyc = 0
feedback = 0/ pi2
buf = new( 4096, 1, FLOAT32)
osc = new( voices)
for ( $v = 0; $v < voices; $v +1){
osc[ $v ] = new( 3, 1, FLOAT32)
rt= 4
rt2 = 8
zdep= 0.6
clean( osc_[ $v ] )
set_prop( osc[ $v ], "w", 0.012)
set_prop( osc[ $v ], "rt", ratios[rt])
set_prop( osc[ $v ], "rt2", ratios[rt2])
set_prop( osc[ $v ], "ph", 0.0)
set_prop( osc[ $v ], "ph2", 0.25)
set_prop( osc[ $v ], "ph3", 0.25)
set_prop( osc[ $v ], "r", 0.0)
set_prop( osc[ $v ], "zdep", 0.5)
set_prop( osc[ $v ], "fb", 0.0 )
set_prop( osc[ $v ], "state", 1)
}
for ( $v = 0; $v< voices; $v +1){
set_prop( osc[ $v ], "w", 440/samplerate )
set_prop( osc[ $v ], "ph", 0 )
set_prop( osc[ $v ], "ph2", 0.25 )
set_prop( osc[ $v ], "ph3", 0.25 )
set_prop( osc[ $v ], "rt", ratios[rt])
set_prop( osc[ $v ], "rt2", ratios[rt2])
tick_osc( $v, 1)
}
fn set_oscf( $v, $f, $zdep){
set_prop( osc[ $v ], "w", $f / samplerate )
set_prop( osc[ $v ], "zdep", $zdep)
set_prop( osc[ $v ], "state", 0 )
ret
}
fn set_oscrt( $rt, $rt2){
for ( $v = 0; $v< voices; $v +1){
set_prop( osc[ $v ], "rt", ratios[rt])
set_prop( osc[ $v ], "rt2", ratios[rt2])
}
ret
}
// ######## below is the oscillator, $v = voice, $scal = decay per tick
// r = radius / amplitude
// w = omega, normalized frequency
// ph..2,3 = phase x, y, z
// rt = frequency ratio y, z
// fb = feedback
// zdep = 2D / 3D z scaling, 0...1
// output is sqrt of x*x + y*y
// in other words there is dc offset ...
// this doesent matter when you feed the output into a pick simulation
// ( not included in this version )
// not optimized and using trig operations for clarity
//
fn tick_osc( $v, $scal){
if get_prop( osc[ $v ], "state" ) ==0 {
set_prop( osc[ $v ], "r", M_SQRT1_2 )
set_prop( osc[ $v ], "ph", 0 )
set_prop( osc[ $v ], "ph2", 0.25 )
set_prop( osc[ $v ], "ph3", 0.25 )
set_prop( osc[ $v ], "rt", ratios[rt])
set_prop( osc[ $v ], "rt2", ratios[rt2])
set_prop( osc[ $v ], "state", 1 )
}
$r = get_prop( osc[ $v ], "r") * $scal
$w = get_prop( osc[ $v ], "w" ) + get_prop( osc[ $v ], "fb" )
$rt = get_prop( osc[ $v ], "rt" )
$rt2 = get_prop( osc[ $v ], "rt2" )
$zdep= get_prop( osc[ $v ], "zdep" )
$ph = get_prop( osc[ $v ], "ph" ) + get_prop( osc[ $v ], "w" ) + get_prop( osc[ $v ], "fb" )
$ph2 = get_prop( osc[ $v ], "ph2" ) + get_prop( osc[ $v ], "w" ) * $rt
$ph3 = get_prop( osc[ $v ], "ph3" ) + get_prop( osc[ $v ], "w" ) * $rt2
set_prop( osc[ $v ], "ph", $ph )
set_prop( osc[ $v ], "ph2", $ph2 )
set_prop( osc[ $v ], "ph3", $ph3 )
set_prop( osc[ $v ], "r", $r )
osc[ $v ][0] =(1 + ( cos( pi2 * $ph3) -1 ) *$zdep)* cos( pi2 * $ph2) * $r
osc[ $v ][1] =(1 + (sin( pi2 * $ph3) -1 ) *$zdep)* sin( pi2 * $ph) * $r
// z positi9n not needed here:
//osc[ $v ][2] =(1 + ( sin( pi2 * $ph2) -1 ) *$zdep)* cos( pi2 * ph ) * $r
// outpout: [in audiocallback
//$vec = sqrt(osc[ $v ][ 0 ]*osc[ $v ][ 0 ]+ osc[ $v ][ 1 ]*osc[ $v ][ 1 ])
//feedback
$fb = osc[ $v ][0] * feedback
set_prop( osc[ $v ], "fb", $fb )
ret
}
// ########### end of oscillator code
//######### ui and audio render, slightly buggy.. ###########№##
fn audio_callback(
$stream,
$userdata,
$channels,
$frames,
$output_time_in_system_ticks,
$in_channels,
$latency_in_frames )
{
clean( $channels[ 0 ] )
clean( buf )
$ti = 0
while $ti < $frames {
$v = 0
while $v < voices {
tick_osc( $v, 0.99995)
$vec = sqrt(osc[ $v ][ 0 ]*osc[ $v ][ 0 ]+ osc[ $v ][ 1 ]*osc[ $v ][ 1 ])
buf[ $ti ] + $vec *0.3
$v +1
}
$ti +1
}
op_cc( OP_ADD, $channels[ 0 ], buf, 0, 0, $frames )
//num_to_str( test, $frames )
ret( 1 )
}
set_audio_callback( audio_callback, 0, 44100, FLOAT32, 1 )
while( 1 )
{
while( get_event() ) {
if EVT[ EVT_TYPE ] == EVT_QUIT { breakall }
if EVT[ EVT_TYPE ] == EVT_MOUSEBUTTONDOWN{
$x = EVT[ EVT_X ]
$y = EVT[ EVT_Y ]
if $y > 0 {
mode = -1
voicyc + unis
voicyc % voices
note = 36 + floor(($x + xsize/2) / xsize * 36 )
if note > 35 {
$f = pow( 2, (note-69)/12 ) * 440
set_oscf( voicyc, $f, zdep)
//set_oscf( voicyc +1, $f + 0.02)
zdep = 1- $y / hysize
}
} else {
mode=floor((-4 * $y / hysize))
if mode == 3
{
$rt = rt
$rt2 = rt2
$rtnew = floor(($x + xsize/2) / xsize * 24 )
rt = $rtnew rt2 = $rt2
set_oscrt( rt, rt2)
}
if mode == 2
{
$rt = rt
$rt2 = rt2
$rtnew = floor(($x + xsize/2) / xsize * 24 )
rt = $rt rt2 = $rtnew }
set_oscrt( rt, rt2)
}
if mode == 1
{ feedback = ($x + xsize/2) / xsize
feedback * feedback
feedback / pi2
}
}
}
//transp(32)
clear()
$x = (note -36)/ 36 * xsize - xsize/2
line( $x, 0, $x, ysize/2, RED)
line( -xsize/2, 0, xsize/2, 0, RED)
fbox( -xsize/2, -ysize/2, rt* xsize/24, ysize/8, GREEN)
fbox( -xsize/2, -ysize*0.4, rt2* xsize/24, ysize/8, GREEN)
fbox( -xsize/2, -ysize*0.25, sqrt(feedback)* xsize, ysize/8, BLUE)
fbox( -xsize/2, -ysize*0.125, zdep* xsize, ysize/8, WHITE)
num_to_str(test, mode)
print( test, -xsize / 2 + 8, -ysize / 2 + 8, WHITE, LEFT | TOP )
frame(50)
}