ChucK

Code:
// open MIDI kanaal naar Q25
MidiIn min;
MidiMsg msg;
min.open(1);


// wacht op midi event
min => now;
    // receive midimsg(s)
if( min.recv( msg ) )
{

// print MIDI en frequentie
<<< msg.data1, msg.data2, msg.data3 >>>;
<<< Std.mtof(msg.data2) >>>;


// speel oscillator af
SawOsc s => dac;
Std.mtof(msg.data2) => s.freq;
0.5 => s.gain;
1::second => now;

}

Weer een klein stapje verder, hiermee kan ik precies één aangeslagen noot spelen waarna het progje stopt. :D
 
Lastig is dat ik steeds met hangende tonen zit. Maar dit gaat nog wel goed:
Code:
// open MIDI kanaal naar Q25
MidiIn min;
MidiMsg msg;
min.open(1);


while(true)
{


// wacht op midi-on event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
  {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;

     // als MIDI On message print dat dan
     if( msg.data1 == 144 )
          {
              <<< "MIDI On gesignaleerd" >>>;
          }
   }



// wacht op midi-off event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
   {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;
 
    // als MIDI Off message print dat dan
    if( msg.data1 == 128 )
         {
             <<< "MIDI Off gesignaleerd" >>>;
         }
   }


}
 
Wie helpt mij de fout te zoeken? Waarom blijven in het onderstaaande progje de tonen na eenmaal te zijn aangeslagen hangen?

Code:
// open MIDI kanaal naar Q25
MidiIn min;
MidiMsg msg;
min.open(1);


while(true)
{


// wacht op midi-on event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
  {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;

     // als MIDI On message print dat dan
     if( msg.data1 == 144 )
          {
              <<< "MIDI On gesignaleerd" >>>;
              // toon spelen
              SawOsc s => dac;
              Std.mtof(msg.data2) => s.freq;
              0.5 => s.gain;
              0.5::second => now;
          }
   }




// wacht op midi-off event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
   {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;
 
    // als MIDI Off message print dat dan
    if( msg.data1 == 128 )
         {
             <<< "MIDI Off gesignaleerd" >>>;
         }
   }


}
 
Zo is het nog niet helemaal goed want snel achter elkaar aangeslagen noten worden later alsnog afgespeeld, maar de noten blijven in elk geval niet meer hangen:

Code:
// open MIDI kanaal naar Q25
MidiIn min;
MidiMsg msg;
min.open(1);


while(true)
{


// wacht op midi-on event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
  {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;

     // als MIDI On message print dat dan
     if( msg.data1 == 144 )
          {
              <<< "MIDI On gesignaleerd" >>>;
              // toon spelen
              SawOsc s => dac;
              Std.mtof(msg.data2) => s.freq;
              0.5 => s.gain;
              0.5::second => now;
              0 => s.gain;
              0.5::second => now;
          }
   }




// wacht op midi-off event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
   {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;
 
    // als MIDI Off message print dat dan
    if( msg.data1 == 128 )
         {
             <<< "MIDI Off gesignaleerd" >>>;
         }
   }


}
 
Laatst gewijzigd:
Zo is het nog niet helemaal goed want snel achter elkaar aangeslagen noten worden later alsnog afgespeeld

Er zit een tijdsfactor in van 0,5 seconden, als ik naar de code kijk? Gaat het mis als je binnen die halve seconde noten aanslaat?
 
Ik heb nu binnen de while-loop onderstaande stille noot (gain=0) toegevoegd:

Code:
              0 => s.gain;
              0.5::second => now;

Dat geeft een rust van een halve seconde en breekt daarmee het hangen van de noten. Als ik dat niet doe blijven alle eenmaal aangeslagen tonen vanwege de while-loop voor eeuwig klinken. Maar het is mij nog steeds niet helemaal duidelijk hoe die while-loop precies werkt. Alles wat bij mijn laatste progje gedurende het afspelen van een aangeslagen noot of de bijbehorende rust nog meer wordt aangeslagen wordt door het programma onthouden en daarna dan alsnog afgespeeld. Een bizarre variant van een monofone synth! :P
 
Iets beter (een rust van slechts 1 sample):

Code:
// open MIDI kanaal naar Q25
MidiIn min;
MidiMsg msg;
min.open(1);


