void SprayEvent(MIDIEvent *ev, uint32 time)
  {
    switch (ev->status & 0xF0)
    {
    case B_NOTE_OFF:
      SprayNoteOff((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
      break;
    case B_NOTE_ON:
      SprayNoteOn((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
      break;
    case B_KEY_PRESSURE:
      SprayKeyPressure((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
      break;
    case B_CONTROL_CHANGE:
      SprayControlChange((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
      break;
    case B_PROGRAM_CHANGE:
      SprayProgramChange((ev->status & 0x0F) + 1, ev->data[0], time);
      break;
    case B_CHANNEL_PRESSURE:
      SprayChannelPressure((ev->status & 0x0F) + 1, ev->data[0], time);
      break;
    case B_PITCH_BEND:
      SprayPitchBend((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
      break;
    case 0xF:
      switch (ev->status)
      {
      case B_SYS_EX_START:
        SpraySystemExclusive(ev->extraData, ev->extraLen, time);
	break;
      case B_MIDI_TIME_CODE:
      case B_SONG_POSITION:
      case B_SONG_SELECT:
      case B_CABLE_MESSAGE:
      case B_TUNE_REQUEST:
      case B_SYS_EX_END:
        SpraySystemCommon(ev->status, ev->data[0], ev->data[1], time);
	break;
      case B_TIMING_CLOCK:
      case B_START:
      case B_STOP:
      case B_CONTINUE:
      case B_ACTIVE_SENSING:
        SpraySystemRealTime(ev->status, time);
	break;
      case B_SYSTEM_RESET:
        if (ev->data[0] == 0x51 && ev->data[1] == 0x03)
	{
	  assert(ev->extraLen == 3);
	  int val = (ev->extraData[0] << 16) | (ev->extraData[1] << 8) | ev->extraData[2];
	  int tempo = 60000000 / val;
	  SprayTempoChange(tempo, time);
	}
	else
	{
	  SpraySystemRealTime(ev->status, time);
	}
      }
      break;
    }
  }
예제 #2
0
int32 
MidiPortProducer::GetData()
{
	uint8 msgBuf[3];
	uint8* sysexBuf = NULL;

	uint8* msgPtr = NULL;
	size_t msgSize = 0;
	size_t needed = 0;
	uint8 runningStatus = 0;

	bool haveSysEx = false;
	size_t sysexAlloc = 0;
	size_t sysexSize = 0;

	uint8 next = 0;

	while (fKeepRunning) {
		if (read(fFileDescriptor, &next, 1) != 1) {
			if (errno == B_CANCELED) 
				fKeepRunning = false;
			else 
				perror("Error reading data from driver");
			break;
		}
	
		bigtime_t timestamp = system_time();

		if (haveSysEx) { 
			// System Exclusive mode
			if (next < 0x80) { 
				// System Exclusive data byte
				sysexBuf[sysexSize++] = next;
				if (sysexSize == sysexAlloc) {
					sysexAlloc *= 2;
					sysexBuf = (uint8*) realloc(sysexBuf, sysexAlloc);
				}
				continue;
			} else if ((next & 0xF8) == 0xF8) {
				// System Realtime interleaved in System Exclusive sequence
				SpraySystemRealTime(next, timestamp);
				continue;
			} else {  
				// Whatever byte, this one ends the running SysEx sequence
				SpraySystemExclusive(sysexBuf, sysexSize, timestamp);
				haveSysEx = false;
				if (next == B_SYS_EX_END) {
					// swallow SysEx end byte
					continue;
				}
				// any other byte, while ending the SysEx sequence, 
				// should be handled, not dropped
			}
		}
		
		if ((next & 0xF8) == 0xF8) {
			// System Realtime
			SpraySystemRealTime(next, timestamp);
		} else if ((next & 0xF0) == 0xF0) {
			// System Common
			runningStatus = 0;
			msgBuf[0] = next;
			msgPtr = msgBuf + 1;
			switch (next) {
				case B_SYS_EX_START:
					sysexAlloc = 4096;
					sysexBuf = (uint8*) malloc(sysexAlloc);
					sysexSize = 0;
					haveSysEx = true;
					break;

				case B_SONG_POSITION:
					needed = 2;
					msgSize = 3;
					break;

				case B_MIDI_TIME_CODE:
				case B_SONG_SELECT:
				case B_CABLE_MESSAGE:
					needed = 1;
					msgSize = 2;
					break;
			
				case B_SYS_EX_END:	
					// Unpaired with B_SYS_EX_START, but pass it anyway...
				case B_TUNE_REQUEST:
					SpraySystemCommon(next, 0, 0, timestamp);
					break;
			}			
		} else if ((next & 0x80) == 0x80) {
			// Voice message
			runningStatus = next;
			msgBuf[0] = next;
			msgPtr = msgBuf + 1;
			switch (next & 0xF0) {
				case B_NOTE_OFF:
				case B_NOTE_ON:
				case B_KEY_PRESSURE:
				case B_CONTROL_CHANGE:
				case B_PITCH_BEND:
					needed = 2;
					msgSize = 3;
					break;

				case B_PROGRAM_CHANGE:
				case B_CHANNEL_PRESSURE:
					needed = 1;
					msgSize = 2;
					break;
			}
		} else if (needed > 0) {
			// Data bytes to complete message
			*msgPtr++ = next;
			if (--needed == 0) {
				switch (msgBuf[0] & 0xF0) {
					case B_NOTE_OFF:
						SprayNoteOff(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2],
							timestamp);
						break;

					case B_NOTE_ON:
						SprayNoteOn(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2],
							timestamp);
						break;

					case B_KEY_PRESSURE:
						SprayKeyPressure(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2],
							timestamp);
						break;

					case B_CONTROL_CHANGE:
						SprayControlChange(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2],
							timestamp);
						break;

					case B_PROGRAM_CHANGE:
						SprayProgramChange(msgBuf[0] & 0x0F, msgBuf[1],
							timestamp);
						break;

					case B_CHANNEL_PRESSURE:
						SprayChannelPressure(msgBuf[0] & 0x0F, msgBuf[1],
							timestamp);
						break;

					case B_PITCH_BEND:
						SprayPitchBend(msgBuf[0] & 0x0F, msgBuf[1], msgBuf[2],
							timestamp);
						break;
				}

				switch (msgBuf[0]) {
					case B_SONG_POSITION:
						SpraySystemCommon(msgBuf[0], msgBuf[1], msgBuf[2],
							timestamp);
						break;

					case B_MIDI_TIME_CODE:
					case B_SONG_SELECT:
					case B_CABLE_MESSAGE:
						SpraySystemCommon(msgBuf[0], msgBuf[1], 0, timestamp);
						break;
				}
			}
		} else if (runningStatus != 0) {
			// Repeated voice command
			msgBuf[0] = runningStatus;
			msgBuf[1] = next;
			msgPtr = msgBuf + 2;
			needed = msgSize - 2;
		}
	}	// while fKeepRunning

	if (haveSysEx)
		free(sysexBuf);

	return fKeepRunning ? errno : B_OK;
}