Digital Music Programming II: Assignment 1




For this assignment, you will create a Max object, called voice, which will keep track of note-offs for a monophonic voice.

The object will remember the last note that was sent through it. When a new note is sent into the object, it will check to see if the last note needs to be turned off. If so, it will send a note off for the last note that came in and then it will send the new note message.

Below is a picture of the object you will write. There are two inputs and two outputs detailed in the table below.

Inputs:
  1. A MIDI note number to played.
  2. An attack velocity for the note.
Outputs:
  1. The MIDI note number that came from the input (and possibly the previous note number to turn off).
  2. The attack velocity that came from the input (and possiblly a zero velocity to turn off the previous note.

As an example of how the voice object will work, consider the following example. First play the note C on a synthesizer by going through the object to noteout. Next, play the note D

Other things to consider when implementing the voice object:

  1. If the last note message sent out was a note-off, then the voice object will not send an additional note-off message.

  2. Optionally, have the voice object accept bang messages which will turn off the current note in memory.

  3. Extra Credit: Have the object respond to the "off" message which will turn off the current note it has in memory.

  4. Extra Credit: Add an inlet and outlet for MIDI channel number to keep track of voices which change to different channels.

Code Template

Either write your own program, or fill in the sections in the following program shell:


//
// Programmer:    YOUR NAME HERE
// Filename:      voice.c
// Syntax:        C; Max4/MSP2 External Object; CodeWarrior 6.0
// OS:	          Mac OS 9; PPC
//
// Description:   Monophonic voice manager.
//

#include "ext.h"

typedef struct {
   t_object maxData;          // Max/MSP data, MUST come first in struct
   long     curkey;           // Current note being played
   long     curvel;           // Current velocity of note being played
   long     invel;            // velocity input value (temp storage)
   void*    outputKeyNumber;  // output bang function pointer
   void*    outputVelocity;   // output bang function pointer
} MyObject;

void* objectdata = NULL;

// function declarations:
void*  create_object    (void);
void   InputBang        (MyObject* mo);
void   InputKeyNumber   (MyObject* mo, long value);
void   InputVelocity    (MyObject* mo, long value);


/////////////////////////////////////////////////////////////////////////
//
// Initialization functions
//

//////////////////////////////
//
// main -- called once when the object is created in a patcher window.
//

void main(void) {
   setup((t_messlist**)&objectdata, (method)create_object, NULL, 
      sizeof(MyObject), NULL, A_DEFLONG, A_NOTHING);
   addbang((method)InputBang);
   addint ((method)InputKeyNumber);
   addinx ((method)InputVelocity, 1);
}



//////////////////////////////
//
// create_object -- create the data storage for the mydiff object and
//     and setup input 1.
//

void* create_object(void) {
   MyObject *mo;
   mo = (MyObject*)newobject(objectdata);
   mo->outputVelocity  = intout(mo);      // create outlet 2
   mo->outputKeyNumber = intout(mo);      // create outlet 1
   intin(mo, 1);                          // create inlet 2
   return mo;
}


/////////////////////////////////////////////////////////////////////////
//
// Behavior functions
//


//////////////////////////////
//
// InputBang -- behavior of the object when a "bang" message is received.
//    Turn off the current note if it is playing (has a non-zero
//    velocity).
//

void InputBang(MyObject* mo) {
/////// ADD CODE HERE (OPTIONAL) ///////
}



//////////////////////////////
//
// InputKeyNumber -- what to do when a new key number comes in.
//   When a new note number comes into the object do these things:
//    (1) check to see if the last note should be turned off.
//    (2) if current note is still on, then send a note off message
//        to the outlets.
//    (3) send the input note to the outlets.
//    (4) store the input note into the current note memory.
//

void InputKeyNumber(MyObject* mo, long value) {
/////// ADD CODE HERE ///////
}



//////////////////////////////
//
// InputVelocity -- what to do when a new velocity value comes in.
//   Store the velocity in a temporary location, but don't erase the last
//   velocity that was sent out with the last note out.
//

void InputVelocity(MyObject* mo, long value) {
/////// ADD CODE HERE ///////
}





Email me the source code for your program when it is finished. After you have compiled it and tested it in Max.