1 /************************************************************************
2  * seq2mid.c - converts dump of /dev/sequencer (aka toy.c ouput) to a
3  * type 0 midi file.
4  *
5  * This code was written by by Nathan Laredo (laredo@gnu.ai.mit.edu)
6  * Source code may be freely distributed in unmodified form.
7  *************************************************************************/
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <sys/soundcard.h>
13 
14 int outfile, infile;
15 
16 /*
17  * midi header, track header, and timing info.  Given timing is good for
18  * /dev/sequencer tick of 100Hz.  Adjust division for others.
19  */
20 
21 #define FLUFFSIZE 29
22 unsigned char midifluff[FLUFFSIZE] =
23 { 0x4d, 0x54, 0x68, 0x64,	/* MThd */
24   0x00, 0x00, 0x00, 0x06,	/* 6 bytes in header block */
25   0x00, 0x00,			/* midi format 0 */
26   0x00, 0x01,			/* one track */
27 /* the following line is for a 100Hz sequencer tick, adjust accordingly */
28   0x00, 0x32,			/* 50 ticks per quarter, 100Hz resolution */
29   0x4d, 0x54, 0x72, 0x6b,	/* MTrk */
30 #define SIZEINDEX 18
31   0x00, 0x00, 0x00, 0x00,	/* x bytes in track block */
32   0x00,	0xff, 0x51, 0x03,	/* meta tempo event */
33   0x07, 0xA1, 0x20		/* one quarter note = .5 sec = 120bpm */
34 #define STARTCOUNT 7
35   };
36 
37 #define ENDFLUFFSIZE 4
38 unsigned char endfluff[ENDFLUFFSIZE] =
39 { 0x00, 0xff, 0x2f, 0x00 };	/* meta end of track */
40 
41 /* indexed by high nibble of command */
42 int cmdlen[16] =
43 {0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0};
44 
midiwrite(buf,count)45 void midiwrite(buf, count)
46 unsigned char *buf;
47 int count;
48 {
49     if(write(outfile, buf, count) < count) {
50 	perror("write");
51 	exit(-1);
52     }
53 }
54 
main(argc,argv)55 int main(argc, argv)
56 int argc;
57 char **argv;
58 {
59     unsigned char delta[4], inputbuf[5], mid[8], cmd = 0;
60     unsigned int oldticks = 0, ticks = 0, db = 0;
61     off_t filesize, tracksize;
62     int i, status = 0;
63 
64     if (argc < 3) {
65 	fprintf(stderr, "usage: %s infile.seq outfile.mid\n", argv[0]);
66 	exit(1);
67     }
68     if ((infile = open(argv[1], O_RDONLY, 0)) < 0) {
69 	perror(argv[1]);
70 	exit(-1);
71     }
72     if ((outfile = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666))
73 	< 0) {
74 	perror(argv[2]);
75 	exit(-1);
76     }
77     midiwrite(midifluff, FLUFFSIZE);
78     inputbuf[4] = 0;
79     while (read(infile, inputbuf, 4) == 4) {
80 	if (inputbuf[0] == SEQ_WAIT)
81 	    ticks = (*(unsigned int *) &inputbuf[1]);
82 	if (*inputbuf == SEQ_MIDIPUTC) {
83 	    if (inputbuf[1] & 0x80)
84 		cmd = mid[db = 0] = inputbuf[1];
85 	    else
86 		mid[db] = inputbuf[1];
87 	    db++;
88 	    if (db == cmdlen[cmd >> 4] + 1) {
89 		register unsigned int buffer = ticks - oldticks;
90 		delta[i = 3] = (buffer & 0x7f);
91 		while ((buffer >>= 7) > 0 && i > 0)
92 		    delta[--i] = (buffer & 0x7f) | 0x80;
93 		midiwrite(&delta[i], 4 - i);
94 		if (status == cmd && cmd < 0xf0)
95 		    midiwrite(&mid[1], db - 1);
96 		else
97 		    midiwrite(mid, db);
98 		status = mid[0];
99 		oldticks = ticks;
100 		db = 1;
101 	    }
102 	}
103     }
104     midiwrite(endfluff, ENDFLUFFSIZE);
105 
106     /* write big endian track size */
107     filesize = lseek(outfile, 0, SEEK_CUR);
108     tracksize = filesize - FLUFFSIZE + STARTCOUNT;
109     lseek(outfile, SIZEINDEX, SEEK_SET);
110     delta[0] = (tracksize >> 24) & 0xff;
111     delta[1] = (tracksize >> 16) & 0xff;
112     delta[2] = (tracksize >> 8) & 0xff;
113     delta[3] = tracksize & 0xff;
114     midiwrite(delta, 4);
115     close(infile);
116     close(outfile);
117     printf("%s: saved as %s, %d bytes, %d bytes track data\n",
118 	   argv[1], argv[2], (int) filesize, (int) tracksize);
119     exit(0);
120 }
121 /* end of file */
122