Esempio n. 1
0
void MIDIController::poll_loop()
{
	int update_freq = 5; // 5 Hz (200ms)

	std::vector<float> x;

	while(keep_polling){
		microsleep(1000/update_freq);

		if(source.data(x) == false) continue;

		unsigned int d = 8;
		if(x.size() < d) d = x.size();
		unsigned int m = 0;

		for(unsigned int i=0;i<d;i++){
			if(mute[i]) continue; // don't send this controller's value

			int v = (int)(127*x[i]);
			if(v > 127) v = 127;
			else if(v < 0) v = 0;

			if(i < 4){
				// controller values [0x10-0x13]: 0-127
				unsigned int cc = (0x10 + i);
				event[m].message = Pm_Message((0xB0+channel), cc, ((unsigned int)v));
				event[m].timestamp = 0;
				m++;
			}
			else{
				// controller values [0x50-0x53]: 0-127
				unsigned int cc = (0x50+(i-4));
				event[m].message = Pm_Message((0xB0+channel), cc, ((unsigned int)v));
				event[m].timestamp = 0;
				m++;
			}
		}


		if(m > 0){
			pthread_mutex_lock(&portmidi_lock);

			if(Pm_Write(midi, event, m) == pmNoError){
				sending_data = true;
			}
			else{
				sending_data = false;
			}

			pthread_mutex_unlock(&portmidi_lock);
		}
		else{
			sending_data = false;
		}

	}
}
Esempio n. 2
0
/* callback function for PortTime -- computes histogram */
void pt_callback(PtTimestamp timestamp, void *userData)
{
    PtTimestamp difference = timestamp - previous_callback_time - period;
    previous_callback_time = timestamp;

    /* allow 5 seconds for the system to settle down */
    if (timestamp < 5000) return;

    iteration++;
    /* send a note on/off if user requested it */
    if (test_out && (iteration % output_period == 0)) {
        PmEvent buffer[1];
        buffer[0].timestamp = Pt_Time(NULL);
        if (note_on) {
            /* note off */
            buffer[0].message = Pm_Message(0x90, 60, 0);
            note_on = 0;
        } else {
            /* note on */
            buffer[0].message = Pm_Message(0x90, 60, 100);
            note_on = 1;
        }
        Pm_Write(out, buffer, 1);
        iteration = 0;
    }

    /* read all waiting events (if user requested) */
    if (test_in) {
       PmError status;
       PmEvent buffer[1];
       do {
          status = Pm_Poll(in);
          if (status == TRUE) {
              Pm_Read(in,buffer,1);
          }
       } while (status == TRUE);
    }

    if (difference < 0) return; /* ignore when system is "catching up" */

    /* update the histogram */
    if (difference < HIST_LEN) {
        histogram[difference]++;
    } else {
        out_of_range++;
    }

    if (max_latency < difference) max_latency = difference;
}
Esempio n. 3
0
static int WriteMidiData_(CSOUND *csound, void *userData,
                          const unsigned char *mbuf, int nbytes)
{
    int             n, st;
    PmEvent         mev;
    PortMidiStream  *midistream;
    /*
     * Writes to user-defined MIDI output.
     */
    midistream = (PortMidiStream*) userData;
    if (UNLIKELY(nbytes < 1))
      return 0;
    n = 0;
    do {
      //int time = csound->GetCurrentTimeSamples(csound)/csound->GetSr(csound);
      //printf("jitter: %d \n",
      //       Pt_Time(NULL) - (int)(1000*time/csound->GetSr(csound)));
      st = (int)*(mbuf++);
      if (UNLIKELY(st < 0x80)) {
        portMidiErrMsg(csound, Str("invalid MIDI out data"));
        break;
      }
      if (UNLIKELY(st >= 0xF0 && st < 0xF8)) {
        portMidiErrMsg(csound,
                       Str("MIDI out: system message 0x%02X is not supported"),
                       (unsigned int) st);
        break;
      }
      nbytes -= (datbyts[(st - 0x80) >> 4] + 1);
      if (UNLIKELY(nbytes < 0)) {
        portMidiErrMsg(csound, Str("MIDI out: truncated message"));
        break;
      }
      mev.message = (PmMessage) 0;
      mev.timestamp = (PmTimestamp) 0;
      mev.message |= (PmMessage) Pm_Message(st, 0, 0);
      if (datbyts[(st - 0x80) >> 4] > 0)
        mev.message |= (PmMessage) Pm_Message(0, (int)*(mbuf++), 0);
      if (datbyts[(st - 0x80) >> 4] > 1)
        mev.message |= (PmMessage) Pm_Message(0, 0, (int)*(mbuf++));
      if (UNLIKELY(Pm_Write(midistream, &mev, 1L) != pmNoError))
        portMidiErrMsg(csound, Str("MIDI out: error writing message"));
      else {
        n += (datbyts[(st - 0x80) >> 4] + 1);
      }
    } while (nbytes > 0);
    /* return the number of bytes written */
    return n;
}
Esempio n. 4
0
void SonifyNoteOnOff(int p, int v)
{
   if (!sonificationStarted)
      SonifyBeginSonification();
   if (sonMidiStream)
      Pm_WriteShort(sonMidiStream, 0, Pm_Message(0x90, p, v));
}
Esempio n. 5
0
void sendNoteOnOff(int status, const mxArray *prhs[]) {
  int n,N;
  const double *note, *vel;
  int channel = (int) mxGetScalar(prhs[1]);
  
  if (channel < 1 || channel > 16) mexErrMsgTxt("Channel (2nd arg.) must be 1..16");
  --channel;
  
  if (!mxIsDouble(prhs[2]) || !mxIsDouble(prhs[3])) {
    mexErrMsgTxt("3rd and 4th arguments (note number and velocity) must be 'double' arrays");
  }
  N = mxGetNumberOfElements(prhs[2]);
  if (N != mxGetNumberOfElements(prhs[3])) {
    mexErrMsgTxt("3rd and 4th arguments (note number and velocity) must have same number of elements");
  }
  note = mxGetPr(prhs[2]);
  vel = mxGetPr(prhs[3]);
  
  status = (status & 0xF0) | channel;
  
  for (n=0;n<N;n++) {
    PmMessage msg;
    PmError err;
    
    msg = Pm_Message(status, (int) note[n], (int) vel[n]);
    /* latency=0 => send asap */
    err = Pm_WriteShort(outStream, 0, msg);
    if (err!=pmNoError) reportPmError(err);
  }
}
Esempio n. 6
0
void
midibus::continue_from( long a_tick )
{

    /* tell the device that we are going to start at a certain position */
    long pp16th = (c_ppqn / 4);

    long leftover = ( a_tick % pp16th );
    long beats = ( a_tick / pp16th );

    long starting_tick = a_tick - leftover;

    /* was there anything left?, then wait for next beat (16th note) to start clocking */
    if ( leftover > 0)
    {
        starting_tick += pp16th;
    }
    //printf ( "continue_from leftover[%ld] starting_tick[%ld]\n", leftover, starting_tick );

    m_lasttick = starting_tick - 1;

    if ( m_clock_type != e_clock_off )
    {

        PmEvent event;
        event.timestamp = 0;
        event.message = Pm_Message( EVENT_MIDI_CONTINUE, 0,0 );
        Pm_Write( m_pms, &event, 1 );
        event.message = Pm_Message( EVENT_MIDI_SONG_POS, (beats & 0x3F80 >> 7), (beats & 0x7F) );
        Pm_Write( m_pms, &event, 1 );
    }
void TestPmEventParser::programChange()
{
  uint8_t input[] = {
    0xc0, 0x7f, /* Program Change */
    0xc1, 0x01, /* Program Change */
  };
  PmEventParser parser;
  PmEvent event;

  parser.feed(input, sizeof(input));

  QVERIFY(parser.next(&event));
  QVERIFY(event.message == Pm_Message(0xc0, 0x7f, 0x00));
  QVERIFY(parser.next(&event));
  QVERIFY(event.message == Pm_Message(0xc1, 0x01, 0x00));
  QVERIFY(!parser.next(&event));
}
Esempio n. 8
0
void
pm_pressout(Server *self, int value, int chan, long timestamp)
{
    int i, curtime;
    PmEvent buffer[1];

    PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;

    curtime = Pt_Time();
    buffer[0].timestamp = curtime + timestamp;
    if (chan == 0)
        buffer[0].message = Pm_Message(0xD0, value, 0);
    else
        buffer[0].message = Pm_Message(0xD0 | (chan - 1), value, 0);
    for (i=0; i<self->midiout_count; i++) {
        Pm_Write(be_data->midiout[i], buffer, 1);
    }
}
/*!
 @function midi_note
 @abstract
 @discussion
 @param
 @result
 */
void midi_note(int pitch, int channel, int velocity)
{
    int channel1,  velocity1;

    channel1 = 1 + (channel % 16);
    velocity1 = velocity % 128;

    Pm_WriteShort(mstream, 0, Pm_Message(SBYTE(MD_NOTEON,channel1), pitch, velocity1));
}
Esempio n. 10
0
void SonifyBeginSonification()
{
   PmError err = Pm_OpenOutput(&sonMidiStream, Pm_GetDefaultOutputDeviceID(),
                               NULL, 0, NULL, NULL, 0);
   if (err) sonMidiStream = NULL;
   if (sonMidiStream)
      Pm_WriteShort(sonMidiStream, 0, Pm_Message(0xC0, SON_PROGRAM, 0));
   sonificationStarted = true;
}
/*!
 @function program_change
 @abstract
 @discussion
 @param
 @result
 */
void program_change(int channel, int instrument)
{
    int channel1, instrument1;

    instrument1 = 1+ (instrument % 128);
    channel1 = 1 + (channel % 16);

    Pm_WriteShort(mstream, 0, Pm_Message(SBYTE(MD_PRG,channel1), instrument1, 0));
}
Esempio n. 12
0
void
pm_bendout(Server *self, int value, int chan, long timestamp)
{
    int i, lsb, msb, curtime;
    PmEvent buffer[1];

    PyoPmBackendData *be_data = (PyoPmBackendData *) self->midi_be_data;

    curtime = Pt_Time();
    buffer[0].timestamp = curtime + timestamp;
    lsb = value & 0x007F;
    msb = (value & (0x007F << 7)) >> 7;
    if (chan == 0)
        buffer[0].message = Pm_Message(0xE0, lsb, msb);
    else
        buffer[0].message = Pm_Message(0xE0 | (chan - 1), lsb, msb);
    for (i=0; i<self->midiout_count; i++) {
        Pm_Write(be_data->midiout[i], buffer, 1);
    }
}
Esempio n. 13
0
static ERL_NIF_TERM do_write(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  static PortMidiStream ** stream;

  ErlNifResourceType* streamType = (ErlNifResourceType*)enif_priv_data(env);
  if(!enif_get_resource(env, argv[0], streamType, (PortMidiStream **) &stream)) {
    return enif_make_badarg(env);
  }

  ERL_NIF_TERM erlMessages = argv[1];
  const ERL_NIF_TERM * erlEvent;
  const ERL_NIF_TERM * erlMessage;
  ERL_NIF_TERM erlTuple;

  unsigned int numOfMessages;
  int tupleSize;
  enif_get_list_length(env, erlMessages, &numOfMessages);

  PmEvent events[numOfMessages];
  long int status, note, velocity, timestamp;

  for(unsigned int i = 0; i < numOfMessages; i++) {
    enif_get_list_cell(env, erlMessages, &erlTuple, &erlMessages);
    enif_get_tuple(env, erlTuple, &tupleSize, &erlEvent);

    enif_get_tuple(env, erlEvent[0], &tupleSize, &erlMessage);
    enif_get_long(env, erlMessage[0], &status);
    enif_get_long(env, erlMessage[1], &note);
    enif_get_long(env, erlMessage[2], &velocity);

    enif_get_long(env, erlEvent[1], &timestamp);

    PmEvent event;
    event.message = Pm_Message(status, note, velocity);
    event.timestamp = timestamp;

    events[i] = event;
  }

  PmError writeError;
  writeError = Pm_Write(*stream, events, numOfMessages);

  if (writeError == pmNoError) {
    return enif_make_atom(env, "ok");
  }

  const char * writeErrorMsg;
  writeErrorMsg = Pm_GetErrorText(writeError);

  return enif_make_tuple2(
    env,
    enif_make_atom(env, "error"),
    enif_make_string(env, writeErrorMsg, ERL_NIF_LATIN1)
  );
}
Esempio n. 14
0
void sys_putmidimess(int portno, int a, int b, int c)
{
    PmEvent buffer;
    /* fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev); */
    if (portno >= 0 && portno < mac_nmidioutdev)
    {
        buffer.message = Pm_Message(a, b, c);
        buffer.timestamp = 0;
        /* fprintf(stderr, "put msg\n"); */
        Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
    }
}
Esempio n. 15
0
int main (void)
{
    midi_init();

    // Play a chord
    midi_write(Pm_Message(0x90, 60, 100));
    midi_write(Pm_Message(0x90, 64, 100));
    midi_write(Pm_Message(0x90, 67, 100));
    midi_flush();
    
    printf("num_devices: %i\n",Pm_CountDevices());
    PmDeviceID id = Pm_GetDefaultOutputDeviceID();
    const PmDeviceInfo* device = Pm_GetDeviceInfo(id);
    printf("%s\n", device->name);
    
    
    char setchar = '.';
	int channel = 0;
	while (setchar!='\e'){
		scanf(" %c", &setchar);
		//printf("%c\n", setchar);
		switch (setchar){
			case 'z': channel = 0xB0; break;
			case 'x': channel = 0xB1; break;
			case 'c': channel = 0xB2; break;
			case 'v': channel = 0xB3; break;
                // 'q': Pm_WriteShort(midi, 0, Pm_Message(channel, 10, 0)); //button1
                // 'w': Pm_WriteShort(midi, 0, Pm_Message(channel, 11, 0)); //button2
                // 'e': Pm_WriteShort(midi, 0, Pm_Message(channel, 12, 0)); //button3
                // 'r': Pm_WriteShort(midi, 0, Pm_Message(channel, 13, 0)); //button4
			case '1': midi_write(Pm_Message(channel, 0, 0)); midi_flush(); break;
			case '2': midi_write(Pm_Message(channel, 1, 0)); midi_flush(); break;//hand angle
                // '7': Pm_WriteShort(midi, 0, Pm_Message(channel, 7, 0));
                // '8': Pm_WriteShort(midi, 0, Pm_Message(channel, 8, 0));
                // '9': Pm_WriteShort(midi, 0, Pm_Message(channel, 9, 0));
                // '0': Pm_WriteShort(midi, 0, Pm_Message(channel, 10, 0));
			default:
                break;
		}
	}
Esempio n. 16
0
int keyboard_send(MidiObj* m,uint8_t a,uint8_t b , uint8_t c) {

	if(!m->midi_stream_out) return 0;

	static PmEvent events[KEYBOARD_MAX_EVENTS];

	events[0].timestamp =  0;
	events[0].message = Pm_Message( a,b,c );

	int i = Pm_Write(m->midi_stream_out, events, 1);

	return i;
}
Esempio n. 17
0
void TestPmEventParser::noteOnOff()
{
  uint8_t input[] = {
    0x90, 0x40, 0x7f, /* Note On */
    0x90, 0x41, 0x32, /* Note On */
    0x80, 0x40, 0x7f, /* Note Off */
    0x80, 0x41, 0x32, /* Note Off */
  };
  PmEventParser parser;
  PmEvent event;

  parser.feed(input, sizeof(input));

  QVERIFY(parser.next(&event));
  QVERIFY(event.message == Pm_Message(0x90, 0x40, 0x7f));
  QVERIFY(parser.next(&event));
  QVERIFY(event.message == Pm_Message(0x90, 0x41, 0x32));
  QVERIFY(parser.next(&event));
  QVERIFY(event.message == Pm_Message(0x80, 0x40, 0x7f));
  QVERIFY(parser.next(&event));
  QVERIFY(event.message == Pm_Message(0x80, 0x41, 0x32));
  QVERIFY(!parser.next(&event));
}
Esempio n. 18
0
int main(int argc, char **argv)
{
    FILE *f;
    PmError perr;
    MfFile *pf;
    int ti;
    MfTrack *track;
    MfEvent *cur;
    int redux;

    if (argc < 4) {
        fprintf(stderr, "Use: hreducevel <file> <output file> <range reduction>\n");
        return 1;
    }
    redux = atoi(argv[3]);

    PSF(perr, Mf_Initialize, ());

    /* open it for input */
    SF(f, fopen, NULL, (argv[1], "rb"));

    /* and read it */
    PSF(perr, Mf_ReadMidiFile, (&pf, f));
    fclose(f);

    /* redux it */
    for (ti = 0; ti < pf->trackCt; ti++) {
        track = pf->tracks[ti];
        cur = track->head;
        while (cur) {
            if (Pm_MessageType(cur->e.message) == MIDI_NOTE_ON) {
                uint8_t vel = Pm_MessageData2(cur->e.message);
                vel = 127 - (127-vel)/redux;
                cur->e.message = Pm_Message(
                    Pm_MessageStatus(cur->e.message),
                    Pm_MessageData1(cur->e.message),
                    vel);
            }
            cur = cur->next;
        }
    }

    /* write it out */
    SF(f, fopen, NULL, (argv[2], "wb"));
    PSF(perr, Mf_WriteMidiFile, (f, pf));
    fclose(f);

    return 0;
}
Esempio n. 19
0
void
midibus::play (event * a_e24, unsigned char a_channel)
{
    automutex locker(m_mutex);
    PmEvent event;
    event.timestamp = 0;

    /* fill buffer and set midi channel */

    unsigned char buffer[3];                /* temp for midi data */
    buffer[0] = a_e24->get_status();
    buffer[0] += (a_channel & 0x0F);
    a_e24->get_data(&buffer[1], &buffer[2]);
    event.message = Pm_Message(buffer[0], buffer[1], buffer[2]);
    /*PmError err = */ Pm_Write(m_pms, &event, 1);
}
Esempio n. 20
0
static Scheme_Object *note_off(int argc, Scheme_Object **argv)
{
intptr_t channel,note,velocity;
PmEvent event;

  scheme_get_int_val(argv[0],&channel);
  scheme_get_int_val(argv[1],&note);
  scheme_get_int_val(argv[2],&velocity);

  event.message=Pm_Message(0x80+(unsigned char)channel,
                    (unsigned char)note,
                    (unsigned char)velocity);
  event.timestamp=0;
  midi_io.write_event(&event);

  return scheme_void;
} // note_off()
Esempio n. 21
0
void playRaw(const mxArray *A) {
  int N = mxGetNumberOfElements(A);
  unsigned char * data = mxGetData(A);
  int n;
  
  PmMessage msg;
  PmError err;
  
  if (N % 3 != 0) mexErrMsgTxt("Raw arguments must be a multiple of 3 elements long.");
  
  N/=3;
  
  for (n=0;n<N;n++) {
    msg = Pm_Message(data[0], data[1], data[2]);
    err = Pm_WriteShort(outStream, 0, msg);
    if (err!=pmNoError) reportPmError(err);
    data+=3;
  }
}
Esempio n. 22
0
/*
-------------------------------------------------------------
*/
int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed)
{
	ScopeMutexLock mulo(&gPmStreamMutex);
	//port, uid, len, hiStatus, loStatus, a, b, latency
	//PyrSlot *m = g->sp - 8;
	PyrSlot *p = g->sp - 7;

	PyrSlot *u = g->sp - 6;
	PyrSlot *l = g->sp - 5;

	PyrSlot *his = g->sp - 4;
	PyrSlot *los = g->sp - 3;

	PyrSlot *a = g->sp - 2;
	PyrSlot *b = g->sp - 1;
	PyrSlot *plat = g->sp;

	int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval;
	float late;
	err = slotIntVal(p, &outputIndex);
	if (err) return err;
	if (outputIndex < 0 || outputIndex >= gNumMIDIOutPorts) return errIndexOutOfRange;

	err = slotIntVal(u, &uid);
	if (err) return err;
	err = slotIntVal(l, &length);
	if (err) return err;
	err = slotIntVal(his, &hiStatus);
	if (err) return err;
	err = slotIntVal(los, &loStatus);
	if (err) return err;
	err = slotIntVal(a, &aval);
	if (err) return err;
	err = slotIntVal(b, &bval);
	if (err) return err;
	err = slotFloatVal(plat, &late);
	if (err) return err;

	Pm_WriteShort(gMIDIOutStreams[uid], 0, 
	Pm_Message((hiStatus & 0xF0) | (loStatus & 0x0F) , aval, bval));

	return errNone;
}
Esempio n. 23
0
TTErr MIDIOutput::sendMessage(TTAddress& address, const TTValue& value)
{
    if (mRunning) {
        
        MIDIParserTo    parser;
        TTBoolean       done;
        
        // until the parsing ends
        do {
            done = parser.parse(address, value);
            int message = Pm_Message(parser.statusByte, parser.dataByte1, parser.dataByte2);
            Pm_WriteShort(mStream, 0, message);
        }
        while (!done);
        
        return kTTErrNone;
    }
    
    return kTTErrGeneric;
}
Esempio n. 24
0
static Scheme_Object *note_on(int argc, Scheme_Object **argv)
{
intptr_t channel,note,velocity;
PmEvent event;

  scheme_get_int_val(argv[0],&channel);
  scheme_get_int_val(argv[1],&note);
  scheme_get_int_val(argv[2],&velocity);

  /*
    #define Pm_Message(status, data1, data2) \
              ((((data2) << 16) & 0xFF0000) | \
               (((data1) << 8) & 0xFF00) | \
               ((status) & 0xFF))
  */
  event.message=Pm_Message(0x90+(int)channel,(int)note,(int)velocity);
  event.timestamp=0;
  midi_io.write_event(&event);

  return scheme_void;
} // note_on()
Esempio n. 25
0
void sendProgChange(const mxArray *prhs[]) {
  int channel = (int) mxGetScalar(prhs[1]);
  int prog = (int) mxGetScalar(prhs[2]);
  int status;
  PmMessage msg;
  PmError err;
  
  if (channel < 1 || channel > 16) mexErrMsgTxt("Channel (2nd arg.) must be 1..16");
  --channel;
  
  if (!mxIsDouble(prhs[2])) {
    mexErrMsgTxt("3rd argument (program number) must be a 'double'");
  }
  
  status = 0xC0 | channel;
  
  msg = Pm_Message(status, prog-1, 0);
  /* latency=0 => send asap */
  err = Pm_WriteShort(outStream, 0, msg);
  if (err!=pmNoError) reportPmError(err);
}
Esempio n. 26
0
static void Mf_FinalizeTrack(MfTrack *track)
{
    MfEvent *event;
    int mustFinalize = 0;

    if (track->tail) {
        event = track->tail;
        if (!(event->meta) || event->meta->type != 0x2F) { /* last isn't end-of-stream */
            mustFinalize = 1;
        }
    } else {
        mustFinalize = 1;
    }

    if (mustFinalize) {
        /* OK, we have to finalize */
        event = Mf_NewEvent();
        event->e.message = Pm_Message(0xFF, 0, 0);
        event->meta = Mf_NewMeta(0);
        event->meta->type = 0x2F;
        Mf_PushEvent(track, event);
    }
}
Esempio n. 27
0
/* timer interrupt for processing midi data */
void process_midi(PtTimestamp timestamp, void *userData)
{
    PmError result;
    PmEvent buffer; /* just one message at a time */
    long msg;

    /* do nothing until initialization completes */
    if (!active) 
        return;

    /* check for messages */
    do { 
        result = Pm_Dequeue(main_to_midi, &msg); 
        if (result) {
            if (msg >= -127 && msg <= 127) 
                transpose = msg;
            else if (msg == QUIT_MSG) {
                /* acknowledge receipt of quit message */
                Pm_Enqueue(midi_to_main, &msg);
                active = FALSE;
                return;
            } else if (msg == MONITOR_MSG) {
                /* main has requested a pitch. monitor is a flag that
                 * records the request:
                 */
                monitor = TRUE;
            } else if (msg == THRU_MSG) {
                /* toggle Thru on or off */
                midi_thru = !midi_thru;
            }
        }
    } while (result);         
    
    /* see if there is any midi input to process */
    do {
		result = Pm_Poll(midi_in);
        if (result) {
            long status, data1, data2;
            if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) 
                continue;
            if (midi_thru) 
                Pm_Write(midi_out, &buffer, 1);
            /* unless there was overflow, we should have a message now */
            status = Pm_MessageStatus(buffer.message);
            data1 = Pm_MessageData1(buffer.message);
            data2 = Pm_MessageData2(buffer.message);
            if ((status & 0xF0) == 0x90 ||
                (status & 0xF0) == 0x80) {
                
                /* this is a note-on or note-off, so transpose and send */
                data1 += transpose;
                
                /* keep within midi pitch range, keep proper pitch class */
                while (data1 > 127) 
                    data1 -= 12;
                while (data1 < 0) 
                    data1 += 12;
                
                /* send the message */
                buffer.message = Pm_Message(status, data1, data2);
                Pm_Write(midi_out, &buffer, 1);
                
                /* if monitor is set, send the pitch to the main thread */
                if (monitor) {
                    Pm_Enqueue(midi_to_main, &data1);
                    monitor = FALSE; /* only send one pitch per request */
                }
            }
        }
    } while (result);
}
Esempio n. 28
0
// TODO: this was copied from Jack version...I'd like to eventually unify these two, so that they handle midi event types in the same manner
void Portaudio::putEvent(const NPlayEvent& e, unsigned framePos)
      {
      PortMidiDriver* portMidiDriver = static_cast<PortMidiDriver*>(midiDriver);
      if (!portMidiDriver || !portMidiDriver->getOutputStream() || !portMidiDriver->canOutput())
            return;

      int portIdx = seq->score()->midiPort(e.channel());
      int chan    = seq->score()->midiChannel(e.channel());

      if (portIdx < 0 ) {
            qDebug("Portaudio::putEvent: invalid port %d", portIdx);
            return;
            }

      if (midiOutputTrace) {
            int a     = e.dataA();
            int b     = e.dataB();
            qDebug("MidiOut<%d>: Portaudio: %02x %02x %02x, chan: %i", portIdx, e.type(), a, b, chan);
            }

      switch(e.type()) {
            case ME_NOTEON:
            case ME_NOTEOFF:
            case ME_POLYAFTER:
            case ME_CONTROLLER:
                  // Catch CTRL_PROGRAM and let other ME_CONTROLLER events to go
                  if (e.dataA() == CTRL_PROGRAM) {
                        // Convert CTRL_PROGRAM event to ME_PROGRAM
                        long msg = Pm_Message(ME_PROGRAM | chan, less128(e.dataB()), 0);
                        PmError error = Pm_WriteShort(portMidiDriver->getOutputStream(), seq->getCurrentMillisecondTimestampWithLatency(framePos), msg);
                        if (error != pmNoError) {
                              qDebug("Portaudio: error %d", error);
                              return;
                              }
                        break;
                        }
                  // fall through
            case ME_PITCHBEND:
                  {
                  long msg = Pm_Message(e.type() | chan, less128(e.dataA()), less128(e.dataB()));
                  PmError error = Pm_WriteShort(portMidiDriver->getOutputStream(), seq->getCurrentMillisecondTimestampWithLatency(framePos), msg);
                  if (error != pmNoError) {
                        qDebug("Portaudio: error %d", error);
                        return;
                        }
                  }
                  break;

            case ME_PROGRAM:
            case ME_AFTERTOUCH:
                  {
                  long msg = Pm_Message(e.type() | chan, less128(e.dataA()), 0);
                  PmError error = Pm_WriteShort(portMidiDriver->getOutputStream(), seq->getCurrentMillisecondTimestampWithLatency(framePos), msg);
                  if (error != pmNoError) {
                        qDebug("Portaudio: error %d", error);
                        return;
                        }
                  }
                  break;
            case ME_SONGPOS:
            case ME_CLOCK:
            case ME_START:
            case ME_CONTINUE:
            case ME_STOP:
                  qDebug("Portaudio: event type %x not supported", e.type());
                  break;
            }
      }
