Music 220A Final – Song remix

Brian Yoo

For this final, I wanted to use ChucK to somehow help me create a hip-hop composition, that I would eventually want to rap over. Although I came in with no musical ability/experience with ChucK, I found the task to be pretty fun. At first, I went through the Stk library to see if there were any sounds I liked. I played with the different sounds for a bit, and none of them really suited my taste. It was around then that I decided to use ChucK to help me create a beat, not necessarily by using sounds created by the synths, but by using samples. For the past few months, there was a song that in the back of my mind I thought would sound cool as a hip hop beat, “Nothing to Worry About” by Peter Bjorn and John. This is the song below:

http://www.youtube.com/watch?v=GwcaQ3qJ88U

In fact, this song recently was sampled by a hip hop artist named Wale, but the song was basically the same as the original, a four bar loop lifted directly out of the song. I decided that instead of doing something like that to the track, I would remix the song, by slicing out short samples, for example, the kicks, snares, claps, sound effects, etc. and make my own composition out of it. I used Audacity to make the slices, and exported those wav files. Then, I made use of ChucK’s SndBuf class, which allows you to read in and play samples. After chopping the beat up, I loaded the tracks into ChucK, by creating an array of SndBuf’s, assigning each sample to an instance of SndBuf. However, I needed some way of actually organizing the different samples. I also wanted some way for me to be able to loop the song, while letting me control the structure of the song in live performance. I decided to organize the musical data similar to how an MPC does its samples. I created a ‘track’ class and a ‘sequence’ class. The sequence is a determinate number of bars (in this case 4) going at a set speed (bpm). A sequence holds an array of tracks. Tracks each have an array of track information, that is when the track should trigger the sample. This is organized such that a non-zero value in the 2-d array specified when/what sample to play.  Each track can trigger multiple samples simultaneously. The sequence loops through each track, and each array value in each track’s information array, loading up the samples to be played at each step interval (here a 16th note).

After coding in the values for each track in the song, I was able to get ChucK to play my remix. However, I wanted to add a little more functionality to allow me to control which tracks were playing at any given time. I then chose 16 keys on the keyboard to represent the first 16 tracks in any given sequence. In the sequence function, there is a keyboard listener that is sporked when the user starts playing the sequence. This allows the user to choose which tracks are being played in real-time. I would also like to add more functionality to this in the future, including a GUI and a drum-machine capability that saves keystrokes, so I don’t have to hardcode in all the sample triggering information manually.

Chuck file and samples

-for performance mode, open file in command prompt

Here is the code below:

//Initialize basic sequence info.

95.2 => float BPM;

4 => int numberOfBars;

4 => int beatsPerBar;

beatsPerBar * numberOfBars * 60 / BPM => float lengthOfSequence; //seconds

 

//determines quantization

16 => int stepsPerBar; //16th notes

stepsPerBar * numberOfBars => int stepsPerSequence;

 

14 => int numberOfSamples;

string sampleNames[numberOfSamples];

//put in file names

"PBJ7.wav" => sampleNames[0];

"PBJ12.wav" => sampleNames[1];

"PBJ13.wav" => sampleNames[2];

"PBJ14.wav" => sampleNames[3];

"PBJclic4.wav" => sampleNames[4];

"PBJdrum11.wav" => sampleNames[5];

"PBJdrum2.wav" => sampleNames[6];

"PBJdrum3.wav" => sampleNames[7];

"PBJkick20.wav" => sampleNames[8];

"PBJkick21.wav" => sampleNames[9];

"PBJmain7.wav" => sampleNames[10];

"PBJratt1.wav" => sampleNames[11];

"PBJsnare.wav" => sampleNames[12];

"PBJratt2.wav" => sampleNames[13];

 

//creates array of SndBuf, reads in the filename to initialize

SndBuf buf[numberOfSamples];

for(0 => int i; i < numberOfSamples; i++)

{

    buf[i] => Gain g => dac;

    sampleNames[i] => buf[i].read;

    0.5 => g.gain;

}

 

//encode the information for my song

float chorusInfo[numberOfSamples][stepsPerSequence];

1 => chorusInfo[3][0];

1 => chorusInfo[3][16];

1 => chorusInfo[3][32];

1 => chorusInfo[3][48];

track chorusTrack;

chorusInfo @=> chorusTrack.trackInformation;

 

float chimeInfo[numberOfSamples][stepsPerSequence];

1 => chimeInfo[0][8];

1 => chimeInfo[0][8 + 16];

1 => chimeInfo[0][8 + 32];

1 => chimeInfo[0][8 + 48];

track chimeTrack;

chimeInfo @=> chimeTrack.trackInformation;

 

float drum1Info[numberOfSamples][stepsPerSequence];

1 => drum1Info[8][0];

1 => drum1Info[8][3];

1 => drum1Info[8][4];

1 => drum1Info[8][6];

1 => drum1Info[8][10];

1 => drum1Info[8][14];

1 => drum1Info[8][0 + 16];

1 => drum1Info[8][3 + 16];

1 => drum1Info[8][4 + 16];

1 => drum1Info[8][6 + 16];

1 => drum1Info[8][10 + 16];

