예제 #1
0
파일: midi_usb.c 프로젝트: JoeMatt/p600fw
void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) {
   MIDI_EventPacket_t event;
   event.Data1 = byte0;
   event.Data2 = byte1;
   event.Data3 = byte2;

   //if the length is undefined we assume it is a SYSEX message
   if (midi_packet_length(byte0) == UNDEFINED) {
      switch(cnt) {
         case 3:
            if (byte2 == SYSEX_END)
               event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_3);
            else
               event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT);
            break;
         case 2:
            if (byte1 == SYSEX_END)
               event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_2);
            else
               event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT);
            break;
         case 1:
            if (byte0 == SYSEX_END)
               event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_1);
            else
               event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT);
            break;
         default:
            return; //invalid cnt
      }
   } else {
      //deal with 'system common' messages
      //TODO are there any more?
      switch(byte0 & 0xF0){
         case MIDI_SONGPOSITION:
            event.Event = MIDI_EVENT(0, SYS_COMMON_3);
            break;
         case MIDI_SONGSELECT:
         case MIDI_TC_QUARTERFRAME:
            event.Event = MIDI_EVENT(0, SYS_COMMON_2);
            break;
         default:
            event.Event = MIDI_EVENT(0, byte0);
            break;
      }
   }

   MIDI_Device_SendEventPacket(&USB_MIDI_Interface, &event);
   MIDI_Device_Flush(&USB_MIDI_Interface);
   MIDI_Device_USBTask(&USB_MIDI_Interface);
   USB_USBTask();
}
예제 #2
0
/** Task to manage an enumerated USB MIDI device once connected, to display received
 *  note events from the host and send note changes in response to the board's joystick.
 */
void JoystickHost_Task(void)
{
	if (USB_HostState != HOST_STATE_Configured)
	  return;

	MIDI_EventPacket_t MIDIEvent;
	while (MIDI_Host_ReceiveEventPacket(&Keyboard_MIDI_Interface, &MIDIEvent))
	{
		bool NoteOnEvent  = (MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON));
		bool NoteOffEvent = (MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_OFF));

		/* Display note events from the host */
		if (NoteOnEvent || NoteOffEvent)
		{
			printf_P(PSTR("MIDI Note %s - Channel %d, Pitch %d, Velocity %d\r\n"), NoteOnEvent ? "On" : "Off",
																				   ((MIDIEvent.Data1 & 0x0F) + 1),
																				   MIDIEvent.Data2, MIDIEvent.Data3);
		}
	}

	CheckJoystickMovement();
}
예제 #3
0
파일: DualMIDI.c 프로젝트: 40000ft/lufa
/** Main program entry point. This routine contains the overall program flow, including initial
 *  setup of all components and the main program loop.
 */
int main(void)
{
	SetupHardware();

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
	GlobalInterruptEnable();

	for (;;)
	{
		CheckJoystickMovement();

		MIDI_EventPacket_t ReceivedMIDIEvent;
		while (MIDI_Device_ReceiveEventPacket(&Keyboard_MIDI_Interface, &ReceivedMIDIEvent))
		{
			if ((ReceivedMIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON)) && (ReceivedMIDIEvent.Data3 > 0))
			  LEDs_SetAllLEDs(ReceivedMIDIEvent.Data2 > 64 ? LEDS_LED1 : LEDS_LED2);
			else
			  LEDs_SetAllLEDs(LEDS_NO_LEDS);
		}

		MIDI_Device_USBTask(&Keyboard_MIDI_Interface);
		USB_USBTask();
	}
}
예제 #4
0
/** Main program entry point. This routine contains the overall program flow, including initial
 *  setup of all components and the main program loop.
 */
