Hi
I'm wrestling with some mostly conceptual problems that I'd like to get
some feedback on. I hope some of you people take the time to discuss
this with me. It's not about chuck bugs, it's not about
how-do-i-use-this-chuck-construct, it's about how I get my brain dead
brain around a design problem for something that I really would like to
do in chuck.
Long story short: I'd like to be able to record sniplets of midi into
chuck and grow it (by performing various transformations). For this to
work my instruments need to work with noteon/noteoff, since that's what
gonna happen with midiin.
Currently I have a really simple, well working way of doing instruments
by making each instrument a static member function of an Instruments
class. Each function (might) take a length parameter indicating how long
the instrument should sound before going into it's release phase.
From a coding point of view I prefer my current instrument definition,
but if it should work with midi I need to make instruments work with
noteon/off. I'd like to be able to use the same instrument from both
code and midi. Another issue with midi is that it should be polyphonic.
First question: How are you guys handling this? Anyone recorded midi
sniplets into chuck for processing?
Attached is an (bit messy) attempt at this design. It's suffering from
the CPU-eating problem that Ge advised about a couple of days ago
(could/should be fixed, don't care at this point). There's currently
also no support for "length-driven" use, but that would be easy, simply
by having a play function that calls noteOn(), waits a few::ms and calls
noteOff(). The reason for the four classes (monoInstrument,
polyInstrument, mono_sine and poly_sine) is that I'd like to have as
much of the book keeping as possible in the super classes, so basically
only noise making is happening in sub classes. Actually I'd like to only
have to write the mono_sine (or similar for other instruments) class.
Second question: Would it be possible to get rid of poly_sine, or at
least the repetitive (for other instruments) code in functions on(),
off() and kill()? Main reason it's there is that the voices are not
known in any of the other classes. Could that be changed?
Supposed I actually get this thing going, I'm gonna set chuck to record
to some data structure, probably an object. This is happening in one
shred. But then I'd like to a) grow (permutate) and b) use this data
structure in other shreds.
Third question: But how is that gonna be possible? The recorded-to
instance is not known outside the scope of the recording shred :-(
Static class? Possible, but inelegant.
Sorry for the loong post.
Any feedback is highly appreciated!
--
peace, love & harmony
Atte
http://www.atte.dk | quartet: http://www.anagrammer.dk
http://www.atte.dk/gps | compositions: http://www.atte.dk/compositions
// ---------------------------------------------------
// ring_element
// ---------------------------------------------------
class ring_element{
int date;
float freq;
}
// ---------------------------------------------------
// ring
// ---------------------------------------------------
class ring{
4 => int size;
1000 => int max_size;
ring_element container[max_size];
int counter;
fun int is_full(){
1 => int result;
for(0=>int i; i result;
size => i;
}
}
return result;
}
fun int remove_oldest(){
1000000 => int min;
-1 => int pos;
for(0=>int i; i min;
i => pos;
}
}
if(pos != -1){
unset(pos);
}
return pos;
}
fun int add(float freq){
10000000 => int min;
int position;
for (0=>int i; i min;
i => position;
}
}
counter++;
counter => container[position].date;
freq => container[position].freq;
return position;
}
fun void unset(int position){
0 => container[position].date;
0 => container[position].freq;
}
fun int freq2voice(float freq){
-1 => int position;
for(0=>int i; i position;
size => i;
}
}
<<<"freq2voice",freq,position>>>;
return position;
}
fun void full_clear(int position){
//<<<"before">>>;
//print();
unset(position);
//<<<"after">>>;
//print();
}
fun void print(){
<<<"------">>>;
for(0 => int i; i>>;
}
<<<"------">>>;
}
}
// ---------------------------------------------------
// monoInstrument
// ---------------------------------------------------
public class monoInstrument {
.4 => float volume;
ADSR env;
env =< dac;
0 => env.gain;
.001 => float attackTime;
.01 => float decayTime;
1 => float sustainLevel;
.01 => float releaseTime;
attackTime => env.attackTime;
decayTime => env.decayTime;
sustainLevel => env.sustainLevel;
releaseTime => env.releaseTime;
0 => env.gain;
1 => env.keyOff;
fun void setFreq(float freq){}
fun void noteOn(float freq, float dynamic){
env =< dac;
attackTime => env.attackTime;
decayTime => env.decayTime;
sustainLevel => env.sustainLevel;
releaseTime => env.releaseTime;
volume * dynamic => env.gain;
setFreq(freq);
env => dac;
1 => env.keyOn;
}
fun void noteOff(){
1 => env.keyOff;
while(env.state() != 4){
2::ms => now;
}
0 => env.gain;
env =< dac;
1::samp => now;
}
fun void hardOff(){
1 => env.keyOff;
0 => env.gain;
env =< dac;
}
fun void play(float freq, dur length, float dynamic){
noteOn(freq,dynamic);
length => now;
noteOff();
}
}
// ---------------------------------------------------
// polyInstrument
// ---------------------------------------------------
class polyInstrument {
6 => int polyphony;
ring pressed;
polyphony => pressed.size;
fun void on(int voice, float freq, float dynamic){
}
fun void off(int voice){
}
fun void kill(int voice){
}
fun void noteOn(float freq, float dynamic){
int voice;
if(pressed.is_full()){
pressed.remove_oldest() => voice;
kill(voice);
}
pressed.add(freq) => voice;
on(voice, freq, dynamic);
pressed.print();
}
fun void noteOff(float freq){
pressed.freq2voice(freq) => int voice;
if(voice != -1){
off(voice);
}
else {
<<<"oops, couldn't find match for",freq>>>;
}
pressed.full_clear(voice);
}
}
// ---------------------------------------------------
// mono_sine
// ---------------------------------------------------
class mono_sine extends monoInstrument{
sinosc osc => env =< dac;
//.1 => decayTime;
//0 => sustainLevel;
//.1 => decayTime;
2.6 => releaseTime;
fun void setFreq(float freq){
freq => osc.freq;
}
}
fun void sine(float freq){
sinosc osc => ADSR env => dac;
.001 => env.attackTime;
.01 => env.decayTime;
1 => env.sustainLevel;
.01 => env.releaseTime;
1 => env.keyOn;
10::ms => now;
freq => osc.freq;
1 => env.keyOff;
while(env.state() != 4){
1::ms => now;
}
osc =< env =< dac;
}
// ---------------------------------------------------
// poly_sine
// ---------------------------------------------------
class poly_sine extends polyInstrument {
//2 => polyphony;
polyphony => pressed.size;
mono_sine voices[polyphony];
fun void on(int voice, float freq, float dynamic){
<<<"on",voice,freq>>>;
voices[voice].noteOn(freq,dynamic);
}
fun void off(int voice){
<<<"off",voice>>>;
voices[voice].noteOff();
while(voices[voice].env.state() != 4){
2::ms => now;
}
1::samp => now;
}
fun void kill(int voice){
<<<"kill",voice>>>;
voices[voice].hardOff();
}
}
400::ms => dur length;
[0,3,5,7,10] @=> int notes[];
float freq;
poly_sine s;
while(true){
std.rand2(220,450) => freq;
spork ~ s.noteOn(freq,std.rand2f(.6,1));
10::ms => now;
spork ~ s.noteOff(freq);
300::ms => now;
}