static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) { uint8_t val; uint8_t i; switch (mpu->playbuf[chan].type) { case T_OVERFLOW: break; case T_MARK: val=mpu->playbuf[chan].sys_val; if (val==0xfc) { midi_write(val); mpu->state.amask&=~(1<<chan); mpu->state.req_mask&=~(1<<chan); } break; case T_MIDI_NORM: for (i=0;i<mpu->playbuf[chan].vlength;i++) midi_write(mpu->playbuf[chan].value[i]); break; default: break; } }
static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) { mpu401_uart_t *mpu = (mpu401_uart_t *)p; if (addr & 1) /*Command*/ { switch (val) { case 0xff: /*Reset*/ mpu->rx_data = 0xfe; /*Acknowledge*/ mpu->status = 0; mpu->uart_mode = 0; break; case 0x3f: /*Enter UART mode*/ mpu->rx_data = 0xfe; /*Acknowledge*/ mpu->status = 0; mpu->uart_mode = 1; break; } return; } /*Data*/ if (mpu->uart_mode) midi_write(val); }
static void sendexclusive(CMMIDI midi, const UINT8 *buf, UINT leng) { CopyMemory(midi->excvbuf, buf, leng); midi_write(midi, midi->excvbuf, leng); midi->midiexcvwait = 1; }
int main(int argc, char *argv[]) { struct midi m; struct pollfd pt[8]; if (argc != 2) { fprintf(stderr, "usage: %s <device>\n", argv[0]); return -1; } if (midi_open(&m, argv[1]) == -1) return -1; for (;;) { ssize_t z; char buf[32]; z = midi_pollfds(&m, pt, ARRAY_SIZE(pt)); if (z == -1) return -1; fputs("poll...\n", stderr); if (poll(pt, z, -1) == -1) { perror("poll"); return -1; } fputs("... return\n", stderr); for (;;) { size_t n; ssize_t z; z = midi_read(&m, buf, sizeof buf); if (z == -1) return -1; if (z == 0) break; for (n = 0; n < z; n++) printf(" %02hhx", buf[n]); z = midi_write(&m, buf, z); printf(" =%d", z); if (z == -1) return -1; } printf("\n"); fflush(stdout); } midi_close(&m); }
static void midiout_device(CMMIDI midi, UINT32 msg, UINT cnt) { UINT8 buf[3]; UINT i; for (i = 0; i < cnt; i++, msg >>= 8) { buf[i] = msg & 0xff; } waitlastexclusiveout(midi); midi_write(midi, buf, cnt); }
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; } }
static void dspio_process_midi(struct dspio_state *state) { Bit8u data; /* no timing for now */ while (!dspio_midi_output_empty(state)) { data = dspio_get_midi_data(state); midi_write(data); } while (midi_get_data_byte(&data)) { dspio_put_midi_in_byte(state, data); sb_handle_midi_data(); } }
// build and send a midi serial packet void op_midi_out_cc_send_packet( op_midi_out_cc_t* mout ) { u8 pack[3]; // control change: high nib = 1011 pack[0] = 0xb0; // low nib = channel pack[0] |= (u8)(mout->chan & 0x0f); // two data bytes: number, value pack[1] = (u8)(mout->num); pack[2] = (u8)(mout->val); /* print_dbg("\r\n midi_out_cc_send_packet; data: "); */ /* print_dbg_char_hex(pack[0]); print_dbg(" "); */ /* print_dbg_char_hex(pack[1]); print_dbg(" "); */ /* print_dbg_char_hex(pack[2]); print_dbg(" "); */ midi_write(pack, 3); }
// build and send a midi serial packet void op_midi_out_note_send_packet( op_midi_out_note_t* mout ) { u8 pack[3]; if(mout->vel == 0) { // note on/off pack[0] = 0x80; } else { pack[0] = 0x90; } pack[0] |= (u8)(mout->chan & 0x0f); pack[1] = (u8)(mout->num); pack[2] = (u8)(mout->vel); print_dbg("\r\n midi_out_note_send_packet; data: "); print_dbg_char_hex(pack[0]); print_dbg(" "); print_dbg_char_hex(pack[1]); print_dbg(" "); print_dbg_char_hex(pack[2]); print_dbg(" "); midi_write(pack, 3); }
static void MPU401_WriteData(mpu_t *mpu, uint8_t val) { if (mpu->mode==M_UART) {midi_write(val); return;} switch (mpu->state.command_byte) { /* 0xe# command data */ case 0x00: break; case 0xe0: /* Set tempo */ mpu->state.command_byte=0; mpu->clock.tempo=val; return; case 0xe1: /* Set relative tempo */ mpu->state.command_byte=0; if (val!=0x40) //default value pclog("MPU-401:Relative tempo change not implemented\n"); return; case 0xe7: /* Set internal clock to host interval */ mpu->state.command_byte=0; mpu->clock.cth_rate=val>>2; return; case 0xec: /* Set active track mask */ mpu->state.command_byte=0; mpu->state.tmask=val; return; case 0xed: /* Set play counter mask */ mpu->state.command_byte=0; mpu->state.cmask=val; return; case 0xee: /* Set 1-8 MIDI channel mask */ mpu->state.command_byte=0; mpu->state.midi_mask&=0xff00; mpu->state.midi_mask|=val; return; case 0xef: /* Set 9-16 MIDI channel mask */ mpu->state.command_byte=0; mpu->state.midi_mask&=0x00ff; mpu->state.midi_mask|=((uint16_t)val)<<8; return; //case 0xe2: /* Set graduation for relative tempo */ //case 0xe4: /* Set metronome */ //case 0xe6: /* Set metronome measure length */ default: mpu->state.command_byte=0; return; } static int length,cnt,posd; if (mpu->state.wsd) { /* Directly send MIDI message */ if (mpu->state.wsd_start) { mpu->state.wsd_start=0; cnt=0; switch (val&0xf0) { case 0xc0:case 0xd0: mpu->playbuf[mpu->state.channel].value[0]=val; length=2; break; case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0: mpu->playbuf[mpu->state.channel].value[0]=val; length=3; break; case 0xf0: //pclog("MPU-401:Illegal WSD byte\n"); mpu->state.wsd=0; mpu->state.channel=mpu->state.old_chan; return; default: /* MIDI with running status */ cnt++; midi_write(mpu->playbuf[mpu->state.channel].value[0]); } } if (cnt<length) {midi_write(val);cnt++;} if (cnt==length) { mpu->state.wsd=0; mpu->state.channel=mpu->state.old_chan; } return; } if (mpu->state.wsm) { /* Directly send system message */ if (val==MSG_EOX) {midi_write(MSG_EOX);mpu->state.wsm=0;return;} if (mpu->state.wsd_start) { mpu->state.wsd_start=0; cnt=0; switch (val) { case 0xf2:{ length=3; break;} case 0xf3:{ length=2; break;} case 0xf6:{ length=1; break;} case 0xf0:{ length=0; break;} default: length=0; } } if (!length || cnt<length) {midi_write(val);cnt++;} if (cnt==length) mpu->state.wsm=0; return; } if (mpu->state.cond_req) { /* Command */ switch (mpu->state.data_onoff) { case -1: return; case 0: /* Timing byte */ mpu->condbuf.vlength=0; if (val<0xf0) mpu->state.data_onoff++; else { mpu->state.data_onoff=-1; MPU401_EOIHandlerDispatch(mpu); return; } if (val==0) mpu->state.send_now=1; else mpu->state.send_now=0; mpu->condbuf.counter=val; break; case 1: /* Command byte #1 */ mpu->condbuf.type=T_COMMAND; if (val==0xf8 || val==0xf9) mpu->condbuf.type=T_OVERFLOW; mpu->condbuf.value[mpu->condbuf.vlength]=val; mpu->condbuf.vlength++; if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(mpu); else mpu->state.data_onoff++; break; case 2:/* Command byte #2 */ mpu->condbuf.value[mpu->condbuf.vlength]=val; mpu->condbuf.vlength++; MPU401_EOIHandlerDispatch(mpu); break; } return; } switch (mpu->state.data_onoff) { /* Data */ case -1: return; case 0: /* Timing byte */ if (val<0xf0) mpu->state.data_onoff=1; else { mpu->state.data_onoff=-1; MPU401_EOIHandlerDispatch(mpu); return; } if (val==0) mpu->state.send_now=1; else mpu->state.send_now=0; mpu->playbuf[mpu->state.channel].counter=val; break; case 1: /* MIDI */ mpu->playbuf[mpu->state.channel].vlength++; posd=mpu->playbuf[mpu->state.channel].vlength; if (posd==1) { switch (val&0xf0) { case 0xf0: /* System message or mark */ if (val>0xf7) { mpu->playbuf[mpu->state.channel].type=T_MARK; mpu->playbuf[mpu->state.channel].sys_val=val; length=1; } else { //LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message"); mpu->playbuf[mpu->state.channel].type=T_MIDI_SYS; mpu->playbuf[mpu->state.channel].sys_val=val; length=1; } break; case 0xc0: case 0xd0: /* MIDI Message */ mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; length=mpu->playbuf[mpu->state.channel].length=2; break; case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; length=mpu->playbuf[mpu->state.channel].length=3; break; default: /* MIDI data with running status */ posd++; mpu->playbuf[mpu->state.channel].vlength++; mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; length=mpu->playbuf[mpu->state.channel].length; break; } } if (!(posd==1 && val>=0xf0)) mpu->playbuf[mpu->state.channel].value[posd-1]=val; if (posd==length) MPU401_EOIHandlerDispatch(mpu); } }
static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { uint8_t i; if (mpu->state.reset) { mpu->state.cmd_pending=val+1; return; } if (val<=0x2f) { switch (val&3) { /* MIDI stop, start, continue */ case 1: {midi_write(0xfc);break;} case 2: {midi_write(0xfa);break;} case 3: {midi_write(0xfb);break;} } // if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",(int)val); switch (val&0xc) { case 0x4: /* Stop */ mpu->state.playing=0; mpu401_event_callback = 0; for (i=0xb0;i<0xbf;i++) { /* All notes off */ midi_write(i); midi_write(0x7b); midi_write(0); } break; case 0x8: /* Play */ // LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started"); mpu->state.playing=1; mpu401_event_callback = (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000 * TIMER_USEC; ClrQueue(mpu); break; } } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ if (mpu->state.cmask&(1<<(val&7))) QueueByte(mpu, mpu->playbuf[val&7].counter); } else if (val>=0xd0 && val<=0xd7) { /* Send data */ mpu->state.old_chan=mpu->state.channel; mpu->state.channel=val&7; mpu->state.wsd=1; mpu->state.wsm=0; mpu->state.wsd_start=1; } else switch (val) { case 0xdf: /* Send system message */ mpu->state.wsd=0; mpu->state.wsm=1; mpu->state.wsd_start=1; break; case 0x8e: /* Conductor */ mpu->state.cond_set=0; break; case 0x8f: mpu->state.cond_set=1; break; case 0x94: /* Clock to host */ mpu->clock.clock_to_host=0; break; case 0x95: mpu->clock.clock_to_host=1; break; case 0xc2: /* Internal timebase */ mpu->clock.timebase=48; break; case 0xc3: mpu->clock.timebase=72; break; case 0xc4: mpu->clock.timebase=96; break; case 0xc5: mpu->clock.timebase=120; break; case 0xc6: mpu->clock.timebase=144; break; case 0xc7: mpu->clock.timebase=168; break; case 0xc8: mpu->clock.timebase=192; break; /* Commands with data byte */ case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: mpu->state.command_byte=val; break; /* Commands 0xa# returning data */ case 0xab: /* Request and clear recording counter */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, 0); return; case 0xac: /* Request version */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, MPU401_VERSION); return; case 0xad: /* Request revision */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, MPU401_REVISION); return; case 0xaf: /* Request tempo */ QueueByte(mpu, MSG_MPU_ACK); QueueByte(mpu, mpu->clock.tempo); return; case 0xb1: /* Reset relative tempo */ mpu->clock.tempo_rel=40; break; case 0xb9: /* Clear play map */ case 0xb8: /* Clear play counters */ for (i=0xb0;i<0xbf;i++) { /* All notes off */ midi_write(i); midi_write(0x7b); midi_write(0); } for (i=0;i<8;i++) { mpu->playbuf[i].counter=0; mpu->playbuf[i].type=T_OVERFLOW; } mpu->condbuf.counter=0; mpu->condbuf.type=T_OVERFLOW; if (!(mpu->state.conductor=mpu->state.cond_set)) mpu->state.cond_req=0; mpu->state.amask=mpu->state.tmask; mpu->state.req_mask=0; mpu->state.irq_pending=1; break; case 0xff: /* Reset MPU-401 */ pclog("MPU-401:Reset %X\n",val); mpu401_reset_callback = MPU401_RESETBUSY * 33 * TIMER_USEC; mpu->state.reset=1; MPU401_Reset(mpu); #if 0 if (mpu->mode==M_UART) return;//do not send ack in UART mode #endif break; case 0x3f: /* UART mode */ pclog("MPU-401:Set UART mode %X\n",val); mpu->mode=M_UART; break; default:; //LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val); } QueueByte(mpu, MSG_MPU_ACK); }