1 => drum1Info[8][14 + 16];

track drumTrack1;

drum1Info @=> drumTrack1.trackInformation;

 

float drum2Info[numberOfSamples][stepsPerSequence];

1.2 => drum2Info[9][0 + 32];

1.2 => drum2Info[9][3 + 32];

1.2 => drum2Info[9][4 + 32];

1.2 => drum2Info[9][6 + 32];

1.2 => drum2Info[9][10 + 32];

1.2 => drum2Info[9][14 + 32];

1.2 => drum2Info[9][0 + 48];

1.2 => drum2Info[9][3 + 48];

1.2 => drum2Info[9][4 + 48];

1.2 => drum2Info[9][6 + 48];

1.2 => drum2Info[9][10 + 48];

1.2 => drum2Info[9][14 + 48];

track drumTrack2;

drum2Info @=> drumTrack2.trackInformation;

 

float drum3Info[numberOfSamples][stepsPerSequence];

1 => drum3Info[5][10];

1 => drum3Info[5][10 + 16];

1 => drum3Info[5][10 + 32];

1 => drum3Info[5][10 + 48];

track drumTrack3;

drum3Info @=> drumTrack3.trackInformation;

 

float drum4Info[numberOfSamples][stepsPerSequence];

1 => drum4Info[6][12];

1 => drum4Info[6][12 + 16];

1 => drum4Info[6][12 + 32];

1 => drum4Info[6][12 + 48];

track drumTrack4;

drum4Info @=> drumTrack4.trackInformation;

 

float drumSnareInfo[numberOfSamples][stepsPerSequence];

1 => drumSnareInfo [12][4];

1 => drumSnareInfo [12][12];

1 => drumSnareInfo [12][4 + 16];

1 => drumSnareInfo [12][12 + 16];

1 => drumSnareInfo [12][4 + 32];

1 => drumSnareInfo [12][12 + 32];

1 => drumSnareInfo [12][4 + 48];

1 => drumSnareInfo [12][10 + 48];

1 => drumSnareInfo [12][12 + 48];

1 => drumSnareInfo [12][14 + 48];

1 => drumSnareInfo [12][15 + 48];

track drumSnareTrack;

drumSnareInfo @=> drumSnareTrack.trackInformation;

 

float rattleInfo[numberOfSamples][stepsPerSequence];

1 => rattleInfo[13][2];

1 => rattleInfo[11][4];

1 => rattleInfo[11][5];

1 => rattleInfo[13][8];

1 => rattleInfo[13][10];

1 => rattleInfo[11][12];

1 => rattleInfo[11][13];

1 => rattleInfo[11][14];

 

1 => rattleInfo[13][2 + 16];

1 => rattleInfo[11][4 + 16];

1 => rattleInfo[11][5 + 16];

1 => rattleInfo[13][8 + 16];

1 => rattleInfo[13][10 + 16];

1 => rattleInfo[11][12 + 16];

1 => rattleInfo[11][13 + 16];

1 => rattleInfo[11][14 + 16];

 

1 => rattleInfo[13][2 + 32];

1 => rattleInfo[11][4 + 32];

1 => rattleInfo[11][5 + 32];

1 => rattleInfo[13][8 + 32];

1 => rattleInfo[13][10 + 32];

1 => rattleInfo[11][12 + 32];

1 => rattleInfo[11][13 + 32];

1 => rattleInfo[11][14 + 32];

 

1 => rattleInfo[13][2 + 48];

1 => rattleInfo[11][4 + 48];

1 => rattleInfo[11][5 + 48];

1 => rattleInfo[13][8 + 48];

1 => rattleInfo[13][10 + 48];

1 => rattleInfo[11][12 + 48];

1 => rattleInfo[11][13 + 48];

1 => rattleInfo[11][14 + 48];

track rattleTrack;

rattleInfo @=> rattleTrack.trackInformation;

 

 

float clickInfo[numberOfSamples][stepsPerSequence];

1 => clickInfo[4][2];

1 => clickInfo[4][6];

1 => clickInfo[4][10];

1 => clickInfo[4][14];

track clickTrack;

clickInfo @=> clickTrack.trackInformation;

 

float originalSampleInfo[numberOfSamples][stepsPerSequence];

1 => originalSampleInfo[10][0];

track originalSampleTrack;

originalSampleInfo @=> originalSampleTrack.trackInformation;

 

//put my tracks into an array of tracks

track songTracks[10];

drumTrack1 @=> songTracks[0];

drumTrack2 @=> songTracks[1];

drumTrack3 @=> songTracks[2];

drumTrack4 @=> songTracks[3];

drumSnareTrack @=> songTracks[4]; //

rattleTrack @=> songTracks[5]; //

clickTrack @=> songTracks[6];

chimeTrack @=> songTracks[7];

chorusTrack @=> songTracks[8];

originalSampleTrack @=> songTracks[9]; //

 

 

//create sequence for my song

sequence song;

stepsPerSequence => song.stepsPerSequence;

lengthOfSequence / stepsPerSequence => song.step_length;

songTracks.cap() => song.numberOfTracks;

songTracks @=> song.trackArray;