int main(void)
{
	SetupHardware();

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
	GlobalInterruptEnable();

	for (;;)
	{
		MIDI_EventPacket_t ReceivedMIDIEvent;
		if (MIDI_Device_ReceiveEventPacket(&Keyboard_MIDI_Interface, &ReceivedMIDIEvent))
		{
			if ((ReceivedMIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
			{
				DDSNoteData* LRUNoteStruct = &NoteData[0];

				/* Find a free entry in the note table to use for the note being turned on */
				for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
				{
					/* Check if the note is unused */
					if (!(NoteData[i].Pitch))
					{
						/* If a note is unused, it's age is essentially infinite - always prefer unused not entries */
						LRUNoteStruct = &NoteData[i];
						break;
					}
					else if (NoteData[i].LRUAge >= LRUNoteStruct->LRUAge)
					{
						/* If an older entry that the current entry has been found, prefer overwriting that one */
						LRUNoteStruct = &NoteData[i];
					}

					NoteData[i].LRUAge++;
				}

				/* Update the oldest note entry with the new note data and reset its age */
				LRUNoteStruct->Pitch          = ReceivedMIDIEvent.Data2;
				LRUNoteStruct->TableIncrement = (uint32_t)(BASE_INCREMENT * SCALE_FACTOR) +
						                         ((uint32_t)(BASE_INCREMENT * NOTE_OCTIVE_RATIO * SCALE_FACTOR) *
						                          (ReceivedMIDIEvent.Data2 - BASE_PITCH_INDEX));
				LRUNoteStruct->TablePosition  = 0;
				LRUNoteStruct->LRUAge         = 0;

				/* Turn on indicator LED to indicate note generation activity */
				LEDs_SetAllLEDs(LEDS_LED1);
			}
			else if ((ReceivedMIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_OFF)) && ((ReceivedMIDIEvent.Data1 & 0x0F) == 0))
			{
				bool FoundActiveNote = false;

				/* Find the note in the note table to turn off */
				for (uint8_t i = 0; i < MAX_SIMULTANEOUS_NOTES; i++)
				{
					if (NoteData[i].Pitch == ReceivedMIDIEvent.Data2)
					  NoteData[i].Pitch = 0;
					else if (NoteData[i].Pitch)
					  FoundActiveNote   = true;
				}

				/* If all notes off, turn off the indicator LED */
				if (!(FoundActiveNote))
				  LEDs_SetAllLEDs(LEDS_NO_LEDS);
			}
		}

		MIDI_Device_USBTask(&Keyboard_MIDI_Interface);
		USB_USBTask();
	}
}
예제 #5
0
파일: MIDI.c 프로젝트: eta4ever/led-kb
// 		.Event       = MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON), // VirtualCable 0
// 		.Data1       = MIDI_COMMAND_NOTE_ON | MIDI_CHANNEL(1),
// 		.Data2       = 0b00000001,
// 		.Data3       = vel, 
// 	};

// 	MIDI_Device_SendEventPacket(&Keyboard_MIDI_Interface, &MIDIEvent); // отправить пакет
// 	MIDI_Device_Flush(&Keyboard_MIDI_Interface);
// }

// отправить в кабель 0 инструмент instr CONTROL CHANGE с заданным vel
void cc_send(int instr, int vel)
{
	MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t) // сформировать пакет
			{
				.Event       = MIDI_EVENT(0, MIDI_COMMAND_CONTROL_CHANGE), // VirtualCable 0
				.Data1       = MIDI_COMMAND_CONTROL_CHANGE | MIDI_CHANNEL(1), // канал 1
				.Data2       = instr, 
				.Data3       = vel, 
			};

			MIDI_Device_SendEventPacket(&Keyboard_MIDI_Interface, &MIDIEvent); // отправить пакет
			MIDI_Device_Flush(&Keyboard_MIDI_Interface);
}

