/* Midi-Output: you have to write complete commands to the driver, if a command is 10 bytes long you can't write() 5 bytes now and the other 5 bytes later. This is why 'cat file > /dev/mpu401' will not work. A command starts with a byte, that tells the driver the length of the mpu-data and where to put it. Bits 0..5: length of MPU-Data following. Bits 6..7: 00 : send later on Track Data Request Interrupt (0xF0-0xF6, 7 tracks supported, track number follows leading byte) 01 : write immediately to Data Register 10 : write immediately to Command Register 11 : driver command: 0xc0 = reset everything #define TRK (0<<6) #define DAT (1<<6) #define CMD (2<<6) #define RES (3<<6) Examlpe (plays some notes, sounds horrible :) -------------------------------- mpudemo.c ----------------------------------- */ #include #include #include #include #include #include #define TRK (0<<6) #define DAT (1<<6) #define CMD (2<<6) #define RES (3<<6) #define TRACK 0 int mpu_fd; int out_chn = 0; int nfds; fd_set rfds; unsigned char filebuf[BUFSIZ]; int filebytes; unsigned char *recbuf[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; int bytes_in_recbuf[7] = {0, 0, 0, 0, 0, 0, 0}; int size_of_recbuf[7] = {0, 0, 0, 0, 0, 0, 0}; int cur_track = 0; char tempo[] = { CMD+1, 0xe0, DAT+1, 120 }; char init_mpu[] = { RES, /* reset device */ CMD+1, 0x34, /* send timing byte always */ CMD+1, 0x8e, /* conductor off */ CMD+1, 0x8c, /* don't send measures while recording */ CMD+1, 0x98, CMD+1, 0x9a, CMD+1, 0x9c, CMD+1, 0x9e, /* channel ref off */ }; char init2_mpu[] = { CMD+1, 0x34, /* send timing byte always */ CMD+1, 0x8e, /* conductor off */ CMD+1, 0x8c, /* don't send measures while recording */ CMD+1, 0x98, CMD+1, 0x9a, CMD+1, 0x9c, CMD+1, 0x9e, /* channel ref off */ }; char set_track_active[] = { CMD+1, 0xec, DAT+1, 0x01 }; char clear_play_count[] = { CMD+1, 0xb8 }; char clear_rec_count[] = { CMD+1, 0xbA }; char start[] = { CMD+1, 0x2a /* start record/play */ }; char stop[] = { CMD+1, 0x15 /* stop record/play */ }; char clk[] = { TRK+2, TRACK, 0xf8 }; char prog_change [] = { TRK+4, TRACK, 0x00, 0xc0, 0x00 }; int store(int track, unsigned char ch) { if (bytes_in_recbuf[track] >= size_of_recbuf[track]) { recbuf[track] = (unsigned char*) realloc(recbuf[track], size_of_recbuf[track] + BUFSIZ); size_of_recbuf[track] += BUFSIZ; if (! recbuf[track]) return 0; } recbuf[track][bytes_in_recbuf[track]++] = ch; return 1; } int read_mpu(void) { fd_set rfds; struct timeval timeout; int res, k; unsigned char ch; FD_ZERO(&rfds); FD_SET(mpu_fd, &rfds ); timeout.tv_sec = 0; timeout.tv_usec = 0; res = select(mpu_fd + 1, &rfds, NULL, NULL, &timeout); if (res <= 0) return 1; if (! FD_ISSET(mpu_fd, &rfds)) return 1; /* Read from file (blocking) */ filebytes = read(mpu_fd, filebuf, BUFSIZ); if ( filebytes == -1 ) { fprintf(stderr, "mpu device read error\n"); return 0; } /* Write to recbuffer and send clock_to_host_byte to socket */ if (filebytes > 0) { for (k = 0; k < filebytes; k++) { ch = filebuf[k]; if (ch == 0xff) continue; /* I sometimes get these 0xff bytes, don't know why but they are of no use */ /* clock-to-host received ? */ if (ch == 0xfd) { printf("host clock\n"); } else if ( (ch == 0xfa) || (ch == 0xfb) || (ch == 0xfc) ) { /* Real time message */ } else if (ch == 0xf2) { /* Song pointer received */ } else { /* record byte received; write to recbuffer */ if (! store(cur_track, ch)) return 0; } } } return 1; } #define MAXTRIES 100000 int dwrite(int fd, char *buf, int len) { int bytes, written = 0, i; for (i = 0; i < MAXTRIES; i++) { bytes = write(fd, buf + written, len - written); if (bytes > 0) written = written + bytes; if (written >= len) break; } if (i >= MAXTRIES) { fprintf(stderr, "mpu write failed.\n"); exit (1); } return len; } void change_prog(int chn, int prog) { prog_change[3] = 0xc0 + chn; prog_change[4] = prog; dwrite(mpu_fd, prog_change, sizeof(prog_change)); } int play_track(int track) { int i, n = 0, len; unsigned char c, delta; unsigned char mpubuf[15]; mpubuf[0] = TRK; mpubuf[1] = track; while (1) { c = recbuf[track][n++]; mpubuf[2] = c; if (c == 0xf8) { mpubuf[0] += 2; dwrite(mpu_fd, mpubuf, 3); mpubuf[0] = TRK; continue; } c = recbuf[track][n]; if (c >= 0x80) { recbuf[track][n] += out_chn; len = 3; } else len = 2; mpubuf[0] += (len + 2); for (i = 0; i < len; i++) mpubuf[3 + i] = recbuf[track][n++]; #ifdef DEBUG for (i = 0; i < len + 3; i++) printf("%02x ", mpubuf[i]); printf("\n"); #endif dwrite(mpu_fd, mpubuf, len + 3); mpubuf[0] = TRK; if (n >= bytes_in_recbuf[track]) break; } } void rec_play(int play) { clock_t clk; int i; printf("%d\n", bytes_in_recbuf[0]); printf("%d\n", bytes_in_recbuf[1]); /* if (play) { for (i = 0; i < 7; i++) { if (bytes_in_recbuf[i]) play_track(i); } } */ clk = clock(); while (1) { if (! read_mpu()) { fprintf(stderr, "read mpu failed\n"); return; } if ((clock() - clk) >= (CLOCKS_PER_SEC * 10)) break; } } void set_active_tracks(int tracks) { set_track_active[3] = tracks; dwrite(mpu_fd, set_track_active, sizeof(set_track_active)); } void clear_count(void) { dwrite(mpu_fd, clear_play_count, sizeof(clear_play_count)); /* dwrite(mpu_fd, clear_rec_count, sizeof(clear_rec_count)); */ } int main(void) { int i, j; mpu_fd = open("/dev/mpu401", O_RDWR); if (mpu_fd < 0) { printf("Device %d\n", mpu_fd); return 1; } for (i = 0; i < 7; i++) { recbuf[i] = (unsigned char*) malloc(BUFSIZ); size_of_recbuf[i] = BUFSIZ; bytes_in_recbuf[i] = 0; } dwrite(mpu_fd, init_mpu, sizeof(init_mpu)); out_chn = 1; change_prog(1, 32); printf("Now recording track 0...\n"); set_active_tracks(0); cur_track = 0; // clear_count(); dwrite(mpu_fd, start, sizeof(start)); rec_play(1); dwrite(mpu_fd, stop, sizeof(stop)); printf("Now recording track 1...\n"); set_active_tracks(1); clear_count(); dwrite(mpu_fd, start, sizeof(start)); cur_track = 1; rec_play(1); dwrite(mpu_fd, stop, sizeof(stop)); printf("Now playing...\n"); set_active_tracks(3); // clear_count(); dwrite(mpu_fd, start, sizeof(start)); cur_track = 6; rec_play(1); dwrite(mpu_fd, stop, sizeof(stop)); printf("Done, press \n"); error: getchar(); for (i = 0; i < 7; i++) free(recbuf[i]); close(mpu_fd); return 0; } .