while(true)
{


// wacht op midi-on event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
  {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;

     // als MIDI On message print dat dan
     if( msg.data1 == 144 )
          {
              <<< "MIDI On gesignaleerd" >>>;
              // toon spelen
              SawOsc s => dac;
              Std.mtof(msg.data2) => s.freq;
              0.5 => s.gain;
              0.5::second => now;
              0 => s.gain;
              1::samp => now;
          }
   }




// wacht op midi-off event
min => now;
// receive midimsg(s)
if( min.recv( msg ) )
   {
     // print MIDI en frequentie
     <<< msg.data1, msg.data2, msg.data3 >>>;
     <<< Std.mtof(msg.data2) >>>;
 
    // als MIDI Off message print dat dan
    if( msg.data1 == 128 )
         {
             <<< "MIDI Off gesignaleerd" >>>;
         }
   }


}
 
Weer ietsjes beter (een ADSR toegevoegd):

Code:
// open MIDI channel to Q25
MidiIn min;
MidiMsg msg;
min.open(1);


// patch
SawOsc s => ADSR e => dac;


// set A, D, S, R
e.set( 1::ms, 2::ms, .7, 30::ms );


// infinite time-loop
while( true )
{

//receive MIDI messages
min => now;
if( min.recv(msg) )
{


// print MIDI-message
<<< msg.data1, msg.data2, msg.data3 >>>;

// set frequency
Std.mtof( msg.data2 ) => s.freq;

// key on
if (msg.data1==144) {e.keyOn();}

// key off
if (msg.data1==128) {e.keyOff();}


}


// allow the RELEASE to ramp down to 0
e.releaseTime() => now;


// return infinite time-loop
}

Maar twee of meer toetsen tegelijk aanslaan vindt die nog steeds niet fijn. En ook krijg ik de velocity van de aanslag niet goed, alles klinkt even hard.
 
Is er geen stukje code beschikbaar die de basisdingetjes doet, waarop je kunt voortborduren? Het is nu echt vanaf de grond opbouwen.
 
Dat is ook mijn bedoeling om alles zo veel mogelijk zelf uit te zoeken en zo te leren hoe en waarom dat zo werkt. Alleen wanneer ik helemaal vast loop kijk is soms even af bij een werkend voorbeeld. Zoals die ADSR enveloppe die ga ik niet zelf bouwen, dus heb ik even in een voorbeeldje opgezocht hoe je die moet aansturen.
 
Ah, okay. Ja, van het zelf doen leer je inderdaad het meeste. Maar goed, van effen spieken soms toch ook wel een beetje. :D
 
Code:
// open MIDI channel to Q25
MidiIn min;
MidiMsg msg;
min.open(1);


//-------------------------------------------------------------

// define class X
class X {static int mononote;}
// initialize mononote
0 => X.mononote;


//-------------------------------------------------------------

// set parameters

// attack a
1::ms => dur A;

// decay
2::ms => dur D;

// sustain
0.7 => float S;

// release
20::ms => dur R;

// reverb mix
0.05 => float revmix;

// detune factor d
0.04 => float d;


//-------------------------------------------------------------

// patches
SawOsc s1 => ADSR e1 => NRev reverb1 => dac;
SqrOsc s2 => ADSR e2 => NRev reverb2 => dac;


//-------------------------------------------------------------

// set envelopes e1 and e2
e1.set( A, D, S, R );
e2.set( A, D, S, R );


// set reverb mix's
revmix => reverb1.mix;
revmix => reverb2.mix;


//-------------------------------------------------------------

// infinite time-loop
while( true )
{


//receive MIDI messages
min => now;

// if-loop received messages
if( min.recv(msg) )
{

    // monophonic note
    if (msg.data1 == 144 && X.mononote == 0) {msg.data2 => X.mononote;}
    if (msg.data1 == 128 && msg.data2 == X.mononote) {0 => X.mononote;}


    // set frequencies s1 and s2
    if (msg.data1==144 && msg.data2 == X.mononote)
    {
    Std.mtof(msg.data2) => s1.freq;
    Std.mtof(msg.data2) => s2.freq;   
    }   

    // set velocities s1 and s2
    msg.data3/127.0 => s1.gain;
    msg.data3/127.0 => s2.gain;


    // key on e1 and e2
    if (msg.data1==144 && msg.data2 == X.mononote)
    {
    e1.keyOn();
    e2.keyOn();
    }


    // key off e1 and e2
    if (msg.data1==128 && X.mononote == 0)
    {
    e1.keyOff();
    e2.keyOff();
    }


// end if-loop received messages
}


// allow e1 and e2 to ramp down to 0
e1.releaseTime() => now;
e2.releaseTime() => now;


// return infinite time-loop
}