/** установить адрес входа мультиплексора */
void MUX_address(int address)
{
	if (address & 0b0001) PORTF |= (1<<PF4); else PORTF &= ~(1<<PF4);
	if (address & 0b0010) PORTF |= (1<<PF5); else PORTF &= ~(1<<PF5);
	if (address & 0b0100) PORTF |= (1<<PF6); else PORTF &= ~(1<<PF6);
예제 #6
0
/** Task to handle the generation of MIDI note change events in response to presses of the board joystick, and send them
 *  to the host.
 */
void MIDI_Task(void)
{
	static uint8_t PrevJoystickStatus;

	/* Device must be connected and configured for the task to run */
	if (USB_DeviceState != DEVICE_STATE_Configured)
	  return;

	Endpoint_SelectEndpoint(MIDI_STREAM_IN_EPADDR);

	if (Endpoint_IsINReady())
	{
		uint8_t MIDICommand = 0;
		uint8_t MIDIPitch;

		uint8_t JoystickStatus  = Joystick_GetStatus();
		uint8_t JoystickChanges = (JoystickStatus ^ PrevJoystickStatus);

		/* Get board button status - if pressed use channel 10 (percussion), otherwise use channel 1 */
		uint8_t Channel = ((Buttons_GetStatus() & BUTTONS_BUTTON1) ? MIDI_CHANNEL(10) : MIDI_CHANNEL(1));

		if (JoystickChanges & JOY_LEFT)
		{
			MIDICommand = ((JoystickStatus & JOY_LEFT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3C;
		}

		if (JoystickChanges & JOY_UP)
		{
			MIDICommand = ((JoystickStatus & JOY_UP)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3D;
		}

		if (JoystickChanges & JOY_RIGHT)
		{
			MIDICommand = ((JoystickStatus & JOY_RIGHT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3E;
		}

		if (JoystickChanges & JOY_DOWN)
		{
			MIDICommand = ((JoystickStatus & JOY_DOWN)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3F;
		}

		if (JoystickChanges & JOY_PRESS)
		{
			MIDICommand = ((JoystickStatus & JOY_PRESS)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3B;
		}

		/* Check if a MIDI command is to be sent */
		if (MIDICommand)
		{
			MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t)
				{
					.Event       = MIDI_EVENT(0, MIDICommand),

					.Data1       = MIDICommand | Channel,
					.Data2       = MIDIPitch,
					.Data3       = MIDI_STANDARD_VELOCITY,
				};

			/* Write the MIDI event packet to the endpoint */
			Endpoint_Write_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL);

			/* Send the data in the endpoint to the host */
			Endpoint_ClearIN();
		}

		/* Save previous joystick value for next joystick change detection */
		PrevJoystickStatus = JoystickStatus;
	}

	/* Select the MIDI OUT stream */
	Endpoint_SelectEndpoint(MIDI_STREAM_OUT_EPADDR);

	/* Check if a MIDI command has been received */
	if (Endpoint_IsOUTReceived())
	{
		MIDI_EventPacket_t MIDIEvent;

		/* Read the MIDI event packet from the endpoint */
		Endpoint_Read_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL);

		/* Check to see if the sent command is a note on message with a non-zero velocity */
		if ((MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON)) && (MIDIEvent.Data3 > 0))
		{
			/* Change LEDs depending on the pitch of the sent note */
			LEDs_SetAllLEDs(MIDIEvent.Data2 > 64 ? LEDS_LED1 : LEDS_LED2);
		}
		else
		{
			/* Turn off all LEDs in response to non Note On messages */
			LEDs_SetAllLEDs(LEDS_NO_LEDS);
		}

		/* If the endpoint is now empty, clear the bank */
		if (!(Endpoint_BytesInEndpoint()))
		{
			/* Clear the endpoint ready for new packet */
			Endpoint_ClearOUT();
		}
	}
}
예제 #7
0
// Parse via Arduino/Serial
ISR(USART1_RX_vect, ISR_BLOCK) 
{
	// Device must be connected and configured for the task to run
	if (USB_DeviceState != DEVICE_STATE_Configured) return;

	const uint8_t extracted = UDR1;

	// Borrowed + Modified from Francois Best's Arduino MIDI Library
	// https://github.com/FortySevenEffects/arduino_midi_library
    if (mPendingMessageIndex == 0)
    {
        // Start a new pending message
        mPendingMessage[0] = extracted;

        // Check for running status first
        if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX)))
        {
            // Only these types allow Running Status

            // If the status byte is not received, prepend it to the pending message
            if (extracted < 0x80)
            {
                mPendingMessage[0]   = mRunningStatus_RX;
                mPendingMessage[1]   = extracted;
                mPendingMessageIndex = 1;
            }
            // Else we received another status byte, so the running status does not apply here.
            // It will be updated upon completion of this message.
        }

        switch (getTypeFromStatusByte(mPendingMessage[0]))
        {
            // 1 byte messages
            case Start:
            case Continue:
            case Stop:
            case Clock:
            case ActiveSensing:
            case SystemReset:
            case TuneRequest:
                // Handle the message type directly here.
            	mCompleteMessage.Event 	 = MIDI_EVENT(0, getTypeFromStatusByte(mPendingMessage[0]));
                mCompleteMessage.Data1   = mPendingMessage[0];
                mCompleteMessage.Data2   = 0;
                mCompleteMessage.Data3   = 0;
                mPendingMessageValid  	 = true;

                // We still need to reset these
                mPendingMessageIndex = 0;
                mPendingMessageExpectedLength = 0;

                return;
                break;

            // 2 bytes messages
            case ProgramChange:
            case AfterTouchChannel:
            case TimeCodeQuarterFrame:
            case SongSelect:
                mPendingMessageExpectedLength = 2;
                break;

            // 3 bytes messages
            case NoteOn:
            case NoteOff:
            case ControlChange:
            case PitchBend:
            case AfterTouchPoly:
            case SongPosition:
                mPendingMessageExpectedLength = 3;
                break;

            case SystemExclusive:
                break;

            case InvalidType:
            default:
                // Something bad happened
                break;
        }

        if (mPendingMessageIndex >= (mPendingMessageExpectedLength - 1))
        {
            // Reception complete
            mCompleteMessage.Event = MIDI_EVENT(0, getTypeFromStatusByte(mPendingMessage[0]));
            mCompleteMessage.Data1 = mPendingMessage[0]; // status = channel + type
 			mCompleteMessage.Data2 = mPendingMessage[1];

            // Save Data3 only if applicable
            if (mPendingMessageExpectedLength == 3)
                mCompleteMessage.Data3 = mPendingMessage[2];
            else
                mCompleteMessage.Data3 = 0;

            mPendingMessageIndex = 0;
            mPendingMessageExpectedLength = 0;
            mPendingMessageValid = true;
            return;
        }
        else
        {
            // Waiting for more data
            mPendingMessageIndex++;
        }
    }
    else
    {
        // First, test if this is a status byte
        if (extracted >= 0x80)
        {
            // Reception of status bytes in the middle of an uncompleted message
            // are allowed only for interleaved Real Time message or EOX
            switch (extracted)
            {
                case Clock:
                case Start:
                case Continue:
                case Stop:
                case ActiveSensing:
                case SystemReset:

                    // Here we will have to extract the one-byte message,
                    // pass it to the structure for being read outside
                    // the MIDI class, and recompose the message it was
                    // interleaved into. Oh, and without killing the running status..
                    // This is done by leaving the pending message as is,
                    // it will be completed on next calls.
           		 	mCompleteMessage.Event = MIDI_EVENT(0, getTypeFromStatusByte(extracted));
            		mCompleteMessage.Data1 = extracted;
                    mCompleteMessage.Data2 = 0;
                    mCompleteMessage.Data3 = 0;
                   	mPendingMessageValid   = true;
                    return;
                    break;
                default:
                    break;
            }
        }

        // Add extracted data byte to pending message
        mPendingMessage[mPendingMessageIndex] = extracted;

        // Now we are going to check if we have reached the end of the message
        if (mPendingMessageIndex >= (mPendingMessageExpectedLength - 1))
        {

        	mCompleteMessage.Event = MIDI_EVENT(0, getTypeFromStatusByte(mPendingMessage[0]));
            mCompleteMessage.Data1 = mPendingMessage[0];
            mCompleteMessage.Data2 = mPendingMessage[1];

            // Save Data3 only if applicable
            if (mPendingMessageExpectedLength == 3)
                mCompleteMessage.Data3 = mPendingMessage[2];
            else
                mCompleteMessage.Data3 = 0;

            // Reset local variables
            mPendingMessageIndex = 0;
            mPendingMessageExpectedLength = 0;
            mPendingMessageValid = true;

            // Activate running status (if enabled for the received type)
            switch (getTypeFromStatusByte(mPendingMessage[0]))
            {
                case NoteOff:
                case NoteOn:
                case AfterTouchPoly:
                case ControlChange:
                case ProgramChange:
                case AfterTouchChannel:
                case PitchBend:
                    // Running status enabled: store it from received message
                    mRunningStatus_RX = mPendingMessage[0];
                    break;

                default:
                    // No running status
                    mRunningStatus_RX = InvalidType;
                    break;
            }
            return;
        }
        else
        {
            // Not complete? Then update the index of the pending message.
            mPendingMessageIndex++;
        }
    }
}
예제 #8
0
/** Task to read in note on/off messages from the attached MIDI device and print it to the serial port.
 *  When the board joystick or buttons are pressed, note on/off messages are sent to the attached device.
 */
void MIDIHost_Task(void)
{
	if (USB_HostState != HOST_STATE_Configured)
	  return;

	Pipe_SelectPipe(MIDI_DATA_IN_PIPE);
	Pipe_Unfreeze();

	if (Pipe_IsINReceived())
	{
		MIDI_EventPacket_t MIDIEvent;

		Pipe_Read_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL);

		if (!(Pipe_BytesInPipe()))
		  Pipe_ClearIN();

		bool NoteOnEvent  = (MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_ON));
		bool NoteOffEvent = (MIDIEvent.Event == MIDI_EVENT(0, MIDI_COMMAND_NOTE_OFF));

		if (NoteOnEvent || NoteOffEvent)
		{
			printf_P(PSTR("MIDI Note %s - Channel %d, Pitch %d, Velocity %d\r\n"), NoteOnEvent ? "On" : "Off",
																				   ((MIDIEvent.Data1 & 0x0F) + 1),
																				   MIDIEvent.Data2, MIDIEvent.Data3);
		}
	}
	
	Pipe_Freeze();

	Pipe_SelectPipe(MIDI_DATA_OUT_PIPE);
	Pipe_Unfreeze();

	if (Pipe_IsOUTReady())
	{
		uint8_t MIDICommand = 0;
		uint8_t MIDIPitch;

		static uint8_t PrevJoystickStatus;
		uint8_t JoystickStatus  = Joystick_GetStatus();
		uint8_t JoystickChanges = (JoystickStatus ^ PrevJoystickStatus);

		/* Get board button status - if pressed use channel 10 (percussion), otherwise use channel 1 */
		uint8_t Channel = ((Buttons_GetStatus() & BUTTONS_BUTTON1) ? MIDI_CHANNEL(10) : MIDI_CHANNEL(1));

		if (JoystickChanges & JOY_LEFT)
		{
			MIDICommand = ((JoystickStatus & JOY_LEFT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3C;
		}

		if (JoystickChanges & JOY_UP)
		{
			MIDICommand = ((JoystickStatus & JOY_UP)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3D;
		}

		if (JoystickChanges & JOY_RIGHT)
		{
			MIDICommand = ((JoystickStatus & JOY_RIGHT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3E;
		}

		if (JoystickChanges & JOY_DOWN)
		{
			MIDICommand = ((JoystickStatus & JOY_DOWN)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3F;
		}

		if (JoystickChanges & JOY_PRESS)
		{
			MIDICommand = ((JoystickStatus & JOY_PRESS)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF);
			MIDIPitch   = 0x3B;
		}

		/* Check if a MIDI command is to be sent */
		if (MIDICommand)
		{
			MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t)
				{
					.Event       = MIDI_EVENT(0, MIDICommand),

					.Data1       = MIDICommand | Channel,
					.Data2       = MIDIPitch,
					.Data3       = MIDI_STANDARD_VELOCITY,
				};

			/* Write the MIDI event packet to the pipe */
			Pipe_Write_Stream_LE(&MIDIEvent, sizeof(MIDIEvent), NULL);

			/* Send the data in the pipe to the device */
			Pipe_ClearOUT();
		}

		Pipe_Freeze();

		/* Save previous joystick value for next joystick change detection */
		PrevJoystickStatus = JoystickStatus;
	}
}