Basic Electroacoustics II: Music-Making Systems

Music G6602Y
TueThu 3:10-5:00pm
Spring 2008
Professor: Douglas Repetto [douglas at music columbia edu]
TA: Victor Adan [vga2102 at columbia edu]
Our Motto: "Why and how."
syllabus | lectures




February 13

Samples samples samples!

It's pretty easy to deal with samples in Minim. There are three main sample playback classes that we'll look at today: AudioSnippet, AudioSample, AudioPlayer.

AudioSnippet is good for very simple playback of short sounds. They're loaded into memory, so there's some limit to how many you can load (I seem to have gotten stuck at 32). You just the sound, cue it up, and play it. Note that "1.wav" is a soundfile in a folder called "data" that I made in the sketch's folder. processing will automatically find sound files there. You can also pass a complete path name if you need to be more explicit.

import ddf.minim.*;

AudioSnippet snippet;

void setup()
{
  //always do this!
  Minim.start(this);

  //load sample
  snippet = Minim.loadSnippet("1.wav");
  
  //we'll play once per second
  frameRate(1);
}


void draw()
{
  //this resets the sample back to the beginning
  //you can also use cue to start at some arbitrary point
  //in the sample
  snippet.cue(0);

  //play it!
  snippet.play();
}


//always do this, including a .close() for each output object you create
void stop()
{
    snippet.close();
    super.stop();
}

++++++++++++++++++++++++++++++++++++++++++++++++++

As always, it's more flexible if you use variables/arrays:

import ddf.minim.*;

//let's use several snippets
//we'll also add a looping option to help create a big mess!

int numSnippets = 4;
AudioSnippet snippets[] = new AudioSnippet[numSnippets];

int frameNum = 0;

boolean looping = false;

void setup()
{
  //always do this!
  Minim.start(this);

  //load samples
  loadSnippets(numSnippets);
  
  //we'll play once per second
  frameRate(1);
}

void loadSnippets(int howMany)
{
  for (int i = 0; i < howMany; i++)
  {
    //we'll construct the filenames on the fly...
    //using (i + 1) because our first filename is 1.wav, not 0.wav
    println("loading snippit: " + (i + 1) + ".wav");
    snippets[i] = Minim.loadSnippet((i + 1) + ".wav"); 
  }
}

void draw()
{
  //this will cycle through our snippets as frameNum increases eternally
  int snippetToPlay = frameNum % numSnippets;
  
  println("doing snippet: " + snippetToPlay);
  
  if (looping)
  {
    //if we're already looping then we don't need to do anything!
    if (!snippets[snippetToPlay].isLooping())
    {
      //set our sample back to beginning
      snippets[snippetToPlay].cue(0);
      //loop until the end of the world
      snippets[snippetToPlay].loop();
    }
  }
  else
  {
    //set our sample back to beginning
    snippets[snippetToPlay].cue(0);
    //play once
    snippets[snippetToPlay].play();
  }
  frameNum++;
}

void mousePressed() 
{
  //click to toggle looping on and off
  looping = !looping;
}

//always do this, including a .close() for each output object you create
void stop()
{
  for (int i = 0; i < numSnippets; i++)
    snippets[i].close();
  super.stop();
}

+++++++++++++++++++++++++++++++++++++++++

If you're doing more complex playback of short samples then you might want to look at AudioSample instead. One important thing that AudioSample gives you is the ability to play multiple copies of the same sound at one time. AudioSnippet will restart the sample if you play it again before it's finished. AudioSample will simply play another copy along with the first.

import ddf.minim.*;

//okay, let's use AudioSamples this time
//we'll put a grid on the screen that lets you trigger
//any of the four sounds repeatedly


String filenames[] = {"counting.wav", "letters.wav", "woof.wav", "meow.wav"};
int numSnippets = filenames.length;
AudioSample snippets[] = new AudioSample[numSnippets];

int frameNum = 0;

void setup()
{
  //we'll make a grid with squares 100x100 pixels for each sample
  size(numSnippets/2 * 100, 200);
  //always do this!
  Minim.start(this);

  //load samples
  loadSnippets(numSnippets);

  frameRate(10);

  //let's just draw the screen once since it doesn't change.
  firstDraw();
}

void loadSnippets(int howMany)
{
  for (int i = 0; i < numSnippets; i++)
  {
    snippets[i] = Minim.loadSample(filenames[i]); 
  }
}