Esempio n. 29
0
void main_test_output() {
    PmStream * midi;
	char line[80];
    int32_t off_time;
    int chord[] = { 60, 67, 76, 83, 90 };
    #define chord_size 5 
    PmEvent buffer[chord_size];
    PmTimestamp timestamp;

    /* determine which output device to use */
    int i = get_number("Type output number: ");

    /* It is recommended to start timer before PortMidi */
    TIME_START;

    /* open output device -- since PortMidi avoids opening a timer
       when latency is zero, we will pass in a NULL timer pointer
       for that case. If PortMidi tries to access the time_proc,
       we will crash, so this test will tell us something. */
    Pm_OpenOutput(&midi, 
                  i, 
                  DRIVER_INFO,
                  OUTPUT_BUFFER_SIZE, 
                  (latency == 0 ? NULL : TIME_PROC),
                  (latency == 0 ? NULL : TIME_INFO), 
                  latency);
    printf("Midi Output opened with %ld ms latency.\n", (long) latency);

    /* output note on/off w/latency offset; hold until user prompts */
    printf("ready to send program 1 change... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
    /* if we were writing midi for immediate output, we could always use
       timestamps of zero, but since we may be writing with latency, we
       will explicitly set the timestamp to "now" by getting the time.
       The source of timestamps should always correspond to the TIME_PROC
       and TIME_INFO parameters used in Pm_OpenOutput(). */
    buffer[0].timestamp = TIME_PROC(TIME_INFO);
    /* Send a program change to increase the chances we will hear notes */
    /* Program 0 is usually a piano, but you can change it here: */
#define PROGRAM 0
    buffer[0].message = Pm_Message(0xC0, PROGRAM, 0);
    Pm_Write(midi, buffer, 1);

    printf("ready to note-on... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
    buffer[0].timestamp = TIME_PROC(TIME_INFO);
    buffer[0].message = Pm_Message(0x90, 60, 100);
    Pm_Write(midi, buffer, 1);
    printf("ready to note-off... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
    buffer[0].timestamp = TIME_PROC(TIME_INFO);
    buffer[0].message = Pm_Message(0x90, 60, 0);
    Pm_Write(midi, buffer, 1);

    /* output short note on/off w/latency offset; hold until user prompts */
    printf("ready to note-on (short form)... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
    Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
                  Pm_Message(0x90, 60, 100));
    printf("ready to note-off (short form)... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
    Pm_WriteShort(midi, TIME_PROC(TIME_INFO),
                  Pm_Message(0x90, 60, 0));

    /* output several note on/offs to test timing. 
       Should be 1s between notes */
    printf("chord will arpeggiate if latency > 0\n");
    printf("ready to chord-on/chord-off... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
    timestamp = TIME_PROC(TIME_INFO);
    for (i = 0; i < chord_size; i++) {
        buffer[i].timestamp = timestamp + 1000 * i;
        buffer[i].message = Pm_Message(0x90, chord[i], 100);
    }
    Pm_Write(midi, buffer, chord_size);

    off_time = timestamp + 1000 + chord_size * 1000; 
    while (TIME_PROC(TIME_INFO) < off_time) 
		/* busy wait */;
    for (i = 0; i < chord_size; i++) {
        buffer[i].timestamp = timestamp + 1000 * i;
        buffer[i].message = Pm_Message(0x90, chord[i], 0);
    }
    Pm_Write(midi, buffer, chord_size);    

    /* close device (this not explicitly needed in most implementations) */
    printf("ready to close and terminate... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
	
    Pm_Close(midi);
    Pm_Terminate();
    printf("done closing and terminating...\n");
}
Esempio n. 30
0
/*    The winmm stream mode is used for latency>0, and sends
   timestamped messages. The timestamps are relative (delta) 
   times, whereas PortMidi times are absolute. Since peculiar
   things happen when messages are not always sent in advance,
   this function allows us to exercise the system and test it.
 */
void main_test_stream() {
    PmStream * midi;
	char line[80];
    PmEvent buffer[16];

	/* determine which output device to use */
    int i = get_number("Type output number: ");

	latency = 500; /* ignore LATENCY for this test and
				      fix the latency at 500ms */

    /* It is recommended to start timer before PortMidi */
    TIME_START;

	/* open output device */
    Pm_OpenOutput(&midi, 
                  i, 
                  DRIVER_INFO,
                  OUTPUT_BUFFER_SIZE, 
                  TIME_PROC,
                  TIME_INFO, 
                  latency);
    printf("Midi Output opened with %ld ms latency.\n", (long) latency);

    /* output note on/off w/latency offset; hold until user prompts */
    printf("ready to send output... (type RETURN):");
    fgets(line, STRING_MAX, stdin);

    /* if we were writing midi for immediate output, we could always use
       timestamps of zero, but since we may be writing with latency, we
       will explicitly set the timestamp to "now" by getting the time.
       The source of timestamps should always correspond to the TIME_PROC
       and TIME_INFO parameters used in Pm_OpenOutput(). */
    buffer[0].timestamp = TIME_PROC(TIME_INFO);
    buffer[0].message = Pm_Message(0xC0, 0, 0);
	buffer[1].timestamp = buffer[0].timestamp;
	buffer[1].message = Pm_Message(0x90, 60, 100);
	buffer[2].timestamp = buffer[0].timestamp + 1000;
	buffer[2].message = Pm_Message(0x90, 62, 100);
	buffer[3].timestamp = buffer[0].timestamp + 2000;
	buffer[3].message = Pm_Message(0x90, 64, 100);
	buffer[4].timestamp = buffer[0].timestamp + 3000;
	buffer[4].message = Pm_Message(0x90, 66, 100);
	buffer[5].timestamp = buffer[0].timestamp + 4000;
	buffer[5].message = Pm_Message(0x90, 60, 0);
	buffer[6].timestamp = buffer[0].timestamp + 4000;
	buffer[6].message = Pm_Message(0x90, 62, 0);
	buffer[7].timestamp = buffer[0].timestamp + 4000;
	buffer[7].message = Pm_Message(0x90, 64, 0);
	buffer[8].timestamp = buffer[0].timestamp + 4000;
	buffer[8].message = Pm_Message(0x90, 66, 0);

    Pm_Write(midi, buffer, 9);
#ifdef SEND8
	/* Now, we're ready for the real test.
	   Play 4 notes at now, now+500, now+1000, and now+1500
	   Then wait until now+2000.
	   Play 4 more notes as before.
	   We should hear 8 evenly spaced notes. */
	now = TIME_PROC(TIME_INFO);
	for (i = 0; i < 4; i++) {
		buffer[i * 2].timestamp = now + (i * 500);
		buffer[i * 2].message = Pm_Message(0x90, 60, 100);
		buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
		buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
	}
    Pm_Write(midi, buffer, 8);

    while (Pt_Time() < now + 2500) 
		/* busy wait */;
	/* now we are 500 ms behind schedule, but since the latency
	   is 500, the delay should not be audible */
	now += 2000;
	for (i = 0; i < 4; i++) {
		buffer[i * 2].timestamp = now + (i * 500);
		buffer[i * 2].message = Pm_Message(0x90, 60, 100);
		buffer[i * 2 + 1].timestamp = now + 250 + (i * 500);
		buffer[i * 2 + 1].message = Pm_Message(0x90, 60, 0);
	}
    Pm_Write(midi, buffer, 8);
#endif
    /* close device (this not explicitly needed in most implementations) */
    printf("ready to close and terminate... (type RETURN):");
    fgets(line, STRING_MAX, stdin);
	
    Pm_Close(midi);
    Pm_Terminate();
    printf("done closing and terminating...\n");
}