Zo - het monophonic verhaal werkt nu ook! :) En ik heb er ook nog velocity, detune en reverb bij gemaakt. Voorlopig mooi genoeg om te weten dat ik met Chuck uit de voeten kan. Leuk om later verder mee te knutselen. Nu alleen nog even Sonic Pi uitproberen en als dat ook bevalt dan zit mijn oriëntatiefase erop.
 
Code:
// open MIDI channel to Q25
MidiIn min;
MidiMsg msg;
min.open(1);


//-------------------------------------------------------------

// define class X
class X {static int mononote;}
// initialize mononote
0 => X.mononote;


//-------------------------------------------------------------

// set parameters

// Moog filter
0.8 => float Q;
0.7 => float SweepRate;
1.0 => float Speed;
1.0 => float Depth;
1.0 => float VibFreq;
1.0 => float VibGain;
0.0 => float Volume;


//envelope
// attack
1::ms => dur A;
// decay
2::ms => dur D;
// sustain
0.7 => float S;
// release
20::ms => dur R;


// reverb mix
0.2 => float revmix;


// detune factor d
0.14 => float d;


//-------------------------------------------------------------

// patches
Moog mo1 => ADSR e1 => NRev reverb1 => dac;
Moog mo2 => ADSR e2 => NRev reverb2 => dac;


//-------------------------------------------------------------

// initialize mo1
Q => mo1.filterQ;
SweepRate => mo1.filterSweepRate;
Speed => mo1.lfoSpeed;
Depth => mo1.lfoDepth;
VibFreq => mo1.vibratoFreq;
VibGain => mo1.vibratoGain;
Volume => mo1.volume;

// initialize mo2
Q => mo2.filterQ;
SweepRate => mo2.filterSweepRate;
Speed => mo2.lfoSpeed;
Depth => mo2.lfoDepth;
VibFreq => mo2.vibratoFreq;
VibGain => mo2.vibratoGain;
Volume => mo2.volume;

// initialize envelopes e1 and e2
e1.set( A, D, S, R );
e2.set( A, D, S, R );

// initialize reverb mix's
revmix => reverb1.mix;
revmix => reverb2.mix;


//-------------------------------------------------------------

// infinite time-loop
while( true )
{


//receive MIDI messages
min => now;

// if-loop received messages
if( min.recv(msg) )
{

    // monophonic note
    if (msg.data1 == 144 && X.mononote == 0) {msg.data2 => X.mononote;}
    if (msg.data1 == 128 && msg.data2 == X.mononote) {0 => X.mononote;}


    // set frequencies mo1 and mo2
    if (msg.data1==144 && msg.data2 == X.mononote)
    {
       Std.mtof(msg.data2) => mo1.freq;
       Std.mtof(msg.data2) => mo2.freq;   
    }   

    // noteOn mo1 and mo2
    if (msg.data1==144 && msg.data2 == X.mononote)
    {
       msg.data3/127.0 => mo1.noteOn;
       msg.data3/127.0 => mo2.noteOn;
    }

    // noteOff mo1 and mo2
    if (msg.data1==128 && X.mononote == 0)
    {
       1 => mo1.noteOff;
       1 => mo2.noteOff; 
    }

    // keyOn e1 and e2
    if (msg.data1==144 && msg.data2 == X.mononote)
    {
    e1.keyOn();
    e2.keyOn();
    }

    // keyOff e1 and e2
    if (msg.data1==128 && X.mononote == 0)
    {
    e1.keyOff();
    e2.keyOff();
    }

// end if-loop received messages
}


// allow e1 and e2 to ramp down to 0
e1.releaseTime() => now;
e2.releaseTime() => now;


// return infinite time-loop
}

Nu ook een "Moog-filter" toegevoegd. Luister en huiver :D:




Iemand een idee met welke instellingen hier nog niet kloppen?
 
Vond het ook wel grappig, soort van kikker gekwaak. :P

Maar hoe kan ik dat meer op een Minimoog laten lijken?
 
Een verbeterde versie:

Code:
// open MIDI channel to Q25
MidiIn min;
MidiMsg msg;
min.open(1);


//-------------------------------------------------------------

// define class X
class X {static int mononote;}
// initialize mononote
0 => X.mononote;