buf @=> song.samples;

<<<"READY">>>;

song.performancePlay();

 

/*

//ORIGINAL SAMPLE

float originalSample[numberOfSamples][stepsPerSequence];

1 => originalSample[10][0];

track originalSampleTrack;

originalSample @=> originalSampleTrack.trackInformation;

track originalSongTracks[1];

originalSampleTrack @=> originalSongTracks[0];

 

sequence originalSong;

stepsPerSequence => originalSong.stepsPerSequence;

lengthOfSequence / stepsPerSequence => originalSong.step_length;

numberOfSamples => originalSong.numberOfTracks;

originalSongTracks @=> originalSong.trackArray;

buf @=> originalSong.samples;

originalSong.play();

*/

 

class track

{

    1 => int trackOn;

    //trackInformation[sample corresponding to sndbuf array][which point in the song (step #)];

    float trackInformation[][];

 

    fun void stopTrack()

    {

        0 => trackOn;

    }

    fun void startTrack()

    {

        1 => trackOn;

    }

    fun void toggle()

    {

        if(trackOn)

        {

            0 => trackOn;

        }

        else

        {

            1 => trackOn;

        }

    }

   

}

 

class sequence

{

 

     float step_length;

     int stepsPerSequence;

     int numberOfTracks;

 

     Event new_step;

                 1 => int on;

   

     SndBuf @ samples[];

   

     track trackArray[];

   

    fun void play()

    {

        spork ~ KeyBoardListener();

        while(on){

            playTracks();

        }

    }

   

    fun void performancePlay()

    {

        spork ~ KeyBoardListener();

        turnOffAllTracks();

        while(on){

            playTracks();

        }

    }

   

    fun void KeyBoardListener()

    {

        // computer keyboard input via terminal

        KBHit kb;

 

        while( true )

        {

            // wait on event

            kb => now;

       

            // loop through 1 or more keys

            while( kb.more() )

            {

                // get key

                kb.getchar() => int c;

               

                if( c == 122 && numberOfTracks > 0) //z

                    trackArray[0].toggle();

                else if( c == 120 && numberOfTracks > 1) //x

                    trackArray[1].toggle();

                else if(c == 99 && numberOfTracks > 2) //c

                    trackArray[2].toggle();

                else if(c == 118 && numberOfTracks > 3) //v

                    trackArray[3].toggle();

                else if(c == 97 && numberOfTracks > 4) //a

                    trackArray[4].toggle();

                else if(c == 115 && numberOfTracks > 5)//s

                    trackArray[5].toggle();

                else if(c == 100 && numberOfTracks > 6)//d

                    trackArray[6].toggle();

                else if(c == 102 && numberOfTracks > 7)//f

                    trackArray[7].toggle();

                else if(c == 113 && numberOfTracks > 8)//q

                    trackArray[8].toggle();

                else if(c == 119 && numberOfTracks > 9)//w

                    trackArray[9].toggle();

                else if(c == 101 && numberOfTracks > 10)//e

                    trackArray[10].toggle();

                else if(c == 114 && numberOfTracks > 11)//r

                    trackArray[11].toggle();

                else if(c == 49 && numberOfTracks > 12)//1

                    trackArray[12].toggle();

                else if(c == 50 && numberOfTracks > 13)//2

                    trackArray[13].toggle();

                else if(c == 51 && numberOfTracks > 14)//3

                    trackArray[14].toggle();

                else if(c == 52 && numberOfTracks > 15)//4

                    trackArray[15].toggle();

                else if(c == 32){

                    turnOffAllTracks();

                }

               

            }

        }

    }

   

   

    fun void playTracks()

    {

        0 => int i;

        1 => int n;

        for(0 => int step; step < stepsPerSequence; step++)

        {  

            for(0 => int track; track < trackArray.cap(); track++)

            {

                for(0 => int sample;  sample < samples.cap(); sample++)

                {  

                    trackArray[track].trackInformation[sample][step] => float val;

                   

                    

                    if(val != 0 && trackArray[track].trackOn){

                        spork ~ playSample(sample, val);

                    }

                   

                }

               

            }

            new_step.broadcast();

            if(i % 4 == 0){

                <<<n>>>;

                n++;

            }

            i++;

            if(n == 5)

                1 => n;

            step_length::second => now;

        }

       

 

    }

   

    fun void playSample(int sample, float val)

    {

        new_step => now;

        0 => samples[sample].pos;

        val => samples[sample].gain;

    }

   

    fun void turnOffAllTracks()

    {

        for(0 => int i; i < numberOfTracks; i++)

        {

             trackArray[i].stopTrack();

        }

    }

   

    fun void turnOffTracks(int off[])

    {

        for(0 => int i; i < off.cap(); i++)

        {

            if(off[i] < numberOfTracks)

                trackArray[off[i]].stopTrack();

        }

    }

    

    fun void turnOnTracks(int on[])

    {

        for(0 => int i; i < on.cap(); i++)

        {

            if(on[i] < numberOfTracks)

                trackArray[on[i]].startTrack();

        }

    }

               

    fun void stopSequence()

    {

        0 => on;

    }

   

}