Hi,
I have made a small program to read out MIDI commands for my Numark iDJLive II,
DJ mixer (USB). I got rid of all my Apple software on Apple Hardware and there
I had used Algoriddim DJ Pro software to take commands from this mixer.
I pretty well made a crossfader and menu out of curses to make something like
it and did some reverse engineering to get the controls for the MIDI output
of the iDJLive II equipment. Granted not everyone has this hardware so I'm
trying my best to explain what I'm doing by giving the source code of this.
Basically the program works with 2 childs, where one child is the foreground
and does the curses and input output to the mixer and the other child waits
for commands passed to it via a shared memory (mmap). I can't manage to
get it to make a sound when I select a song on the right play pad (#2), the
worst I hear is just a small pop of the speakers and then silence so I'm
doing something wrong. Let me explain the program lines and then I'll paste
the program itself maybe someone who is experienced with music and sndio can
help me a little?
lines
263-282 - set up the mmap's for 100 MB each (this is both sides of the cross
fader)
283 - is where it forks and the child continues on to waiting instructions to
play what's in the mmap
299 - indicates where I'M having some problems feeding data to sio_setpar()
the data stems from data gotten through getheader() which parses
WAV files and placed at offset 2 on the mmap.
The action at this point is really in the child and I don't know what I'm
doing wrong so lines 283 through 340 which is in a continuous loop. Obviously
the program isn't finished but I was hoping I'd pad out the rest when I'd get
something playing on #2 at least.
If you do have this equipment and start it, wiggle the crossfader a little for
it to flash the leds for a while and then it will list any .WAV's to be selected
with the "push" button, the "browse" buttons will select the songs of which
only #2 is currently programmed to do anything.
If I get this equipment working, I have another DJ mixer which is more portable
that has different MIDI commands that I still need to sit down on and figure
out. But I figured I'd make one work first before working on the other.
Thanks for any hints regarding the playing of the WAV, the program follows, it
gets built with:
cc -g -o numark numark.c -lsndio -lcurses
Regards,
-peter
1 /*
2 * Copyright (c) 2020 Peter J. Philipp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
the
12 * documentation and/or other materials provided with the
distribution.
13 * 3. The name of the author may not be used to endorse or promote
products
14 * derived from this software without specific prior written
permission
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 #include <sys/param.h>
30 #include <sys/select.h>
31 #include <sys/mman.h>
32
33 #include <dirent.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <ncurses.h>
41 #include <sndio.h>
42 #include <signal.h>
43
44
45
46
47
48 #define INQUIRESTRING "\xF0\x7E\x00\x06\x01\xF7" /* MMC device
enquiry */
49 #define INQUIRESTRINGLEN 6
50
51 #define HUNDREDMB (100 * 1024 * 1024)
52
53 #define MIDI_NOTEON 0x90
54 #define MIDI_NOTEOFF 0x80
55
56 #define BUTTON_DOWN 0x90
57 #define BUTTON_UP 0x80
58 #define FADER 0xb0
59
60 #define NUMARK_DEVICE_2E_LEFTVOLUME 0x8
61 #define NUMARK_DEVICE_2E_RIGHTVOLUME 0x9
62 #define NUMARK_DEVICE_2E_CROSSFADER 0xA
63 #define NUMARK_DEVICE_2E_LEFTPITCH 0xD
64 #define NUMARK_DEVICE_2E_RIGHTPITCH 0xE
65 #define NUMARK_DEVICE_2E_LEFTTREBLE 0x10
66 #define NUMARK_DEVICE_2E_RIGHTTREBLE 0x11
67 #define NUMARK_DEVICE_2E_LEFTBASS 0x14
68 #define NUMARK_DEVICE_2E_RIGHTBASS 0x15
69 #define NUMARK_DEVICE_2E_MASTERVOLUME 0x17
70 #define NUMARK_DEVICE_2E_RIGHTWHEEL 0x18
71 #define NUMARK_DEVICE_2E_LEFTWHEEL 0x19
72 #define NUMARK_DEVICE_2E_BROWSE 0x1A
73 #define NUMARK_DEVICE_2E_LEFTCUE 0x33
74 #define NUMARK_DEVICE_2E_RIGHTLOAD 0x34
75 #define NUMARK_DEVICE_2E_LEFTRETURNTOCUE 0x3B
76 #define NUMARK_DEVICE_2E_RIGHTCUE 0x3C
77 #define NUMARK_DEVICE_2E_LEFTSYNC 0x40
78 #define NUMARK_DEVICE_2E_RIGHTRETURNTOCUE 0x42
79 #define NUMARK_DEVICE_2E_LEFTPITCHBENDPLUS 0x43
80 #define NUMARK_DEVICE_2E_LEFTPITCHBENDMINUS 0x44
81 #define NUMARK_DEVICE_2E_RIGHTPITCHBENDPLUS 0x45
82 #define NUMARK_DEVICE_2E_RIGHTPITCHBENDMINUS 0x46
83 #define NUMARK_DEVICE_2E_RIGHTSYNC 0x47
84 #define NUMARK_DEVICE_2E_SCRATCH 0x48
85 #define NUMARK_DEVICE_2E_LEFTPLAY 0x4A
86 #define NUMARK_DEVICE_2E_LEFTLOAD 0x4B
87 #define NUMARK_DEVICE_2E_RIGHTPLAY 0x4C
88 #define NUMARK_DEVICE_2E_LEFTWHEELTAP 0x4D
89 #define NUMARK_DEVICE_2E_RIGHTWHEELTAP 0x4E
90 #define NUMARK_DEVICE_2E_BROWSEPUSHBUTTON 0x4F
91
92 struct midi_reply {
93 u_int8_t nrm; /* non real-time message */
94 u_int8_t channel; /* channel to inquire */
95 u_int8_t inquiry; /* inquiry message */
96 u_int8_t response; /* inquiry response */
97 };
98
99 struct midi_manuf {
100 u_int8_t manufacturer[3];
101 u_int8_t product;
102 };
103
104 struct midi_len {
105 u_int8_t hibyte;
106 u_int8_t lobyte;
107 };
108
109 struct reply {
110 uint32_t version;
111 uint8_t devid;
112 uint32_t serial;
113 char manufacturer[16];
114 };
115
116 struct mywav {
117 char *map;
118 size_t size;
119 size_t songsize;
120 off_t pos;
121 };
122
123 struct wff {
124 char id[4]; /* RIFF */
125 uint32_t chunksize; /* chunk size */
126 char waveid[4]; /* wave id */
127 } waveheader;
128
129 struct chk {
130 char chunkid[4]; /* "fmt " */
131 uint32_t cksize; /* chunk size 16, 18, or 40 */
132 } chunkheader;
133
134 struct fmt16 {
135 char chunkid[4]; /* "fmt " */
136 uint32_t cksize; /* chunk size 16, 18, or 40 */
137 uint16_t fcode; /* format code */
138 uint16_t channels; /* number of channels */
139 uint32_t sps; /* samples per second */
140 uint32_t datarate; /* datarate */
141 uint16_t datablock; /* data block size */
142 uint16_t bps; /* bits per sample */
143
144 uint16_t size; /* size of extension */
145 uint16_t validbits; /* valid # of bits */
146 uint16_t channelmask; /* mask of speaker position */
147 char subformat[16]; /* GUID */
148 } format16;
149
150 struct mywaveheader {
151 struct wff waveheader;
152 struct chk chunkheader;
153 struct fmt16 formathdr;
154 struct chk filler;
155 struct chk data;
156
157 uint32_t dataoffset;
158 };
159
160 struct numarktab {
161 int id;
162 char *string;
163 } myntab[] = { { NUMARK_DEVICE_2E_LEFTVOLUME, "left volume" },
164 { NUMARK_DEVICE_2E_RIGHTVOLUME, "right volume" },
165 { NUMARK_DEVICE_2E_CROSSFADER, "crossfader" },
166 { NUMARK_DEVICE_2E_LEFTPITCH, "left pitch" },
167 { NUMARK_DEVICE_2E_RIGHTPITCH, "right pitch" },
168 { NUMARK_DEVICE_2E_LEFTTREBLE, "left treble" },
169 { NUMARK_DEVICE_2E_RIGHTTREBLE, "right treble" },
170 { NUMARK_DEVICE_2E_LEFTBASS, "left bass" },
171 { NUMARK_DEVICE_2E_RIGHTBASS, "right bass" },
172 { NUMARK_DEVICE_2E_MASTERVOLUME, "master volume" },
173 { NUMARK_DEVICE_2E_RIGHTWHEEL, "right wheel" },
174 { NUMARK_DEVICE_2E_LEFTWHEEL, "left wheel" },
175 { NUMARK_DEVICE_2E_BROWSE, "browse" },
176 { NUMARK_DEVICE_2E_LEFTCUE, "left cue" },
177 { NUMARK_DEVICE_2E_RIGHTLOAD, "right load" },
178 { NUMARK_DEVICE_2E_LEFTRETURNTOCUE, "left return to cue" },
179 { NUMARK_DEVICE_2E_RIGHTCUE, "right cue" },
180 { NUMARK_DEVICE_2E_LEFTSYNC, "left sync" },
181 { NUMARK_DEVICE_2E_RIGHTRETURNTOCUE, "right return to cue" },
182 { NUMARK_DEVICE_2E_LEFTPITCHBENDPLUS, "left pitch bend plus" },
183 { NUMARK_DEVICE_2E_LEFTPITCHBENDMINUS, "left pitch bend minus"
},
184 { NUMARK_DEVICE_2E_RIGHTPITCHBENDPLUS, "right pitch bend plus"
},
185 { NUMARK_DEVICE_2E_RIGHTPITCHBENDMINUS, "right pitch bend
minus" },
186 { NUMARK_DEVICE_2E_RIGHTSYNC, "right sync" },
187 { NUMARK_DEVICE_2E_SCRATCH, "scratch" },
188 { NUMARK_DEVICE_2E_LEFTPLAY, "left play" },
189 { NUMARK_DEVICE_2E_LEFTLOAD, "left load" },
190 { NUMARK_DEVICE_2E_RIGHTPLAY, "right play" },
191 { NUMARK_DEVICE_2E_LEFTWHEELTAP, "left wheel tap" },
192 { NUMARK_DEVICE_2E_RIGHTWHEELTAP, "right wheel tap" },
193 { NUMARK_DEVICE_2E_BROWSEPUSHBUTTON, "browse push button" }};
194
195
196 /* prototypes */
197 int probe_midi(int, struct midi_manuf *);
198 char * numark_controllid(u_int8_t id);
199 int update_fader(WINDOW *crossfader, u_int8_t command);
200 int write_songs(WINDOW *, int);
201 char * get_songs(int selected);
202 struct mywaveheader * getheader(int);
203 void set_led_on(int midi, int deviceid);
204 void set_led_off(int midi, int deviceid);
205
206 /* defines */
207 WINDOW *mixerwindow;
208
209 int
210 main(void)
211 {
212 char buf[512];
213 char *song;
214
215 struct mywaveheader *waveheader, *lwavhdr, *rwavhdr;
216 struct mywav leftwav, rightwav;
217 struct midi_manuf mm;
218 struct sio_hdl *hdl;
219 struct sio_par spar;
220
221 int midi;
222 int sel;
223 int i, fd;
224 int len;
225 int faderpos = 50;
226 int leftvolume = 127;
227 int rightvolume = 127;
228 int selectedsong = 1;
229 int rightplay = 0;
230 int leftplay = 0;
231 uint32_t *loffset, *roffset;
232
233
234 fd_set rset;
235 pid_t pid;
236
237 u_int8_t command[3];
238
239 WINDOW *crossfader, *songselect, *leftsong, *rightsong;
240 off_t offset;
241
242 initscr();
243 cbreak();
244 noecho();
245
246 start_color();
247
248 init_pair(COLOR_BLACK, COLOR_BLACK, 0);
249 init_pair(COLOR_GREEN, COLOR_GREEN, 0);
250 init_pair(COLOR_RED, COLOR_RED, 0);
251
252 mixerwindow = newwin(23, 80, 0, 0);
253 idlok(mixerwindow, TRUE);
254 scrollok(mixerwindow, TRUE);
255
256 wclear(mixerwindow);
257 wrefresh(mixerwindow);
258
259 wattrset(mixerwindow, COLOR_PAIR(COLOR_GREEN));
260
261 /* start the program */
262
263 leftwav.map = (char *)mmap(NULL, HUNDREDMB + 2 + sizeof(struct
mywaveheader), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
264 if (leftwav.map == MAP_FAILED) {
265 perror("mmap");
266 exit(1);
267 }
268 leftwav.size = HUNDREDMB;
269 leftwav.map[0] = '*';
270 leftwav.map[1] = 127;
271 lwavhdr = (struct mywaveheader *)&leftwav.map[2];
272
273 rightwav.map = (char *)mmap(NULL, HUNDREDMB + 2 + sizeof(struct
mywaveheader), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
274 if (rightwav.map == MAP_FAILED) {
275 perror("mmap");
276 exit(1);
277 }
278 rightwav.size = HUNDREDMB;
279 rightwav.map[0] = '*';
280 rightwav.map[1] = 127;
281 rwavhdr = (struct mywaveheader *)&rightwav.map[2];
282
283 pid = fork();
284 /* ze child */
285 if (pid == 0) {
286 for (;;) {
287 while (rightwav.map[0] == '*')
288 usleep(40);
289
290 hdl = sio_open("snd/0", SIO_PLAY, 0);
291 if (hdl == NULL) {
292 perror("sio_open");
293 killpg(-1, SIGINT);
294 }
295
296 sio_initpar(&spar);
297 spar.rate = rwavhdr->formathdr.datarate;
298 #if 0
299 THIS IS THE PART WHERE I'M HAVING PROBLEMS
300
301 spar.rate = 44100;
302 spar.bits = 16;
303 spar.pchan = 2;
304 spar.appbufsz = 2048;
305 #endif
306 spar.bits = rwavhdr->formathdr.bps;
307 spar.pchan = rwavhdr->formathdr.channels;
308 spar.appbufsz = 10240;
309
310 //wprintw(mixerwindow, "%d\n", spar.rate);
311
312 sio_setpar(hdl, &spar);
313 if (sio_getpar(hdl, &spar) == 0) {
314 perror("sio_getpar");
315 killpg(-1, SIGINT);
316 }
317
318 sio_start(hdl);
319
320 while (rightwav.map[0] == 'p') {
321 int n;
322
323 sio_setvol(hdl, SIO_MAXVOL);
324 n = sio_write(hdl,
&rightwav.map[rwavhdr->dataoffset], 10240);
325 if (n == 0) {
326 perror("sio_write");
327 killpg(-1, SIGINT);
328 }
329 rwavhdr->dataoffset += 10240;
330 if (rwavhdr->dataoffset >=
rightwav.size) {
331 rwavhdr->dataoffset = 0;
332 break;
333 }
334
335 usleep(40);
336 }
337
338 sio_close(hdl);
339 } /* for() */
340 } /* if pid == 0 */
341
342 wprintw(mixerwindow, "opening rmidi0\n");
343 wrefresh(mixerwindow);
344 midi = open("/dev/rmidi0", O_RDWR, 0);
345
346 if (midi < 0) {
347 perror("midi");
348 exit(1);
349 }
350
351
352 if (probe_midi(midi, &mm) < 0) {
353 perror("probe_midi");
354 close(midi);
355 exit(1);
356 }
357
358 if (mm.manufacturer[0] != 0x00 || mm.manufacturer[1] != 0x1 ||
359 mm.manufacturer[2] != 0x3f || mm.product != 0x2e) {
360 wprintw(mixerwindow, "this is not a Numark iDJ Live 2
product, exit.\n");
361 wrefresh(mixerwindow);
362 close(midi);
363 exit(1);
364 }
365
366 /* set up a crossfader menu */
367
368 crossfader = newwin(3, 22, 20, 30);
369 box(crossfader, '|', '-');
370
371 wmove(crossfader, 1, 10);
372 wprintw(crossfader, "||");
373 wrefresh(crossfader);
374
375
376 /* let's let the lights blink a little */
377
378 wprintw(mixerwindow, "blinking lights...\n");
379 wrefresh(mixerwindow);
380 for (i = 0; i < 4; i++) {
381 set_led_on(midi, NUMARK_DEVICE_2E_LEFTPLAY);
382 usleep(350);
383 set_led_on(midi, NUMARK_DEVICE_2E_RIGHTPLAY);
384 usleep(350);
385 set_led_on(midi, NUMARK_DEVICE_2E_RIGHTSYNC);
386 usleep(350);
387 set_led_on(midi, NUMARK_DEVICE_2E_LEFTSYNC);
388
389 sleep(1);
390
391 set_led_off(midi, NUMARK_DEVICE_2E_LEFTPLAY);
392 usleep(350);
393 set_led_off(midi, NUMARK_DEVICE_2E_RIGHTPLAY);
394 usleep(350);
395 set_led_off(midi, NUMARK_DEVICE_2E_RIGHTSYNC);
396 usleep(350);
397 set_led_off(midi, NUMARK_DEVICE_2E_LEFTSYNC);
398 sleep(1);
399 }
400 wprintw(mixerwindow, "done blinking lights\n");
401 wrefresh(mixerwindow);
402
403
404 wprintw(mixerwindow, "waiting for input from the device\n");
405 wrefresh(mixerwindow);
406
407 /* set up a songselect window */
408
409 songselect = newwin(8, 30, 2, 25);
410 box(songselect, '|', '-');
411 selectedsong = write_songs(songselect, selectedsong);
412 wrefresh(songselect);
413
414 leftsong = newwin(10, 25, 0, 0);
415 box(leftsong, '|', '-');
416 wrefresh(leftsong);
417
418 rightsong = newwin(10, 25, 0, 55);
419 box(rightsong, '|', '-');
420 wrefresh(rightsong);
421
422 for (;;) {
423 FD_ZERO(&rset);
424 FD_SET(midi, &rset);
425
426 sel = select(midi + 1, &rset, NULL, NULL, NULL);
427
428 if (sel == -1) {
429 perror("select");
430 return (-1);
431 }
432
433 if (FD_ISSET(midi, &rset)) {
434 read(midi, command, 3);
435 #ifdef DEBUG
436 switch ((u_int8_t)command[0]) {
437 case BUTTON_DOWN:
438 wprintw(mixerwindow, "button down ");
439 break;
440 case BUTTON_UP:
441 wprintw(mixerwindow, "button up ");
442 break;
443 case FADER:
444 wprintw(mixerwindow, "POT or FADER ");
445 break;
446 default:
447 wprintw(mixerwindow, "unknown event
%02x", (u_int8_t)buf[0] & 0xff);
448 break;
449 }
450
451 wprintw(mixerwindow, "controlid: %02x (%s)\n",
command[1] & 0xff, numark_controllid((u_int8_t)command[1]));
452
453 #endif
454 if (command[0] == FADER && command[1] ==
NUMARK_DEVICE_2E_CROSSFADER) {
455
456 faderpos = update_fader(crossfader,
command[2]);
457 }
458 if (command[0] == FADER && command[1] ==
NUMARK_DEVICE_2E_BROWSE) {
459 if (command[2] == 127)
460 selectedsong++;
461 else
462 selectedsong--;
463
464 selectedsong = write_songs(songselect,
selectedsong);
465 wrefresh(songselect);
466 }
467 if (command[0] == BUTTON_DOWN && command[1] ==
NUMARK_DEVICE_2E_LEFTLOAD) {
468 wmove(leftsong, 1, 1);
469 song = get_songs(selectedsong);
470 fd = open(song, O_RDONLY, 0);
471 if (fd < 0) {
472 perror("open");
473 exit(1);
474 }
475
476 waveheader = getheader(fd);
477 if (waveheader == NULL) {
478 perror("not a WAV file");
479 exit(1);
480 }
481
482 leftwav.pos = 2;
483 offset = waveheader->dataoffset;
484 lseek(fd, offset, SEEK_SET);
485
486 /* write song to memory */
487 while ((len = read(fd, buf,
sizeof(buf))) > 0) {
488 memcpy(buf,
&leftwav.map[rightwav.pos], len);
489 leftwav.pos += len;
490 leftwav.size = rightwav.pos;
491
492 if (leftwav.pos >= HUNDREDMB)
493 break;
494 }
495
496 close(fd);
497 song[20] = '\0';
498 wprintw(leftsong, "%s", song);
499 wrefresh(leftsong);
500 }
501 if (command[0] == BUTTON_DOWN && command[1] ==
NUMARK_DEVICE_2E_RIGHTLOAD) {
502 wmove(rightsong, 1, 1);
503 song = get_songs(selectedsong);
504
505 fd = open(song, O_RDONLY, 0);
506 if (fd < 0) {
507 perror("open");
508 exit(1);
509 }
510
511 waveheader = getheader(fd);
512 if (waveheader == NULL) {
513 perror("not a WAV file");
514 exit(1);
515 }
516
517 rightwav.pos = 2;
518 offset = waveheader->dataoffset;
519 lseek(fd, offset, SEEK_SET);
520
521 /* write song to memory */
522 while ((len = read(fd, buf,
sizeof(buf))) > 0) {
523 memcpy(buf,
&rightwav.map[rightwav.pos], len);
524 rightwav.pos += len;
525 rightwav.songsize =
rightwav.pos;
526
527 if (rightwav.pos >= HUNDREDMB)
528 break;
529 }
530
531 close(fd);
532
533 memcpy(rwavhdr, waveheader,
sizeof(struct mywaveheader));
534 //rwavhdr->dataoffset = sizeof(struct
mywaveheader) + 2;
535
536
537 song[20] = '\0';
538 wprintw(rightsong, "%s", song);
539 wmove(rightsong, 2, 0);
540 wprintw(rightsong, "%llu",
rwavhdr->dataoffset);
541 wrefresh(rightsong);
542 }
543 if (command[0] == BUTTON_DOWN && command[1] ==
NUMARK_DEVICE_2E_RIGHTPLAY) {
544 if (rightplay == 0)
545 rightplay = 1;
546 else
547 rightplay = 0;
548
549 if (rightplay) {
550 rightwav.map[0] = 'p';
551 set_led_on(midi,
NUMARK_DEVICE_2E_RIGHTPLAY);
552 } else {
553 rightwav.map[0] = '*';
554 set_led_off(midi,
NUMARK_DEVICE_2E_RIGHTPLAY);
555 }
556 }
557 wrefresh(mixerwindow);
558 } /* if */
559 } /* for */
560
561 close(midi);
562 exit(0);
563
564 }
565
566
567
568 int
569 probe_midi(int midi, struct midi_manuf *manufacturer)
570 {
571 struct reply *rply;
572 struct midi_reply *mr;
573 struct midi_manuf *mm;
574 struct midi_len *ml;
575 struct timeval tv;
576
577 u_char buf[512];
578 char *inquire = INQUIRESTRING;
579
580 int sel;
581 int mlen, len;
582 int i;
583 int gotf7;
584
585 fd_set rfdset;
586
587 wprintw(mixerwindow, "now sending inquire string\n");
588 wrefresh(mixerwindow);
589 write(midi, inquire, INQUIRESTRINGLEN);
590 wprintw(mixerwindow, "selecting for reponse\n");
591 wrefresh(mixerwindow);
592
593 tv.tv_sec = 10;
594 tv.tv_usec = 0;
595
596 FD_ZERO(&rfdset);
597 FD_SET(midi, &rfdset);
598
599 sel = select(midi + 1, &rfdset, NULL, NULL, &tv);
600
601 if (sel == -1) {
602 perror("select");
603 return (-1);
604 }
605
606 if (sel == 0) {
607 wprintw(mixerwindow, "no response for 10 seconds\n");
608 wrefresh(mixerwindow);
609 return (-1);
610 }
611
612 if (FD_ISSET(midi, &rfdset)) {
613 read(midi, buf, 1);
614 if ((uint8_t)buf[0] == 0xF0) {
615 if ((len = read(midi, buf, sizeof(*mr))) !=
sizeof(*mr)) {
616 wprintw(mixerwindow, "expected %d bytes
but %d came back\n", sizeof(*mr), len);
617 wrefresh(mixerwindow);
618 return (-1);
619 }
620
621 mr = (struct midi_reply *)buf;
622
623 if (mr->response != 0x2) {
624 wprintw(mixerwindow, "midi reply is not
a response, exit...\n");
625 wrefresh(mixerwindow);
626 return(-1);
627 }
628
629 if ((len = read(midi, buf, sizeof(*mm))) !=
sizeof(*mm)) {
630 wprintw(mixerwindow, "expected %d bytes
but %d came back\n", sizeof(*mm), len);
631 wrefresh(mixerwindow);
632 return (-1);
633 }
634
635 mm = (struct midi_manuf *)buf;
636
637 wprintw(mixerwindow, "manufacturer
%02x:%02x:%02x product %02x\n", mm->manufacturer[0], mm->manufacturer[1],
mm->manufacturer[2], mm->product);
638 wrefresh(mixerwindow);
639 memcpy(manufacturer, mm, sizeof(struct
midi_manuf));
640
641 if ((len = read(midi, buf, sizeof(struct
midi_len))) != sizeof(struct midi_len)) {
642 wprintw(mixerwindow, "expected %d bytes
but %d came back\n", sizeof(*ml), len);
643 wrefresh(mixerwindow);
644 return(-1);
645 }
646
647 ml = (struct midi_len *)buf;
648
649 if (ml->hibyte != 0) {
650 wprintw(mixerwindow, "message is more
than 255 bytes, exiting\n");
651 wrefresh(mixerwindow);
652 return(-1);
653 }
654
655 mlen = ml->lobyte;
656 if ((len = read(midi, buf, mlen)) != mlen) {
657 fprintf(stderr, "expected %d bytes but
%d came back instead\n", mlen, len);
658 return(-1);
659 }
660
661 rply = (struct reply *)&buf[0];
662
663 wprintw(mixerwindow, "version: %lu\nDEVID:
%u\nSerial: %lu\n",
664 rply->version, rply->devid,
rply->serial);
665 wrefresh(mixerwindow);
666
667 wprintw(mixerwindow, "manufacturer: ");
668 wrefresh(mixerwindow);
669 for (i = 9; i < mlen; i++) {
670 if (buf[i] == 0xf7) {
671 gotf7 = 1;
672 break;
673 }
674
675 wprintw(mixerwindow, "%c", buf[i]);
676 wrefresh(mixerwindow);
677 }
678 wprintw(mixerwindow, "\n");
679 wrefresh(mixerwindow);
680
681 if (!gotf7)
682 while (buf[0] != 0xf7)
683 read(midi, buf, 1);
684
685 read(midi, buf, 1);
686 }
687 }
688
689 return 0;
690 }
691
692 char *
693 numark_controllid(u_int8_t id)
694 {
695 static char buf[512];
696 struct numarktab *ptab = myntab;
697 int i;
698
699 strlcpy(buf, "unknown", sizeof(buf));
700
701 for (i = 0; i < nitems(myntab); i++) {
702 if (ptab->id == id) {
703 strlcpy(buf, ptab->string, sizeof(buf));
704 break;
705 }
706
707 ptab++;
708 }
709
710 return (buf);
711 }
712
713
714 int
715 update_fader(WINDOW *crossfader, u_int8_t command)
716 {
717 float pos = command;
718 float newpos;
719 int ret;
720
721 newpos = (1 - (pos / 127)) * 20;
722 ret = (pos * 100) / 127;
723
724 #if 0
725 wprintw(mixerwindow, "%d, ", newpos);
726 wrefresh(mixerwindow);
727 #endif
728
729 wmove(crossfader, 1, 1);
730 wprintw(crossfader, " ");
731 wmove(crossfader, 1, (int)newpos);
732 wprintw(crossfader, "||");
733 wrefresh(crossfader);
734
735 return (ret);
736 }
737
738 int
739 write_songs(WINDOW *songs, int selected)
740 {
741 DIR *dirp;
742 struct dirent *dp;
743 char *p;
744 int i;
745 char song[29];
746
747 dirp = opendir(".");
748 if (dirp) {
749 i = 1;
750 while ((dp = readdir(dirp)) != NULL) {
751 if (i > 8)
752 break;
753
754 if ((p = strrchr(dp->d_name, '.')) == NULL)
755 continue;
756
757 if (strcmp(p, ".wav"))
758 continue;
759
760 if (strlen(dp->d_name) > 28)
761 dp->d_name[27] = '\0';
762
763 memset(song, ' ', sizeof(song));
764 song[28] = '\0';
765 memcpy(song, dp->d_name,
MIN(strlen(dp->d_name), 28));
766
767 if (i == selected)
768 wattrset(songs, A_STANDOUT|A_REVERSE);
769 else
770 wattrset(songs, A_NORMAL);
771
772 wmove(songs, i, 1);
773 wprintw(songs, "%s", song);
774
775 i++;
776 }
777
778 closedir(dirp);
779 }
780
781 return selected;
782 }
783
784 char *
785 get_songs(int selected)
786 {
787 DIR *dirp;
788 struct dirent *dp;
789 char *p;
790 int i;
791 static char song[128];
792
793 dirp = opendir(".");
794 if (dirp) {
795 i = 1;
796 while ((dp = readdir(dirp)) != NULL) {
797 if (i > 8)
798 break;
799
800 if ((p = strrchr(dp->d_name, '.')) == NULL)
801 continue;
802
803 if (strcmp(p, ".wav"))
804 continue;
805
806 if (i == selected) {
807 strlcpy(song, dp->d_name, sizeof(song));
808 break;
809 }
810 i++;
811 }
812
813 closedir(dirp);
814 }
815
816 return (song);
817 }
818
819
820 struct mywaveheader *
821 getheader(int fd)
822 {
823 char buf[512];
824 struct mywaveheader *mwh;
825 struct wff *wh;
826 struct chk *chk;
827 struct fmt16 *fmt16;
828
829 mwh = calloc(1, sizeof(struct mywaveheader));
830 if (mwh == NULL)
831 return NULL;
832
833 read(fd, buf, sizeof(struct wff));
834 wh = (struct wff *)&buf[0];
835
836 if (memcmp(wh->id, "RIFF", 4) != 0) {
837 free (mwh);
838 return NULL;
839 }
840
841 memcpy(&mwh->waveheader.id, wh->id, 4);
842 mwh->waveheader.chunksize = wh->chunksize;
843
844 memcpy(&mwh->waveheader.waveid, wh->waveid, 4);
845
846 /* 8 + 16 */
847 if (read(fd, buf, 24) <= 0) {
848 free(mwh);
849 return NULL;
850 }
851
852 chk = (struct chk *)&buf[0];
853
854 if (memcmp(chk->chunkid, "fmt ", 4) != 0) {
855 free(mwh);
856 return NULL;
857 }
858
859 fmt16 = (struct fmt16 *)&buf[0];
860
861
862 memcpy(&mwh->formathdr.chunkid, fmt16->chunkid, 4);
863 mwh->formathdr.cksize = fmt16->cksize;
864
865 if (fmt16->fcode != 1) {
866 free(mwh);
867 return NULL;
868 }
869
870 mwh->formathdr.fcode = fmt16->fcode;
871
872 mwh->formathdr.channels = fmt16->channels;
873 mwh->formathdr.sps = fmt16->sps;
874 mwh->formathdr.datarate = fmt16->datarate;
875 mwh->formathdr.datablock = fmt16->datablock;
876 mwh->formathdr.bps = fmt16->bps;
877
878 switch (fmt16->cksize) {
879 case 16:
880 break;
881 case 40:
882 mwh->formathdr.validbits = fmt16->validbits;
883 mwh->formathdr.channelmask = fmt16->channelmask;
884 case 18:
885 mwh->formathdr.size = fmt16->size;
886 break;
887 default:
888 fprintf(stderr, "chunksize %d not supported yet\n",
fmt16->cksize);
889 free(mwh);
890 return NULL;
891 break;
892 }
893
894 if (read(fd, buf, 8) <= 0) {
895 free(mwh);
896 return NULL;
897 }
898
899 chk = (struct chk *)&buf[0];
900
901 if (memcmp(chk->chunkid, "FLLR ", 4) != 0) {
902 chk = NULL;
903 goto nofllr;
904 }
905
906 memcpy(&mwh->filler.chunkid, chk->chunkid, 4);
907 mwh->filler.cksize = chk->cksize;
908
909 if (lseek(fd, chk->cksize, SEEK_CUR) < 0) {
910 perror("lseek");
911 free(mwh);
912 return NULL;
913 }
914
915
916 if (read(fd, buf, 8) <= 0) {
917 free(mwh);
918 return NULL;
919 }
920
921 nofllr:
922 chk = (struct chk *)&buf[0];
923
924 if (memcmp(chk->chunkid, "data", 4) != 0) {
925 free(mwh);
926 return NULL;
927 }
928
929 memcpy(&mwh->data.chunkid, chk->chunkid, 4);
930 mwh->data.cksize = chk->cksize;
931
932 mwh->dataoffset = lseek(fd, 0, SEEK_CUR);
933
934
935 return (mwh);
936 }
937
938
939 void
940 set_led_on(int midi, int deviceid)
941 {
942 u_int8_t blinkenlights[3];
943
944 blinkenlights[0] = MIDI_NOTEON;
945 blinkenlights[1] = deviceid;
946 blinkenlights[2] = 0x7f;
947
948 write(midi, blinkenlights, 3);
949 }
950
951 void
952 set_led_off(int midi, int deviceid)
953 {
954 u_int8_t blinkenlights[3];
955
956 blinkenlights[0] = MIDI_NOTEOFF;
957 blinkenlights[1] = deviceid;
958 blinkenlights[2] = 0x7f;
959
960 write(midi, blinkenlights, 3);
961 }