//-------------------------------------------------------------

// set parameters

// Moog filter
0.67 => float Q;
1.0 => float SweepRate;
20.0 => float Speed;
0.0 => float Depth;
0.4 => float VibFreq;
0.01 => float VibGain;
1.0 => float Volume;


//envelope
// attack
1::ms => dur A;
// decay
1::ms => dur D;
// sustain
0.9 => float S;
// release
30::ms => dur R;


// reverb mix
0.2 => float revmixmo;
0.3 => float revmixs;


// detune factor d
0.01 => float dmo;
0.013 => float ds;


// general gain
0.7 => float gainmo;
0.25 => float gains;


//-------------------------------------------------------------

// patches
Moog mo1  => ADSR e1 => NRev reverb1 => dac;
Moog mo2  => ADSR e2 => NRev reverb2 => dac;
SawOsc s1 => ADSR e3 => NRev reverb3 => dac;
SqrOsc s2 => ADSR e4 => NRev reverb4 => dac;

//-------------------------------------------------------------

// initialize mo1
Q => mo1.filterQ;
SweepRate => mo1.filterSweepRate;
Speed => mo1.lfoSpeed;
Depth => mo1.lfoDepth;
VibFreq => mo1.vibratoFreq;
VibGain => mo1.vibratoGain;
Volume => mo1.volume;

// initialize mo2
Q => mo2.filterQ;
SweepRate => mo2.filterSweepRate;
Speed => mo2.lfoSpeed;
Depth => mo2.lfoDepth;
VibFreq => mo2.vibratoFreq;
VibGain => mo2.vibratoGain;
Volume => mo2.volume;


// initialize envelopes e1, e2, e3, e4
e1.set( 0::second, 0::second, 1, R );
e2.set( 0::second, 0::second, 1, R );
e3.set( A, D, S, R );
e4.set( A, D, S, R );


// initialize reverb mix's
revmixmo => reverb1.mix;
revmixmo => reverb2.mix;
revmixs => reverb3.mix;
revmixs => reverb4.mix;


//-------------------------------------------------------------

// infinite time-loop
while( true )
{


//receive MIDI messages
min => now;

// if-loop received messages
if( min.recv(msg) )
{

    // monophonic note
    if (msg.data1 == 144 && X.mononote == 0) {msg.data2 => X.mononote;}
    if (msg.data1 == 128 && msg.data2 == X.mononote) {0 => X.mononote;}



    if (msg.data1==144 && msg.data2 == X.mononote)
    {

       // set frequencies mo1, mo2; and s1,s2
       Std.mtof(msg.data2) => mo1.freq;
       Std.mtof(msg.data2) * (1 + dmo) => mo2.freq;  
       Std.mtof(msg.data2) => s1.freq;
       Std.mtof(msg.data2) * (1 + ds) => s2.freq;  
   

       // set velocities mo1, mo2; and s1, s2
       gainmo*(msg.data3/127.0) => mo1.noteOn;
       gainmo*(msg.data3/127.0) => mo2.noteOn;
       gains*(msg.data3/127.0) => s1.gain;
       gains*(msg.data3/127.0) => s2.gain;  
   
   
       // keyOn e1, e2, e3, e4
       e1.keyOn();
       e2.keyOn();
       e3.keyOn();
       e4.keyOn();
       
       
    }
   


    if (msg.data1==128 && X.mononote == 0)
    {

       // noteOff mo1 and mo2; keyOff e1, e2, e3, e4
       1 => mo1.noteOff;
       1 => mo2.noteOff;
       e1.keyOff();
       e2.keyOff();
       e3.keyOff();
       e4.keyOff();    
       
       
    }

   
// end if-loop received messages
}


// allow e1, e2, e3, e4 to ramp down to 0
e1.releaseTime() => now;
e2.releaseTime() => now;


// return infinite time-loop
}

En hier het geluid van dit progje (let a.u.b. niet op de speeltechniek want ik kan geen keyboard bespelen en doe maar wat):

 
Laatst gewijzigd:
Na mijn upgrade naar Linux Mint 20.3 krijg ik ChucK en miniAudicle niet meer aan de praat. Wordt Chuck nog wel actief ondersteund? Misschien moet ik het maar gewoon bij Csound, PureData en Faust houden, daar is op zich al genoeg mee te beleven.
 
De Windows versie doet het onder Wine kennelijk nog wel. Nu voorlopig daarmee verder.
 
Back
Top