void firstDraw()
{
  int c = 0;

  for (int i = 0; i < numSnippets/2; i++)
  {
    fill(c);
    rect(i * 100, 0, 100, 100);
    if (c == 0)
      c = 255;
    else
      c = 0;

    fill(c);
    rect(i * 100, 100, 100, 100);  
  }  
}

void draw()
{
  //we only start a new sound if the mouse button is pressed
  if (mousePressed == false)
    return;
  
  int squareNum = whichSquare();
  println("we're in square: " + squareNum); 
  snippets[squareNum].trigger();
}

//figure out which square the mouse is in!
int whichSquare()
{
  //we'll use -1 to indicate that we haven't found the square yet
  int squareNum = -1;

  //println("x: " + mouseX + " y: " + mouseY);

  for (int i = 0; i < numSnippets; i++)
  {
    int squareLeft = 0;
    int squareRight = 0;
    int squareTop = 0;
    int squareBottom = 0;
    
    if (i % 2 == 0)
    {
      squareLeft = i/2 * 100;
      squareRight = squareLeft + 100;
      squareTop = 0;
      squareBottom = 100;
    }
    if (i % 2 == 1)
    {
      squareLeft = i/2 * 100;
      squareRight = squareLeft + 100;
      squareTop = 100;
      squareBottom = 200;      
    }

    //println("i: " + i + " L: " + squareLeft + " R: " + squareRight + " T: " + squareTop + " B: " + squareBottom);
    
    if (mouseX >= squareLeft && mouseX <= squareRight)
    {
      if (mouseY >= squareTop && mouseY <= squareBottom)
        squareNum = i;
    }
  }

  return squareNum;
}

//always do this, including a .close() for each output object you create
void stop()
{
  for (int i = 0; i < numSnippets; i++)
    snippets[i].close();
  super.stop();
}

+++++++++++++++++++++++++++++

Longer samples should be played from disc rather than loaded into memory (although exactly what counts as a "long" sample really depends on how much RAM you have to play with...) Minim works well with different kinds of files, here we'll use an mp3, but we'll treat it the same way we would a .wav or .aiff. We'll run our sound through a filter too, YOWZA, NOW THAT'S MUSIC!!!


//notice we have an extra import!
import ddf.minim.*;
import ddf.minim.effects.*;

//let's play back a longer file with AudioPlayer and run it through a filter,
//the parameters of which are tweaked by mouse position
AudioPlayer player;
BandPass filter;

byte c = 0;

void setup()
{
  size(500, 500);
  //always do this!
  Minim.start(this);

  //load the soundfile
  player = Minim.loadFile("mann.mp3");
  //start it looping
  player.loop();

  //create the bandpass filter with:
  //300Hz center freq
  //20Hz bandwidth
  filter = new BandPass(300, 20, player.sampleRate());

  //add it to the player so that the audio from the player passes
  //through the filter
  player.addEffect(filter);
  
  //reasonable update rate so that our changes in freq/bw are smooth
  frameRate(10);

  //let's just draw the screen once since it doesn't change.
  firstDraw();
}


void firstDraw()
{
  background(0);
}

void draw()
{
  //+1 is to avoid divide by zero errors!
  int divisor = int(random(width/5)) + 1;
  int xIncr = width/divisor;
  int yIncr = height/divisor;
  
  for (int i = 0; i < 10; i++)
  {
    stroke(c, c, c);
    c++;
    line(i * xIncr, 0, i * xIncr, height);
    line(0, i * yIncr, width, i * yIncr);
  }  
  
  //we'll square mouseX to get better sensitivity in the low end
  int x = mouseX * mouseX;
  int y = mouseY;
  
  //map freq from 60 to 1000 Hz
  //and bandwidth from 50 to 250Hz
  int freq = int(map(x, 0, width * width, 60, 1000));
  int bandwidth = int(map(y, 0, height, 50, 250)); 
  
  filter.setFreq(freq);
  filter.setBandWidth(bandwidth);

  if (mousePressed)
    println("x: " + x + " freq: " + freq + " y: " + y + " bandwidth: " + bandwidth);
}


//always do this, including a .close() for each output object you create
void stop()
{
  player.close();
  super.stop();
}


+++++++++++++++++++++++++++++++++++++

One last example: infinite beets!!!

+++++++++++++++++++++++++++++++++++++

homework

Combine all that we've done so far: waveforms, samples, filters, some sort of algorithmic process for combining them, mouse input, funky drawing. Make a little multi-modal masterpiece. YOU CAN DO IT!!!