Hi list
I'm working with ChucK in a musical project,
and I have a problem with the code.
This code generates 3 different error menssages in my machine
(running chuck-alsa on linux), depending on the amount of
components in an array.
1) A common
[chuck](VM): NullPointerException: shred[id=3:grancassa.ck], PC=[13]
2) A segfault, and
3) A king of 1) + 2) problem
[chuck](VM): NullPointerException: shred[id=3:grancassa.ck], PC=[13]
*** glibc detected *** chuck-alsa: double free or corruption (!prev): 0x08391c50 ***
======= Backtrace: =========
/lib/libc.so.6[0xb7c9d4b6]
/lib/libc.so.6(cfree+0x89)[0xb7c9f179]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb7eb4a61]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xb7eb4abd]
chuck-alsa[0x8055c25]
chuck-alsa[0x80583aa]
chuck-alsa[0x809b692]
chuck-alsa[0x80564f9]
chuck-alsa[0x8057ac8]
chuck-alsa[0x80afd98]
/lib/libc.so.6(__libc_start_main+0xe0)[0xb7c4cfe0]
chuck-alsa(__gxx_personality_v0+0x3a5)[0x804dfb1]
======= Memory map: ========
08048000-081a6000 r-xp 00000000 08:02 1107555 /usr/bin/chuck-alsa
081a6000-081ce000 rw-p 0015d000 08:02 1107555 /usr/bin/chuck-alsa
081ce000-08456000 rw-p 081ce000 00:00 0 [heap]
b63c4000-b63c5000 ---p b63c4000 00:00 0
b63c5000-b6bc5000 rw-p b63c5000 00:00 0
b6bc5000-b6bc6000 ---p b6bc5000 00:00 0
b6bc6000-b73c6000 rw-p b6bc6000 00:00 0
b73c6000-b73c7000 ---p b73c6000 00:00 0
b73c7000-b7bc9000 rw-p b73c7000 00:00 0
b7bc9000-b7bcd000 r-xp 00000000 08:02 509500 /usr/lib/libogg.so.0.5.3
b7bcd000-b7bcf000 rw-p 00003000 08:02 509500 /usr/lib/libogg.so.0.5.3
b7bcf000-b7c1e000 r-xp 00000000 08:02 510590 /usr/lib/libFLAC.so.8.1.0
b7c1e000-b7c20000 rw-p 0004f000 08:02 510590 /usr/lib/libFLAC.so.8.1.0
b7c20000-b7c33000 r-xp 00000000 08:02 455207 /lib/libpthread-2.6.1.so
b7c33000-b7c35000 rw-p 00013000 08:02 455207 /lib/libpthread-2.6.1.so
b7c35000-b7c37000 rw-p b7c35000 00:00 0
b7c37000-b7d64000 r-xp 00000000 08:02 455181 /lib/libc-2.6.1.so
b7d64000-b7d65000 r--p 0012c000 08:02 455181 /lib/libc-2.6.1.so
b7d65000-b7d67000 rw-p 0012d000 08:02 455181 /lib/libc-2.6.1.so
b7d67000-b7d6b000 rw-p b7d67000 00:00 0
b7d6b000-b7d75000 r-xp 00000000 08:02 455263 /lib/libgcc_s.so.1
b7d75000-b7d77000 rw-p 00009000 08:02 455263 /lib/libgcc_s.so.1
b7d77000-b7d9a000 r-xp 00000000 08:02 455189 /lib/libm-2.6.1.so
b7d9a000-b7d9c000 rw-p 00022000 08:02 455189 /lib/libm-2.6.1.so
b7d9c000-b7df2000 r-xp 00000000 08:02 1237590 /usr/lib/libsndfile.so.1.0.17
b7df2000-b7df4000 rw-p 00055000 08:02 1237590 /usr/lib/libsndfile.so.1.0.17
b7df4000-b7df8000 rw-p b7df4000 00:00 0
b7df8000-b7dfa000 r-xp 00000000 08:02 455187 /lib/libdl-2.6.1.so
b7dfa000-b7dfc000 rw-p 00001000 08:02 455187 /lib/libdl-2.6.1.so
b7dfc000-b7edf000 r-xp 00000000 08:02 510606 /usr/lib/libstdc++.so.6.0.9
b7edf000-b7ee2000 r--p 000e2000 08:02 510606 /usr/lib/libstdc++.so.6.0.9
b7ee2000-b7ee4000 rw-p 000e5000 08:02 510606 /usr/lib/libstdc++.so.6.0.9
b7ee4000-b7eea000 rw-p b7ee4000 00:00 0
b7eea000-b7fa1000 r-xp 00000000 08:02 509387 /usr/lib/libasound.so.2.0.0
b7fa1000-b7fa2000 r--p 000b6000 08:02 509387 /usr/lib/libasound.so.2.0.0
b7fa2000-b7fa6000 rw-p 000b7000 08:02 509387 /usr/lib/libasound.so.2.0.0
b7fa6000-b7fa7000 rw-p b7fa6000 00:00 0
b7fcc000-b7fe6000 r-xp 00000000 08:02 455174 /lib/ld-2.6.1.so
b7fe6000-b7fe8000 rw-p 0001a000 08:02 455174 /lib/ld-2.6.1.so
bfcf2000-bfd07000 rw-p bfcf2000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
Abortado
I think there is not a NullPointerException in the logic of the
chuck code, maybe I'm wrong, but the error menssages 2) and 3) are not
only chuck-code-logic-problems. I can't understand the problem and find
a workaround! If anyone can confirm that the error was due to a bug, or a mistake in my code,
I will be grateful. Here is the simplificated code...
//**************
// grancassa.ck
//**************
// To Test: $ chuck CADSR.ck percaditiva.ck grancassa.ck
public class GranCassa extends PercAditiva
{
int afinacion;
0 => int GRAVE;
1 => int MEDIO;
2 => int AGUDO;
float bfreq;
constructor();
fun void constructor() {
//***********************************************************************
// setNComponentes < 5
// [chuck](VM): NullPointerException: shred[id=3:grancassa.ck], PC=[13]
// setNComponentes = 5
// segfault
// setNComponentes > 5
// [chuck](VM): NullPointerException: shred[id=3:grancassa.ck], PC=[13]
// *** glibc detected *** chuck-alsa: double free or corruption (!prev): 0x083ae308 ***
//************************************************************************
setNComponentes( 5 );
setResonancia( 10::second, 4.0 );
setAfinacion( GRAVE );
setGanancias( 0 );
}
fun float tocar( float n ) {
setTAtaque( 2::second, 0 );
n => g.gain;
noteOn();
}
fun float apagar( float n ) {
if( n > 0.5 ) {
setTApagado( 0.25::second, -2 );
}
else {
setTApagado( 0.5::second, 2 );
}
noteOff();
}
fun void setAfinacion( int a ) {
a => afinacion;
setFrecuencias();
}
fun void setFrecuencias() {
if( afinacion == GRAVE )
40.0 => bfreq;
else if( afinacion == MEDIO )
80.0 => bfreq;
else // afinacion == AGUADO
120.0 => bfreq;
for( int i; i < ncomp; i++ ) {
bfreq + bfreq * 0.5 * i +
( Std.rand2f( -2.5, 2.5 ) ) => s[i].freq;
}
}
fun void setGanancias( int material ) {
for( int i; i < ncomp; i++ ) {
1.0 / (i + 1.0) => gain[i].gain;
}
}
}
// Test
GranCassa gc;
<<< "np" >>>;
gc.connectTo( dac );
while( true ) {
gc.tocar( 0.5 );
5::second => now;
gc.apagar( 0.7 );
2::second => now;
}
// End of grancassa.ck
//****************
// percaditiva.ck
//****************
// Super class for GranCassa
public class PercAditiva
{
12 => int MAX_COMP;
int ncomp;
SinOsc @ s[MAX_COMP];
CADSR @ env[MAX_COMP];
Gain @ gain[MAX_COMP];
Gain g;
fun void connectTo( UGen ug ) {
g => ug;
}
fun float setGain( float g_ ) {
g_ => g.gain;
}
fun float getGain() {
return g.gain();
}
fun void setNComponentes( int n ) {
if( n <= MAX_COMP && n >= 1 ) {
n => ncomp;
}
else {
<<< "(PercAditiva): Cantidad de componenetes no soportada" >>>;
<<< "(PercAditiva): ncomp = 6" >>>;
6 => ncomp;
}
for( int i; i < ncomp; i++ ) {
SinOsc saux @=> s[i];
CADSR caux @=> env[i];
Gain gaux @=> gain[i];
env[i].connectFrom( s[i] );
env[i].connectTo( gain[i] );
//s[i] => env[i].g => gain[i];
gain[i] => g;
}
}
fun void noteOn() {
for( int i; i < ncomp; i++ ) {
env[i].keyOn();
}
}
fun void noteOff() {
for( int i; i < ncomp; i++ ) {
env[i].keyOff();
}
}
fun void setTAtaque( dur dt, float factor ) {
for( int i; i < ncomp; i++ ) {
env[i].setAttack( dt, factor );
}
}
fun void setTApagado( dur dt, float factor ) {
for( int i; i < ncomp; i++ ) {
env[i].setRelease( dt, factor );
}
}
fun void setResonancia( dur dt, float factor ) {
for( int i; i < ncomp; i++ ) {
//*********************************************************
// Commenting the next line, no problem arise (¿?¿?¿?¿?)
//*********************************************************
env[i].setDecay( dt, float factor );
env[i].setSustain( 0.0 );
}
}
}
// End of percaditiva.ck
//**********
// CADSR.ck
//**********
// CADSR = CurveTable + (stk)ADSR
public class CADSR
{
CurveTable attack;
CurveTable decay;
CurveTable release;
Gain g;
dur atime;
dur dtime;
dur rtime;
float acurve;
float dcurve;
float rcurve;
float slevel;
float clevel; // current level
float rate;
float step;
int state;
0 => int ATTACK;
1 => int DECAY;
2 => int SUSTAIN;
3 => int RELEASE;
4 => int DONE;
constructor();
fun void constructor() {
setAttack( 0.5::second, 0.0 );
setDecay( 0.5::second, 0.0 );
setSustain( 0.5 );
setRelease( 0.5::second, 0.0 );
0.0 => g.gain;
}
fun void connectTo( UGen ug ) {
g => ug;
}
fun void connectFrom( UGen ug ) {
ug => g;
}
fun void setAttack( dur t, float curve ) {
t => atime;
curve => acurve;
}
fun void setDecay( dur t, float curve ) {
t => dtime;
curve => dcurve;
}
fun void setSustain( float level ) {
level => slevel;
}
fun void setRelease( dur t, float curve ) {
t => rtime;
curve => rcurve;
}
fun void keyOn() {
// Si se ataca continua sin apagar, se mantienen los shreds
// VERIFICAR
spork ~ computeSamples();
me.yield(); // para darle oportunidad que corra el shred (?)
}
fun void keyOff() {
if( state == DONE | state == RELEASE ) return;
RELEASE => state;
}
fun void computeSamples() {
if( state == ATTACK ) {
// Las CurveTable se inicializan acá porque si no, hay
// problemas con la inicialización y los índices.
[ 0.0, 0.0, acurve, 1.0, 1.0 ] => attack.coefs;
0.0 => clevel;
0.0 => step;
1.0 / ( atime / samp ) => rate;
while( state == ATTACK ) {
attack.lookup( step ) => g.gain => clevel;
rate +=> step;
// La comparación debe ir antes de que se realize el
// cómputo (pase el tiempo) por la concurrencia
// de state con respecto a RELEASE. !!!
if( step >= 1.0 ) DECAY => state;
1::samp => now;
}
}
if( state == DECAY ) {
[ 0.0, clevel, dcurve, 1.0, slevel ] => decay.coefs;
0.0 => step;
1.0 / ( dtime / samp ) => rate;
while( state == DECAY ) {
decay.lookup( step ) => g.gain => clevel;
rate +=> step;
if( step >= 1.0 ) SUSTAIN => state;
1::samp => now;
}
}
// Este no if está demás por el paso del tiempo en el shred
if( state == SUSTAIN ) {
while( state == SUSTAIN ) {
// clevel ~= slevel
clevel => g.gain;
1::samp => now;
}
}
if( state == RELEASE ) {
[ 0.0, clevel, rcurve, 1.0, 0.0 ] => release.coefs;
0.0 => step;
1.0 / ( rtime / samp ) => rate;
while( state == RELEASE ) {
release.lookup( step ) => g.gain => clevel;
rate +=> step;
if( step >= 1.0 ) DONE => state;
1::samp => now;
}
}
// Este if está demás (?)
if( state == DONE ) {
// por si las dudas
0.0 => g.gain;
1::samp => now;
}
}
}
// End of CADSR.ck
Thanks
Lucas