1 /*
2  * wildmidi.c -- Midi Player using the WildMidi Midi Processing Library
3  *
4  * Copyright (C) WildMidi Developers 2001-2016
5  *
6  * This file is part of WildMIDI.
7  *
8  * WildMIDI is free software: you can redistribute and/or modify the player
9  * under the terms of the GNU General Public License and you can redistribute
10  * and/or modify the library under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation, either version 3 of
12  * the licenses, or(at your option) any later version.
13  *
14  * WildMIDI is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License and
17  * the GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License and the
20  * GNU Lesser General Public License along with WildMIDI.  If not,  see
21  * <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "config.h"
25 
26 #include <stdint.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #if defined(__DJGPP__)
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <sys/stat.h>
36 #include "getopt_long.h"
37 #include <conio.h>
38 #define getopt dj_getopt /* hack */
39 #include <unistd.h>
40 #undef getopt
41 #define msleep(s) usleep((s)*1000)
42 #include <io.h>
43 #include <dir.h>
44 #ifdef AUDIODRV_DOSSB
45 #include "dossb.h"
46 #endif
47 
48 #elif (defined _WIN32) || (defined __CYGWIN__)
49 #include <sys/types.h>
50 #include <fcntl.h>
51 #include <sys/stat.h>
52 #include <conio.h>
53 #include <windows.h>
54 #include <mmsystem.h>
55 #define msleep(s) Sleep((s))
56 #include <io.h>
57 #include "getopt_long.h"
58 #ifdef __WATCOMC__
59 #define _putch putch
60 #endif
61 
62 #elif defined(__OS2__) || defined(__EMX__)
63 #define INCL_DOS
64 #define INCL_DOSERRORS
65 #define INCL_OS2MM
66 #ifdef __EMX__
67 #define INCL_KBD
68 #define INCL_VIO
69 #endif
70 #include <os2.h>
71 #include <os2me.h>
72 #include <conio.h>
73 #define msleep(s) DosSleep((s))
74 #include <fcntl.h>
75 #include <io.h>
76 #include "getopt_long.h"
77 #ifdef __EMX__
78 #include <sys/types.h> /* for off_t typedef */
putch(int c)79 int putch (int c) {
80     char ch = c;
81     VioWrtTTY(&ch, 1, 0);
82     return c;
83 }
kbhit(void)84 int kbhit (void) {
85     KBDKEYINFO k;
86     if (KbdPeek(&k, 0))
87         return 0;
88     return (k.fbStatus & KBDTRF_FINAL_CHAR_IN);
89 }
90 #endif
91 
92 #elif defined(WILDMIDI_AMIGA)
93 extern void amiga_sysinit (void);
94 extern int amiga_usleep(unsigned long millisec);
95 #define msleep(s) amiga_usleep((s)*1000)
96 extern int amiga_getch (unsigned char *ch);
97 #include <proto/exec.h>
98 #include <proto/dos.h>
99 #include "getopt_long.h"
100 #ifdef AUDIODRV_AHI
101 #include <devices/ahi.h>
102 #endif
103 
104 #else /* unix build */
105 static int msleep(unsigned long millisec);
106 #include <sys/types.h>
107 #include <fcntl.h>
108 #include <sys/stat.h>
109 #include <sys/ioctl.h>
110 #include <unistd.h>
111 #include <getopt.h>
112 #include <time.h>
113 #ifdef AUDIODRV_ALSA
114 #  include <alsa/asoundlib.h>
115 #elif defined AUDIODRV_OSS
116 #   if defined HAVE_SYS_SOUNDCARD_H
117 #   include <sys/soundcard.h>
118 #   elif defined HAVE_MACHINE_SOUNDCARD_H
119 #   include <machine/soundcard.h>
120 #   elif defined HAVE_SOUNDCARD_H
121 #   include <soundcard.h> /* less common, but exists. */
122 #   endif
123 #elif defined AUDIODRV_OPENAL
124 #   include <al.h>
125 #   include <alc.h>
126 #endif
127 #endif /* !_WIN32, !__DJGPP__ (unix build) */
128 
129 #include "wildmidi_lib.h"
130 #include "wm_tty.h"
131 #include "filenames.h"
132 
133 struct _midi_test {
134     uint8_t *data;
135     uint32_t size;
136 };
137 
138 /* scale test from 0 to 127
139  * test a
140  * offset 18-21 (0x12-0x15) - track size
141  * offset 25 (0x1A) = bank number
142  * offset 28 (0x1D) = patch number
143  */
144 static uint8_t midi_test_c_scale[] = {
145     0x4d, 0x54, 0x68, 0x64, 0x00, 0x00, 0x00, 0x06, /* 0x00    */
146     0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x4d, 0x54, /* 0x08    */
147     0x72, 0x6b, 0x00, 0x00, 0x02, 0x63, 0x00, 0xb0, /* 0x10    */
148     0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x90, 0x00, /* 0x18  C */
149     0x64, 0x08, 0x80, 0x00, 0x00, 0x08, 0x90, 0x02, /* 0x20  D */
150     0x64, 0x08, 0x80, 0x02, 0x00, 0x08, 0x90, 0x04, /* 0x28  E */
151     0x64, 0x08, 0x80, 0x04, 0x00, 0x08, 0x90, 0x05, /* 0x30  F */
152     0x64, 0x08, 0x80, 0x05, 0x00, 0x08, 0x90, 0x07, /* 0x38  G */
153     0x64, 0x08, 0x80, 0x07, 0x00, 0x08, 0x90, 0x09, /* 0x40  A */
154     0x64, 0x08, 0x80, 0x09, 0x00, 0x08, 0x90, 0x0b, /* 0x48  B */
155     0x64, 0x08, 0x80, 0x0b, 0x00, 0x08, 0x90, 0x0c, /* 0x50  C */
156     0x64, 0x08, 0x80, 0x0c, 0x00, 0x08, 0x90, 0x0e, /* 0x58  D */
157     0x64, 0x08, 0x80, 0x0e, 0x00, 0x08, 0x90, 0x10, /* 0x60  E */
158     0x64, 0x08, 0x80, 0x10, 0x00, 0x08, 0x90, 0x11, /* 0x68  F */
159     0x64, 0x08, 0x80, 0x11, 0x00, 0x08, 0x90, 0x13, /* 0x70  G */
160     0x64, 0x08, 0x80, 0x13, 0x00, 0x08, 0x90, 0x15, /* 0x78  A */
161     0x64, 0x08, 0x80, 0x15, 0x00, 0x08, 0x90, 0x17, /* 0x80  B */
162     0x64, 0x08, 0x80, 0x17, 0x00, 0x08, 0x90, 0x18, /* 0x88  C */
163     0x64, 0x08, 0x80, 0x18, 0x00, 0x08, 0x90, 0x1a, /* 0x90  D */
164     0x64, 0x08, 0x80, 0x1a, 0x00, 0x08, 0x90, 0x1c, /* 0x98  E */
165     0x64, 0x08, 0x80, 0x1c, 0x00, 0x08, 0x90, 0x1d, /* 0xA0  F */
166     0x64, 0x08, 0x80, 0x1d, 0x00, 0x08, 0x90, 0x1f, /* 0xA8  G */
167     0x64, 0x08, 0x80, 0x1f, 0x00, 0x08, 0x90, 0x21, /* 0xB0  A */
168     0x64, 0x08, 0x80, 0x21, 0x00, 0x08, 0x90, 0x23, /* 0xB8  B */
169     0x64, 0x08, 0x80, 0x23, 0x00, 0x08, 0x90, 0x24, /* 0xC0  C */
170     0x64, 0x08, 0x80, 0x24, 0x00, 0x08, 0x90, 0x26, /* 0xC8  D */
171     0x64, 0x08, 0x80, 0x26, 0x00, 0x08, 0x90, 0x28, /* 0xD0  E */
172     0x64, 0x08, 0x80, 0x28, 0x00, 0x08, 0x90, 0x29, /* 0xD8  F */
173     0x64, 0x08, 0x80, 0x29, 0x00, 0x08, 0x90, 0x2b, /* 0xE0  G */
174     0x64, 0x08, 0x80, 0x2b, 0x00, 0x08, 0x90, 0x2d, /* 0xE8  A */
175     0x64, 0x08, 0x80, 0x2d, 0x00, 0x08, 0x90, 0x2f, /* 0xF0  B */
176     0x64, 0x08, 0x80, 0x2f, 0x00, 0x08, 0x90, 0x30, /* 0xF8  C */
177     0x64, 0x08, 0x80, 0x30, 0x00, 0x08, 0x90, 0x32, /* 0x100 D */
178     0x64, 0x08, 0x80, 0x32, 0x00, 0x08, 0x90, 0x34, /* 0x108 E */
179     0x64, 0x08, 0x80, 0x34, 0x00, 0x08, 0x90, 0x35, /* 0x110 F */
180     0x64, 0x08, 0x80, 0x35, 0x00, 0x08, 0x90, 0x37, /* 0x118 G */
181     0x64, 0x08, 0x80, 0x37, 0x00, 0x08, 0x90, 0x39, /* 0x120 A */
182     0x64, 0x08, 0x80, 0x39, 0x00, 0x08, 0x90, 0x3b, /* 0X128 B */
183     0x64, 0x08, 0x80, 0x3b, 0x00, 0x08, 0x90, 0x3c, /* 0x130 C */
184     0x64, 0x08, 0x80, 0x3c, 0x00, 0x08, 0x90, 0x3e, /* 0x138 D */
185     0x64, 0x08, 0x80, 0x3e, 0x00, 0x08, 0x90, 0x40, /* 0X140 E */
186     0x64, 0x08, 0x80, 0x40, 0x00, 0x08, 0x90, 0x41, /* 0x148 F */
187     0x64, 0x08, 0x80, 0x41, 0x00, 0x08, 0x90, 0x43, /* 0x150 G */
188     0x64, 0x08, 0x80, 0x43, 0x00, 0x08, 0x90, 0x45, /* 0x158 A */
189     0x64, 0x08, 0x80, 0x45, 0x00, 0x08, 0x90, 0x47, /* 0x160 B */
190     0x64, 0x08, 0x80, 0x47, 0x00, 0x08, 0x90, 0x48, /* 0x168 C */
191     0x64, 0x08, 0x80, 0x48, 0x00, 0x08, 0x90, 0x4a, /* 0x170 D */
192     0x64, 0x08, 0x80, 0x4a, 0x00, 0x08, 0x90, 0x4c, /* 0x178 E */
193     0x64, 0x08, 0x80, 0x4c, 0x00, 0x08, 0x90, 0x4d, /* 0x180 F */
194     0x64, 0x08, 0x80, 0x4d, 0x00, 0x08, 0x90, 0x4f, /* 0x188 G */
195     0x64, 0x08, 0x80, 0x4f, 0x00, 0x08, 0x90, 0x51, /* 0x190 A */
196     0x64, 0x08, 0x80, 0x51, 0x00, 0x08, 0x90, 0x53, /* 0x198 B */
197     0x64, 0x08, 0x80, 0x53, 0x00, 0x08, 0x90, 0x54, /* 0x1A0 C */
198     0x64, 0x08, 0x80, 0x54, 0x00, 0x08, 0x90, 0x56, /* 0x1A8 D */
199     0x64, 0x08, 0x80, 0x56, 0x00, 0x08, 0x90, 0x58, /* 0x1B0 E */
200     0x64, 0x08, 0x80, 0x58, 0x00, 0x08, 0x90, 0x59, /* 0x1B8 F */
201     0x64, 0x08, 0x80, 0x59, 0x00, 0x08, 0x90, 0x5b, /* 0x1C0 G */
202     0x64, 0x08, 0x80, 0x5b, 0x00, 0x08, 0x90, 0x5d, /* 0x1C8 A */
203     0x64, 0x08, 0x80, 0x5d, 0x00, 0x08, 0x90, 0x5f, /* 0x1D0 B */
204     0x64, 0x08, 0x80, 0x5f, 0x00, 0x08, 0x90, 0x60, /* 0x1D8 C */
205     0x64, 0x08, 0x80, 0x60, 0x00, 0x08, 0x90, 0x62, /* 0x1E0 D */
206     0x64, 0x08, 0x80, 0x62, 0x00, 0x08, 0x90, 0x64, /* 0x1E8 E */
207     0x64, 0x08, 0x80, 0x64, 0x00, 0x08, 0x90, 0x65, /* 0x1F0 F */
208     0x64, 0x08, 0x80, 0x65, 0x00, 0x08, 0x90, 0x67, /* 0x1F8 G */
209     0x64, 0x08, 0x80, 0x67, 0x00, 0x08, 0x90, 0x69, /* 0x200 A */
210     0x64, 0x08, 0x80, 0x69, 0x00, 0x08, 0x90, 0x6b, /* 0x208 B */
211     0x64, 0x08, 0x80, 0x6b, 0x00, 0x08, 0x90, 0x6c, /* 0x210 C */
212     0x64, 0x08, 0x80, 0x6c, 0x00, 0x08, 0x90, 0x6e, /* 0x218 D */
213     0x64, 0x08, 0x80, 0x6e, 0x00, 0x08, 0x90, 0x70, /* 0x220 E */
214     0x64, 0x08, 0x80, 0x70, 0x00, 0x08, 0x90, 0x71, /* 0x228 F */
215     0x64, 0x08, 0x80, 0x71, 0x00, 0x08, 0x90, 0x73, /* 0x230 G */
216     0x64, 0x08, 0x80, 0x73, 0x00, 0x08, 0x90, 0x75, /* 0x238 A */
217     0x64, 0x08, 0x80, 0x75, 0x00, 0x08, 0x90, 0x77, /* 0x240 B */
218     0x64, 0x08, 0x80, 0x77, 0x00, 0x08, 0x90, 0x78, /* 0x248 C */
219     0x64, 0x08, 0x80, 0x78, 0x00, 0x08, 0x90, 0x7a, /* 0x250 D */
220     0x64, 0x08, 0x80, 0x7a, 0x00, 0x08, 0x90, 0x7c, /* 0x258 E */
221     0x64, 0x08, 0x80, 0x7c, 0x00, 0x08, 0x90, 0x7d, /* 0x260 F */
222     0x64, 0x08, 0x80, 0x7d, 0x00, 0x08, 0x90, 0x7f, /* 0x268 G */
223     0x64, 0x08, 0x80, 0x7f, 0x00, 0x08, 0xff, 0x2f, /* 0x270   */
224     0x00                                            /* 0x278   */
225 };
226 
227 static struct _midi_test midi_test[] = {
228     { midi_test_c_scale, 663 },
229     { NULL, 0 }
230 };
231 
232 static int midi_test_max = 1;
233 
234 /*
235  ==============================
236  Audio Output Functions
237 
238  We have two 'drivers': first is the wav file writer which is
239  always available. the second, if it is really compiled in,
240  is the system audio output driver. only _one of the two_ can
241  be active, not both.
242  ==============================
243  */
244 
245 static unsigned int rate = 32072;
246 
247 static int (*send_output)(int8_t *output_data, int output_size);
248 static void (*close_output)(void);
249 static void (*pause_output)(void);
250 static void (*resume_output)(void);
251 
252 #define wmidi_geterrno() errno /* generic case */
253 #if defined(_WIN32)
254 static int audio_fd = -1;
255 #define WM_IS_BADF(_fd) ((_fd)<0)
256 #define WM_BADF -1
wmidi_fileexists(const char * path)257 static inline int wmidi_fileexists (const char *path) {
258     return (GetFileAttributes(path) != INVALID_FILE_ATTRIBUTES);
259 }
wmidi_open_write(const char * path)260 static inline int wmidi_open_write (const char *path) {
261     return _open(path, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY), 0664);
262 }
wmidi_close(int fd)263 static inline void wmidi_close (int fd) {
264     _close(fd);
265 }
wmidi_seekset(int fd,long ofs)266 static inline long wmidi_seekset (int fd, long ofs) {
267     return _lseek(fd, ofs, SEEK_SET);
268 }
wmidi_write(int fd,const void * buf,size_t size)269 static inline int wmidi_write (int fd, const void *buf, size_t size) {
270     return _write(fd, buf, size);
271 }
272 
273 #elif defined(__DJGPP__)
274 static int audio_fd = -1;
275 #define WM_IS_BADF(_fd) ((_fd)<0)
276 #define WM_BADF -1
wmidi_fileexists(const char * path)277 static inline int wmidi_fileexists (const char *path) {
278     struct ffblk f;
279     return (findfirst(path, &f, FA_ARCH | FA_RDONLY) == 0);
280 }
wmidi_open_write(const char * path)281 static inline int wmidi_open_write (const char *path) {
282     return open(path, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY), 0664);
283 }
wmidi_close(int fd)284 static inline void wmidi_close (int fd) {
285     close(fd);
286 }
wmidi_seekset(int fd,off_t ofs)287 static inline off_t wmidi_seekset (int fd, off_t ofs) {
288     return lseek(fd, ofs, SEEK_SET);
289 }
wmidi_write(int fd,const void * buf,size_t size)290 static inline int wmidi_write (int fd, const void *buf, size_t size) {
291     return write(fd, buf, size);
292 }
293 
294 #elif defined(__OS2__) || defined(__EMX__)
295 static int audio_fd = -1;
296 #define WM_IS_BADF(_fd) ((_fd)<0)
297 #define WM_BADF -1
wmidi_fileexists(const char * path)298 static inline int wmidi_fileexists (const char *path) {
299     int f = open(path, (O_RDONLY | O_BINARY));
300     if (f != -1) { close(f); return 1; } else return 0;
301 }
wmidi_open_write(const char * path)302 static inline int wmidi_open_write (const char *path) {
303     return open(path, (O_RDWR | O_CREAT | O_TRUNC | O_BINARY), 0664);
304 }
wmidi_close(int fd)305 static inline void wmidi_close (int fd) {
306     close(fd);
307 }
wmidi_seekset(int fd,off_t ofs)308 static inline off_t wmidi_seekset (int fd, off_t ofs) {
309     return lseek(fd, ofs, SEEK_SET);
310 }
wmidi_write(int fd,const void * buf,size_t size)311 static inline int wmidi_write (int fd, const void *buf, size_t size) {
312     return write(fd, buf, size);
313 }
314 
315 #elif defined(WILDMIDI_AMIGA)
316 static BPTR audio_fd = 0;
317 #define WM_IS_BADF(_fd) ((_fd)==0)
318 #define WM_BADF 0
319 #undef wmidi_geterrno
wmidi_geterrno(void)320 static int wmidi_geterrno (void) {
321     switch (IoErr()) {
322     case ERROR_OBJECT_NOT_FOUND: return ENOENT;
323     case ERROR_DISK_FULL: return ENOSPC;
324     }
325     return EIO; /* better ?? */
326 }
wmidi_fileexists(const char * path)327 static inline int wmidi_fileexists (const char *path) {
328     BPTR fd = Open((const STRPTR)path, MODE_OLDFILE);
329     if (!fd) return 0;
330     Close(fd); return 1;
331 }
wmidi_open_write(const char * path)332 static inline BPTR wmidi_open_write (const char *path) {
333     return Open((const STRPTR) path, MODE_NEWFILE);
334 }
wmidi_close(BPTR fd)335 static inline LONG wmidi_close (BPTR fd) {
336     return Close(fd);
337 }
wmidi_seekset(BPTR fd,LONG ofs)338 static inline LONG wmidi_seekset (BPTR fd, LONG ofs) {
339     return Seek(fd, ofs, OFFSET_BEGINNING);
340 }
wmidi_write(BPTR fd,void * buf,LONG size)341 static LONG wmidi_write (BPTR fd, /*const*/ void *buf, LONG size) {
342     LONG written = 0, result;
343     unsigned char *p = (unsigned char *)buf;
344     while (written < size) {
345         result = Write(fd, p + written, size - written);
346         if (result < 0) return result;
347         written += result;
348     }
349     return written;
350 }
351 
352 #else /* common posix case */
353 static int audio_fd = -1;
354 #define WM_IS_BADF(_fd) ((_fd)<0)
355 #define WM_BADF -1
wmidi_fileexists(const char * path)356 static inline int wmidi_fileexists (const char *path) {
357     struct stat st;
358     return (stat(path, &st) == 0);
359 }
wmidi_open_write(const char * path)360 static inline int wmidi_open_write (const char *path) {
361     return open(path, (O_RDWR | O_CREAT | O_TRUNC), (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH));
362 }
wmidi_close(int fd)363 static inline int wmidi_close (int fd) {
364     return close(fd);
365 }
wmidi_seekset(int fd,off_t ofs)366 static inline off_t wmidi_seekset (int fd, off_t ofs) {
367     return lseek(fd, ofs, SEEK_SET);
368 }
wmidi_write(int fd,const void * buf,size_t size)369 static inline ssize_t wmidi_write (int fd, const void *buf, size_t size) {
370     return write(fd, buf, size);
371 }
372 #endif
373 
pause_output_nop(void)374 static void pause_output_nop(void) {
375 }
resume_output_nop(void)376 static void resume_output_nop(void) {
377 }
378 
379 /*
380  MIDI Output Functions
381  */
382 static char midi_file[1024];
383 
write_midi_output(void * output_data,int output_size)384 static int write_midi_output(void *output_data, int output_size) {
385     if (midi_file[0] == '\0')
386         return (-1);
387 
388 /*
389  * Test if file already exists
390  */
391     if (wmidi_fileexists(midi_file)) {
392         fprintf(stderr, "\rError: %s already exists\r\n", midi_file);
393         return (-1);
394     }
395 
396     audio_fd = wmidi_open_write(midi_file);
397     if (WM_IS_BADF(audio_fd)) {
398         fprintf(stderr, "Error: unable to open file for writing (%s)\r\n", strerror(wmidi_geterrno()));
399         return (-1);
400     }
401 
402     if (wmidi_write(audio_fd, output_data, output_size) < 0) {
403         fprintf(stderr, "\nERROR: failed writing midi (%s)\r\n", strerror(wmidi_geterrno()));
404         wmidi_close(audio_fd);
405         audio_fd = WM_BADF;
406         return (-1);
407     }
408 
409     wmidi_close(audio_fd);
410     audio_fd = WM_BADF;
411     return (0);
412 }
413 
414 /*
415  Wav Output Functions
416  */
417 
418 static char wav_file[1024];
419 static uint32_t wav_size;
420 
421 static int write_wav_output(int8_t *output_data, int output_size);
422 static void close_wav_output(void);
423 
open_wav_output(void)424 static int open_wav_output(void) {
425     uint8_t wav_hdr[] = {
426         0x52, 0x49, 0x46, 0x46, /* "RIFF"  */
427         0x00, 0x00, 0x00, 0x00, /* riffsize: pcm size + 36 (filled when closing.) */
428         0x57, 0x41, 0x56, 0x45, /* "WAVE"  */
429         0x66, 0x6D, 0x74, 0x20, /* "fmt "  */
430         0x10, 0x00, 0x00, 0x00, /* length of this RIFF block: 16  */
431         0x01, 0x00,             /* wave format == 1 (WAVE_FORMAT_PCM)  */
432         0x02, 0x00,             /* channels == 2  */
433         0x00, 0x00, 0x00, 0x00, /* sample rate (filled below)  */
434         0x00, 0x00, 0x00, 0x00, /* bytes_per_sec: rate * channels * format bytes  */
435         0x04, 0x00,             /* block alignment: channels * format bytes == 4  */
436         0x10, 0x00,             /* format bits == 16  */
437         0x64, 0x61, 0x74, 0x61, /* "data"  */
438         0x00, 0x00, 0x00, 0x00  /* datasize: the pcm size (filled when closing.)  */
439     };
440 
441     if (wav_file[0] == '\0')
442         return (-1);
443 
444     audio_fd = wmidi_open_write(wav_file);
445     if (WM_IS_BADF(audio_fd)) {
446         fprintf(stderr, "Error: unable to open file for writing (%s)\r\n", strerror(wmidi_geterrno()));
447         return (-1);
448     } else {
449         uint32_t bytes_per_sec;
450 
451         wav_hdr[24] = (rate) & 0xFF;
452         wav_hdr[25] = (rate >> 8) & 0xFF;
453 
454         bytes_per_sec = rate * 4;
455         wav_hdr[28] = (bytes_per_sec) & 0xFF;
456         wav_hdr[29] = (bytes_per_sec >> 8) & 0xFF;
457         wav_hdr[30] = (bytes_per_sec >> 16) & 0xFF;
458         wav_hdr[31] = (bytes_per_sec >> 24) & 0xFF;
459     }
460 
461     if (wmidi_write(audio_fd, wav_hdr, 44) < 0) {
462         fprintf(stderr, "ERROR: failed writing wav header (%s)\r\n", strerror(wmidi_geterrno()));
463         wmidi_close(audio_fd);
464         audio_fd = WM_BADF;
465         return (-1);
466     }
467 
468     wav_size = 0;
469     send_output = write_wav_output;
470     close_output = close_wav_output;
471     pause_output = pause_output_nop;
472     resume_output = resume_output_nop;
473     return (0);
474 }
475 
write_wav_output(int8_t * output_data,int output_size)476 static int write_wav_output(int8_t *output_data, int output_size) {
477 #ifdef WORDS_BIGENDIAN
478 /* libWildMidi outputs host-endian, *.wav must have little-endian. */
479     uint16_t *swp = (uint16_t *) output_data;
480     int i = (output_size / 2) - 1;
481     for (; i >= 0; --i) {
482         swp[i] = (swp[i] << 8) | (swp[i] >> 8);
483     }
484 #endif
485     if (wmidi_write(audio_fd, output_data, output_size) < 0) {
486         fprintf(stderr, "\nERROR: failed writing wav (%s)\r\n", strerror(wmidi_geterrno()));
487         wmidi_close(audio_fd);
488         audio_fd = WM_BADF;
489         return (-1);
490     }
491 
492     wav_size += output_size;
493     return (0);
494 }
495 
close_wav_output(void)496 static void close_wav_output(void) {
497     uint8_t wav_count[4];
498     if (WM_IS_BADF(audio_fd))
499         return;
500 
501     printf("Finishing and closing wav output\r");
502     wav_count[0] = (wav_size) & 0xFF;
503     wav_count[1] = (wav_size >> 8) & 0xFF;
504     wav_count[2] = (wav_size >> 16) & 0xFF;
505     wav_count[3] = (wav_size >> 24) & 0xFF;
506     wmidi_seekset(audio_fd, 40);
507     if (wmidi_write(audio_fd, wav_count, 4) < 0) {
508         fprintf(stderr, "\nERROR: failed writing wav (%s)\r\n", strerror(wmidi_geterrno()));
509         goto end;
510     }
511 
512     wav_size += 36;
513     wav_count[0] = (wav_size) & 0xFF;
514     wav_count[1] = (wav_size >> 8) & 0xFF;
515     wav_count[2] = (wav_size >> 16) & 0xFF;
516     wav_count[3] = (wav_size >> 24) & 0xFF;
517     wmidi_seekset(audio_fd, 4);
518     if (wmidi_write(audio_fd, wav_count, 4) < 0) {
519         fprintf(stderr, "\nERROR: failed writing wav (%s)\r\n", strerror(wmidi_geterrno()));
520         goto end;
521     }
522 
523 end:    printf("\n");
524     if (!WM_IS_BADF(audio_fd))
525         wmidi_close(audio_fd);
526     audio_fd = WM_BADF;
527 }
528 
529 #if (defined _WIN32) || (defined __CYGWIN__)
530 
531 static HWAVEOUT hWaveOut = NULL;
532 static CRITICAL_SECTION waveCriticalSection;
533 
534 #define open_audio_output open_mm_output
535 static int write_mm_output (int8_t *output_data, int output_size);
536 static void close_mm_output (void);
537 
538 static WAVEHDR *mm_blocks = NULL;
539 #define MM_BLOCK_SIZE 16384
540 #define MM_BLOCK_COUNT 3
541 
542 static DWORD mm_free_blocks = MM_BLOCK_COUNT;
543 static DWORD mm_current_block = 0;
544 
545 #if defined(_MSC_VER) && (_MSC_VER < 1300)
546 typedef DWORD DWORD_PTR;
547 #endif
548 
mmOutProc(HWAVEOUT hWaveOut,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)549 static void CALLBACK mmOutProc (HWAVEOUT hWaveOut, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
550     /* unused params */
551     (void)hWaveOut;
552     (void)dwParam1;
553     (void)dwParam2;
554 
555     if(uMsg != WOM_DONE)
556         return;
557     /* increment mm_free_blocks */
558     EnterCriticalSection(&waveCriticalSection);
559     (*(DWORD *)dwInstance)++;
560     LeaveCriticalSection(&waveCriticalSection);
561 }
562 
563 static int
open_mm_output(void)564 open_mm_output (void) {
565     WAVEFORMATEX wfx;
566     char *mm_buffer;
567     int i;
568 
569     InitializeCriticalSection(&waveCriticalSection);
570 
571     if((mm_buffer = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((MM_BLOCK_SIZE + sizeof(WAVEHDR)) * MM_BLOCK_COUNT))) == NULL) {
572         fprintf(stderr, "Memory allocation error\r\n");
573         return -1;
574     }
575 
576     mm_blocks = (WAVEHDR*)mm_buffer;
577     mm_buffer += sizeof(WAVEHDR) * MM_BLOCK_COUNT;
578 
579     for(i = 0; i < MM_BLOCK_COUNT; i++) {
580         mm_blocks[i].dwBufferLength = MM_BLOCK_SIZE;
581         mm_blocks[i].lpData = mm_buffer;
582         mm_buffer += MM_BLOCK_SIZE;
583     }
584 
585     wfx.nSamplesPerSec = rate;
586     wfx.wBitsPerSample = 16;
587     wfx.nChannels = 2;
588     wfx.cbSize = 0;
589     wfx.wFormatTag = WAVE_FORMAT_PCM;
590     wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
591     wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
592 
593     if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)mmOutProc, (DWORD_PTR)&mm_free_blocks, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
594         fprintf(stderr, "unable to open WAVE_MAPPER device\r\n");
595         HeapFree(GetProcessHeap(), 0, mm_blocks);
596         hWaveOut = NULL;
597         mm_blocks = NULL;
598         return -1;
599     }
600 
601     send_output = write_mm_output;
602     close_output = close_mm_output;
603     pause_output = pause_output_nop;
604     resume_output = resume_output_nop;
605     return (0);
606 }
607 
608 static int
write_mm_output(int8_t * output_data,int output_size)609 write_mm_output (int8_t *output_data, int output_size) {
610     WAVEHDR* current;
611     int free_size = 0;
612     int data_read = 0;
613     current = &mm_blocks[mm_current_block];
614 
615     while (output_size) {
616         if(current->dwFlags & WHDR_PREPARED)
617             waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
618         free_size = MM_BLOCK_SIZE - current->dwUser;
619         if (free_size > output_size)
620             free_size = output_size;
621 
622         memcpy(current->lpData + current->dwUser, &output_data[data_read], free_size);
623         current->dwUser += free_size;
624         output_size -= free_size;
625         data_read += free_size;
626 
627         if (current->dwUser < MM_BLOCK_SIZE) {
628             return (0);
629         }
630 
631         current->dwBufferLength = MM_BLOCK_SIZE;
632         waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
633         waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
634         EnterCriticalSection(&waveCriticalSection);
635         mm_free_blocks--;
636         LeaveCriticalSection(&waveCriticalSection);
637         while(!mm_free_blocks)
638             Sleep(10);
639         mm_current_block++;
640         mm_current_block %= MM_BLOCK_COUNT;
641         current = &mm_blocks[mm_current_block];
642         current->dwUser = 0;
643     }
644     return (0);
645 }
646 
647 static void
close_mm_output(void)648 close_mm_output (void) {
649     int i;
650 
651     if (!hWaveOut) return;
652 
653     printf("Shutting down sound output\r\n");
654     for (i = 0; i < MM_BLOCK_COUNT; i++) {
655         while (waveOutUnprepareHeader(hWaveOut, &mm_blocks[i], sizeof(WAVEHDR))
656                 == WAVERR_STILLPLAYING) {
657             Sleep(10);
658         }
659     }
660 
661     waveOutClose (hWaveOut);
662     HeapFree(GetProcessHeap(), 0, mm_blocks);
663     hWaveOut = NULL;
664     mm_blocks = NULL;
665 }
666 
667 #elif (defined(__OS2__) || defined(__EMX__)) && defined(AUDIODRV_OS2DART)
668 /* based on Dart code originally written by Kevin Langman for XMP */
669 
670 #define open_audio_output open_dart_output
671 static int write_dart_output (int8_t *output_data, int output_size);
672 static void close_dart_output (void);
673 
674 #define BUFFERCOUNT 4
675 
676 static MCI_MIX_BUFFER MixBuffers[BUFFERCOUNT];
677 static MCI_MIXSETUP_PARMS MixSetupParms;
678 static MCI_BUFFER_PARMS BufferParms;
679 static MCI_GENERIC_PARMS GenericParms;
680 
681 static ULONG DeviceID = 0;
682 static ULONG bsize = 16;
683 static short next = 2;
684 static short ready = 1;
685 
686 static HMTX dart_mutex;
687 
688 /* Buffer update thread (created and called by DART) */
OS2_Dart_UpdateBuffers(ULONG ulStatus,PMCI_MIX_BUFFER pBuffer,ULONG ulFlags)689 static LONG APIENTRY OS2_Dart_UpdateBuffers
690     (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) {
691 
692     (void) pBuffer;/* unused param */
693 
694     if ((ulFlags == MIX_WRITE_COMPLETE) ||
695         ((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) &&
696          (ulStatus == ERROR_DEVICE_UNDERRUN))) {
697         DosRequestMutexSem(dart_mutex, SEM_INDEFINITE_WAIT);
698         ready++;
699         DosReleaseMutexSem(dart_mutex);
700     }
701     return (TRUE);
702 }
703 
704 static int
open_dart_output(void)705 open_dart_output(void) {
706     int i;
707     MCI_AMP_OPEN_PARMS AmpOpenParms;
708 
709     if (DosCreateMutexSem(NULL, &dart_mutex, 0, 0) != NO_ERROR) {
710         fprintf(stderr, "Failed creating a MutexSem.\r\n");
711         return (-1);
712     }
713 
714     /* compute a size for circa 1/4" of playback. */
715     bsize = rate >> 2;
716     bsize <<= 1; /* stereo */
717     bsize <<= 1; /* 16 bit */
718     for (i = 15; i >= 12; i--) {
719         if (bsize & (1 << i))
720             break;
721     }
722     bsize = (1 << i);
723     /* make sure buffer is not greater than 64 Kb: DART can't handle it. */
724     if (bsize > 65536)
725         bsize = 65536;
726 
727     MixBuffers[0].pBuffer = NULL; /* marker */
728     memset(&GenericParms, 0, sizeof(MCI_GENERIC_PARMS));
729 
730     /* open AMP device */
731     memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
732     AmpOpenParms.usDeviceID = 0;
733 
734     AmpOpenParms.pszDeviceType =
735         (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, 0); /* 0: default waveaudio device */
736 
737     if(mciSendCommand(0, MCI_OPEN, MCI_WAIT|MCI_OPEN_TYPE_ID|MCI_OPEN_SHAREABLE,
738                        (PVOID) &AmpOpenParms, 0) != MCIERR_SUCCESS) {
739         fprintf(stderr, "Failed opening DART audio device\r\n");
740         return (-1);
741     }
742 
743     DeviceID = AmpOpenParms.usDeviceID;
744 
745     /* setup playback parameters */
746     memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS));
747 
748     MixSetupParms.ulBitsPerSample = 16;
749     MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
750     MixSetupParms.ulSamplesPerSec = rate;
751     MixSetupParms.ulChannels = 2;
752     MixSetupParms.ulFormatMode = MCI_PLAY;
753     MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
754     MixSetupParms.pmixEvent = OS2_Dart_UpdateBuffers;
755 
756     if (mciSendCommand(DeviceID, MCI_MIXSETUP,
757                        MCI_WAIT | MCI_MIXSETUP_INIT,
758                        (PVOID) & MixSetupParms, 0) != MCIERR_SUCCESS) {
759 
760         mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT,
761                        (PVOID) & GenericParms, 0);
762         fprintf(stderr, "Failed DART mixer setup\r\n");
763         return (-1);
764     }
765 
766     /*bsize = MixSetupParms.ulBufferSize;*/
767     /*printf("Dart Buffer Size = %lu\n", bsize);*/
768 
769     BufferParms.ulNumBuffers = BUFFERCOUNT;
770     BufferParms.ulBufferSize = bsize;
771     BufferParms.pBufList = MixBuffers;
772 
773     if (mciSendCommand(DeviceID, MCI_BUFFER,
774                        MCI_WAIT | MCI_ALLOCATE_MEMORY,
775                        (PVOID) & BufferParms, 0) != MCIERR_SUCCESS) {
776         fprintf(stderr, "DART Memory allocation error\r\n");
777         mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT,
778                        (PVOID) & GenericParms, 0);
779         return (-1);
780     }
781 
782     for (i = 0; i < BUFFERCOUNT; i++) {
783         MixBuffers[i].ulBufferLength = bsize;
784     }
785 
786     /* Start Playback */
787     memset(MixBuffers[0].pBuffer, /*32767 */ 0, bsize);
788     memset(MixBuffers[1].pBuffer, /*32767 */ 0, bsize);
789     MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffers, 2);
790 
791     send_output = write_dart_output;
792     close_output = close_dart_output;
793     pause_output = pause_output_nop;
794     resume_output = resume_output_nop;
795 
796     return (0);
797 }
798 
799 static int
write_dart_output(int8_t * output_data,int output_size)800 write_dart_output (int8_t *output_data, int output_size) {
801     static int idx = 0;
802 
803     if (idx + output_size > bsize) {
804         do {
805             DosRequestMutexSem(dart_mutex, SEM_INDEFINITE_WAIT);
806             if (ready != 0) {
807                 DosReleaseMutexSem(dart_mutex);
808                 break;
809             }
810             DosReleaseMutexSem(dart_mutex);
811             DosSleep(20);
812         } while (TRUE);
813 
814         MixBuffers[next].ulBufferLength = idx;
815         MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, &(MixBuffers[next]), 1);
816         ready--;
817         next++;
818         idx = 0;
819         if (next == BUFFERCOUNT) {
820             next = 0;
821         }
822     }
823     memcpy(&((char *)MixBuffers[next].pBuffer)[idx], output_data, output_size);
824     idx += output_size;
825     return (0);
826 }
827 
828 static void
close_dart_output(void)829 close_dart_output (void) {
830     printf("Shutting down sound output\r\n");
831     if (MixBuffers[0].pBuffer) {
832         mciSendCommand(DeviceID, MCI_BUFFER,
833                        MCI_WAIT | MCI_DEALLOCATE_MEMORY, &BufferParms, 0);
834         MixBuffers[0].pBuffer = NULL;
835     }
836     if (DeviceID) {
837         mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT,
838                        (PVOID) &GenericParms, 0);
839         DeviceID = 0;
840     }
841 }
842 
843 #elif defined(__DJGPP__) && defined(AUDIODRV_DOSSB)
844 /* SoundBlaster/Pro/16/AWE32 driver for DOS -- adapted from
845  * libMikMod,  written by Andrew Zabolotny <bit@eltech.ru>,
846  * further fixes by O.Sezer <sezero@users.sourceforge.net>.
847  * Timer callback functionality replaced by a push mechanism
848  * to keep the wildmidi player changes to a minimum, for now.
849  */
850 
851 /* The last buffer byte filled with sound */
852 static unsigned int buff_tail = 0;
853 
write_sb_output(int8_t * data,unsigned int siz)854 static int write_sb_output(int8_t *data, unsigned int siz) {
855     unsigned int dma_size, dma_pos;
856     unsigned int cnt;
857 
858     sb_query_dma(&dma_size, &dma_pos);
859     /* There isn't much sense in filling less than 256 bytes */
860     dma_pos &= ~255;
861 
862     /* If nothing to mix, quit */
863     if (buff_tail == dma_pos)
864         return 0;
865 
866     /* If DMA pointer still didn't wrapped around ... */
867     if (dma_pos > buff_tail) {
868         if ((cnt = dma_pos - buff_tail) > siz)
869             cnt = siz;
870         memcpy(sb.dma_buff->linear + buff_tail, data, cnt);
871         buff_tail += cnt;
872         /* If we arrived right to the DMA buffer end, jump to the beginning */
873         if (buff_tail >= dma_size)
874             buff_tail = 0;
875     } else {
876         /* If wrapped around, fill first to the end of buffer */
877         if ((cnt = dma_size - buff_tail) > siz)
878             cnt = siz;
879         memcpy(sb.dma_buff->linear + buff_tail, data, cnt);
880         buff_tail += cnt;
881         siz -= cnt;
882         if (!siz) return cnt;
883 
884         /* Now fill from buffer beginning to current DMA pointer */
885         if (dma_pos > siz) dma_pos = siz;
886         data += cnt;
887         cnt += dma_pos;
888 
889         memcpy(sb.dma_buff->linear, data, dma_pos);
890         buff_tail = dma_pos;
891     }
892     return cnt;
893 }
894 
write_sb_s16stereo(int8_t * data,int siz)895 static int write_sb_s16stereo(int8_t *data, int siz) {
896 /* libWildMidi sint16 stereo -> SB16 sint16 stereo */
897     int i;
898     while (1) {
899         i = write_sb_output(data, siz);
900         if ((siz -= i) <= 0) return 0;
901         data += i;
902         /*usleep(100);*/
903     }
904 }
905 
write_sb_u8stereo(int8_t * data,int siz)906 static int write_sb_u8stereo(int8_t *data, int siz) {
907 /* libWildMidi sint16 stereo -> SB uint8 stereo */
908     int16_t *src = (int16_t *) data;
909     uint8_t *dst = (uint8_t *) data;
910     int i = (siz /= 2);
911     for (; i >= 0; --i) {
912         *dst++ = (*src++ >> 8) + 128;
913     }
914     while (1) {
915         i = write_sb_output(data, siz);
916         if ((siz -= i) <= 0) return 0;
917         data += i;
918         /*usleep(100);*/
919     }
920 }
921 
write_sb_u8mono(int8_t * data,int siz)922 static int write_sb_u8mono(int8_t *data, int siz) {
923 /* libWildMidi sint16 stereo -> SB uint8 mono */
924     int16_t *src = (int16_t *) data;
925     uint8_t *dst = (uint8_t *) data;
926     int i = (siz /= 4); int val;
927     for (; i >= 0; --i) {
928     /* do a cheap (left+right)/2 */
929         val  = *src++;
930         val += *src++;
931         *dst++ = (val >> 9) + 128;
932     }
933     while (1) {
934         i = write_sb_output(data, siz);
935         if ((siz -= i) <= 0) return 0;
936         data += i;
937         /*usleep(100);*/
938     }
939 }
940 
sb_silence_s16(void)941 static void sb_silence_s16(void) {
942     memset(sb.dma_buff->linear, 0, sb.dma_buff->size);
943 }
944 
sb_silence_u8(void)945 static void sb_silence_u8(void) {
946     memset(sb.dma_buff->linear, 0x80, sb.dma_buff->size);
947 }
948 
close_sb_output(void)949 static void close_sb_output(void)
950 {
951     sb.timer_callback = NULL;
952     sb_output(FALSE);
953     sb_stop_dma();
954     sb_close();
955 }
956 
957 #define open_audio_output open_sb_output
open_sb_output(void)958 static int open_sb_output(void)
959 {
960     if (!sb_open()) {
961         fprintf(stderr, "Sound Blaster initialization failed.\n");
962         return -1;
963     }
964 
965     if (rate < 4000) rate = 4000;
966     if (sb.caps & SBMODE_STEREO) {
967         if (rate > sb.maxfreq_stereo)
968             rate = sb.maxfreq_stereo;
969     } else {
970         if (rate > sb.maxfreq_mono)
971             rate = sb.maxfreq_mono;
972     }
973 
974     /* Enable speaker output */
975     sb_output(TRUE);
976 
977     /* Set our routine to be called during SB IRQs */
978     buff_tail = 0;
979     sb.timer_callback = NULL;/* see above  */
980 
981     /* Start cyclic DMA transfer */
982     if (!sb_start_dma(((sb.caps & SBMODE_16BITS) ? SBMODE_16BITS | SBMODE_SIGNED : 0) |
983                             (sb.caps & SBMODE_STEREO), rate)) {
984         sb_output(FALSE);
985         sb_close();
986         fprintf(stderr, "Sound Blaster: DMA start failed.\n");
987         return -1;
988     }
989 
990     if (sb.caps & SBMODE_16BITS) { /* can do stereo, too */
991         send_output = write_sb_s16stereo;
992         pause_output = sb_silence_s16;
993         resume_output = resume_output_nop;
994         printf("Sound Blaster 16 or compatible (16 bit, stereo, %u Hz)\n", rate);
995     } else if (sb.caps & SBMODE_STEREO) {
996         send_output = write_sb_u8stereo;
997         pause_output = sb_silence_u8;
998         resume_output = resume_output_nop;
999         printf("Sound Blaster Pro or compatible (8 bit, stereo, %u Hz)\n", rate);
1000     } else {
1001         send_output = write_sb_u8mono;
1002         pause_output = sb_silence_u8;
1003         resume_output = resume_output_nop;
1004         printf("Sound Blaster %c or compatible (8 bit, mono, %u Hz)\n",
1005                (sb.dspver < SBVER_20)? '1' : '2', rate);
1006     }
1007     close_output = close_sb_output;
1008 
1009     return 0;
1010 }
1011 
1012 #elif defined(WILDMIDI_AMIGA) && defined(AUDIODRV_AHI)
1013 
1014 /* Driver for output to native Amiga AHI device:
1015  * Written by Szilárd Biró <col.lawrence@gmail.com>, loosely based
1016  * on an old AOS4 version by Fredrik Wikstrom <fredrik@a500.org>
1017  */
1018 
1019 #define BUFFERSIZE (4 << 10)
1020 
1021 static struct MsgPort *AHImp = NULL;
1022 static struct AHIRequest *AHIReq[2] = { NULL, NULL };
1023 static int active = 0;
1024 static int8_t *AHIBuf[2] = { NULL, NULL };
1025 
1026 #define open_audio_output open_ahi_output
1027 static int write_ahi_output(int8_t *output_data, int output_size);
1028 static void close_ahi_output(void);
1029 
open_ahi_output(void)1030 static int open_ahi_output(void) {
1031     AHImp = CreateMsgPort();
1032     if (AHImp) {
1033         AHIReq[0] = (struct AHIRequest *) CreateIORequest(AHImp, sizeof(struct AHIRequest));
1034         if (AHIReq[0]) {
1035             AHIReq[0]->ahir_Version = 4;
1036             AHIReq[1] = (struct AHIRequest *) AllocVec(sizeof(struct AHIRequest), MEMF_PUBLIC);
1037             if (AHIReq[1]) {
1038                 if (!OpenDevice(AHINAME, AHI_DEFAULT_UNIT, (struct IORequest *)AHIReq[0], 0)) {
1039                     /*AHIReq[0]->ahir_Std.io_Message.mn_Node.ln_Pri = 0;*/
1040                     AHIReq[0]->ahir_Std.io_Command = CMD_WRITE;
1041                     AHIReq[0]->ahir_Std.io_Data = NULL;
1042                     AHIReq[0]->ahir_Std.io_Offset = 0;
1043                     AHIReq[0]->ahir_Frequency = rate;
1044                     AHIReq[0]->ahir_Type = AHIST_S16S;/* 16 bit stereo */
1045                     AHIReq[0]->ahir_Volume = 0x10000;
1046                     AHIReq[0]->ahir_Position = 0x8000;
1047                     CopyMem(AHIReq[0], AHIReq[1], sizeof(struct AHIRequest));
1048 
1049                     AHIBuf[0] = (int8_t *) AllocVec(BUFFERSIZE, MEMF_PUBLIC | MEMF_CLEAR);
1050                     if (AHIBuf[0]) {
1051                         AHIBuf[1] = (int8_t *) AllocVec(BUFFERSIZE, MEMF_PUBLIC | MEMF_CLEAR);
1052                         if (AHIBuf[1]) {
1053                             send_output = write_ahi_output;
1054                             close_output = close_ahi_output;
1055                             pause_output = pause_output_nop;
1056                             resume_output = resume_output_nop;
1057                             return (0);
1058                         }
1059                     }
1060                 }
1061             }
1062         }
1063     }
1064 
1065     close_ahi_output();
1066     fprintf(stderr, "ERROR: Unable to open AHI output\r\n");
1067     return (-1);
1068 }
1069 
write_ahi_output(int8_t * output_data,int output_size)1070 static int write_ahi_output(int8_t *output_data, int output_size) {
1071     int chunk;
1072     while (output_size > 0) {
1073         if (AHIReq[active]->ahir_Std.io_Data) {
1074             WaitIO((struct IORequest *) AHIReq[active]);
1075         }
1076         chunk = (output_size < BUFFERSIZE)? output_size : BUFFERSIZE;
1077         memcpy(AHIBuf[active], output_data, chunk);
1078         output_size -= chunk;
1079         output_data += chunk;
1080 
1081         AHIReq[active]->ahir_Std.io_Data = AHIBuf[active];
1082         AHIReq[active]->ahir_Std.io_Length = chunk;
1083         AHIReq[active]->ahir_Link = !CheckIO((struct IORequest *) AHIReq[active ^ 1]) ? AHIReq[active ^ 1] : NULL;
1084         SendIO((struct IORequest *)AHIReq[active]);
1085         active ^= 1;
1086     }
1087     return (0);
1088 }
1089 
close_ahi_output(void)1090 static void close_ahi_output(void) {
1091     if (AHIReq[1]) {
1092         AHIReq[0]->ahir_Link = NULL; /* in case we are linked to req[0] */
1093         if (!CheckIO((struct IORequest *) AHIReq[1])) {
1094             AbortIO((struct IORequest *) AHIReq[1]);
1095             WaitIO((struct IORequest *) AHIReq[1]);
1096         }
1097         FreeVec(AHIReq[1]);
1098         AHIReq[1] = NULL;
1099     }
1100     if (AHIReq[0]) {
1101         if (!CheckIO((struct IORequest *) AHIReq[0])) {
1102             AbortIO((struct IORequest *) AHIReq[0]);
1103             WaitIO((struct IORequest *) AHIReq[0]);
1104         }
1105         if (AHIReq[0]->ahir_Std.io_Device) {
1106             CloseDevice((struct IORequest *) AHIReq[0]);
1107             AHIReq[0]->ahir_Std.io_Device = NULL;
1108         }
1109         DeleteIORequest((struct IORequest *) AHIReq[0]);
1110         AHIReq[0] = NULL;
1111     }
1112     if (AHImp) {
1113         DeleteMsgPort(AHImp);
1114         AHImp = NULL;
1115     }
1116     if (AHIBuf[0]) {
1117         FreeVec(AHIBuf[0]);
1118         AHIBuf[0] = NULL;
1119     }
1120     if (AHIBuf[1]) {
1121         FreeVec(AHIBuf[1]);
1122         AHIBuf[1] = NULL;
1123     }
1124 }
1125 
1126 #else
1127 #ifdef AUDIODRV_ALSA
1128 
1129 static int alsa_first_time = 1;
1130 static snd_pcm_t *pcm = NULL;
1131 static char pcmname[64];
1132 
1133 #define open_audio_output open_alsa_output
1134 static int write_alsa_output(int8_t *output_data, int output_size);
1135 static void close_alsa_output(void);
1136 
open_alsa_output(void)1137 static int open_alsa_output(void) {
1138     snd_pcm_hw_params_t *hw;
1139     snd_pcm_sw_params_t *sw;
1140     int err;
1141     unsigned int alsa_buffer_time;
1142     unsigned int alsa_period_time;
1143     unsigned int r;
1144 
1145     if (!pcmname[0]) {
1146         strcpy(pcmname, "default");
1147     }
1148 
1149     if ((err = snd_pcm_open(&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
1150         fprintf(stderr, "Error: audio open error: %s\r\n", snd_strerror(err));
1151         return -1;
1152     }
1153 
1154     snd_pcm_hw_params_alloca(&hw);
1155 
1156     if ((err = snd_pcm_hw_params_any(pcm, hw)) < 0) {
1157         fprintf(stderr, "ERROR: No configuration available for playback: %s\r\n",
1158                 snd_strerror(err));
1159         goto fail;
1160     }
1161 
1162     if ((err = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
1163         fprintf(stderr, "Cannot set access mode: %s.\r\n", snd_strerror(err));
1164         goto fail;
1165     }
1166 
1167     if (snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16) < 0) {
1168         fprintf(stderr, "ALSA does not support 16bit signed audio for your soundcard\r\n");
1169         goto fail;
1170     }
1171 
1172     if (snd_pcm_hw_params_set_channels(pcm, hw, 2) < 0) {
1173         fprintf(stderr, "ALSA does not support stereo for your soundcard\r\n");
1174         goto fail;
1175     }
1176 
1177     r = rate;
1178     if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, 0) < 0) {
1179         fprintf(stderr, "ALSA does not support %uHz for your soundcard\r\n", rate);
1180         goto fail;
1181     }
1182     if (r != rate) {
1183         fprintf(stderr, "ALSA: sample rate set to %uHz instead of %u\r\n", rate, r);
1184     }
1185 
1186     alsa_buffer_time = 500000;
1187     alsa_period_time = 50000;
1188 
1189     if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hw, &alsa_buffer_time, 0)) < 0) {
1190         fprintf(stderr, "Set buffer time failed: %s.\r\n", snd_strerror(err));
1191         goto fail;
1192     }
1193 
1194     if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hw, &alsa_period_time, 0)) < 0) {
1195         fprintf(stderr, "Set period time failed: %s.\r\n", snd_strerror(err));
1196         goto fail;
1197     }
1198 
1199     if (snd_pcm_hw_params(pcm, hw) < 0) {
1200         fprintf(stderr, "Unable to install hw params\r\n");
1201         goto fail;
1202     }
1203 
1204     snd_pcm_sw_params_alloca(&sw);
1205     snd_pcm_sw_params_current(pcm, sw);
1206     if (snd_pcm_sw_params(pcm, sw) < 0) {
1207         fprintf(stderr, "Unable to install sw params\r\n");
1208         goto fail;
1209     }
1210 
1211     send_output = write_alsa_output;
1212     close_output = close_alsa_output;
1213     pause_output = pause_output_nop;
1214     resume_output = resume_output_nop;
1215     return (0);
1216 
1217 fail:   close_alsa_output();
1218     return -1;
1219 }
1220 
write_alsa_output(int8_t * output_data,int output_size)1221 static int write_alsa_output(int8_t *output_data, int output_size) {
1222     int err;
1223     snd_pcm_uframes_t frames;
1224 
1225     while (output_size > 0) {
1226         frames = snd_pcm_bytes_to_frames(pcm, output_size);
1227         if ((err = snd_pcm_writei(pcm, output_data, frames)) < 0) {
1228             if (snd_pcm_state(pcm) == SND_PCM_STATE_XRUN) {
1229                 if ((err = snd_pcm_prepare(pcm)) < 0)
1230                     fprintf(stderr, "\nsnd_pcm_prepare() failed.\r\n");
1231                 alsa_first_time = 1;
1232                 continue;
1233             }
1234             return err;
1235         }
1236 
1237         output_size -= snd_pcm_frames_to_bytes(pcm, err);
1238         output_data += snd_pcm_frames_to_bytes(pcm, err);
1239         if (alsa_first_time) {
1240             alsa_first_time = 0;
1241             snd_pcm_start(pcm);
1242         }
1243     }
1244     return (0);
1245 }
1246 
close_alsa_output(void)1247 static void close_alsa_output(void) {
1248     if (!pcm) return;
1249     printf("Shutting down sound output\r\n");
1250     snd_pcm_close(pcm);
1251     pcm = NULL;
1252 }
1253 
1254 #elif defined AUDIODRV_OSS
1255 
1256 #if !defined(AFMT_S16_NE)
1257 #ifdef WORDS_BIGENDIAN
1258 #define AFMT_S16_NE AFMT_S16_BE
1259 #else
1260 #define AFMT_S16_NE AFMT_S16_LE
1261 #endif
1262 #endif
1263 
1264 #define DEFAULT_FRAGSIZE 14
1265 #define DEFAULT_NUMFRAGS 16
1266 
1267 static char pcmname[64];
1268 
1269 #define open_audio_output open_oss_output
1270 static int write_oss_output(int8_t *output_data, int output_size);
1271 static void close_oss_output(void);
1272 
pause_output_oss(void)1273 static void pause_output_oss(void) {
1274     ioctl(audio_fd, SNDCTL_DSP_POST, 0);
1275 }
1276 
open_oss_output(void)1277 static int open_oss_output(void) {
1278     int tmp;
1279     unsigned int r;
1280 
1281     if (!pcmname[0]) {
1282         strcpy(pcmname, "/dev/dsp");
1283     }
1284 
1285     if ((audio_fd = open(pcmname, O_WRONLY)) < 0) {
1286         fprintf(stderr, "ERROR: Unable to open dsp (%s)\r\n", strerror(errno));
1287         return (-1);
1288     }
1289     if (ioctl(audio_fd, SNDCTL_DSP_RESET, 0) < 0) {
1290         fprintf(stderr, "ERROR: Unable to reset dsp\r\n");
1291         goto fail;
1292     }
1293 
1294     tmp = AFMT_S16_NE;
1295     if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp) < 0) {
1296         fprintf(stderr, "ERROR: Unable to set 16bit sound format\r\n");
1297         goto fail;
1298     }
1299 
1300     tmp = 2;
1301     if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &tmp) < 0) {
1302         fprintf(stderr, "ERROR: Unable to set stereo\r\n");
1303         goto fail;
1304     }
1305 
1306     r = rate;
1307     if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate) < 0) {
1308         fprintf(stderr, "ERROR: Unable to set %uHz sample rate\r\n", rate);
1309         goto fail;
1310     }
1311     if (r != rate) {
1312         fprintf(stderr, "OSS: sample rate set to %uHz instead of %u\r\n", rate, r);
1313     }
1314 
1315     tmp = (DEFAULT_NUMFRAGS<<16)|DEFAULT_FRAGSIZE;
1316     if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp) < 0) {
1317         fprintf(stderr, "ERROR: Unable to set fragment size\r\n");
1318         goto fail;
1319     }
1320 
1321     send_output = write_oss_output;
1322     close_output = close_oss_output;
1323     pause_output = pause_output_oss;
1324     resume_output = resume_output_nop;
1325     return (0);
1326 
1327 fail:   close_oss_output();
1328     return (-1);
1329 }
1330 
write_oss_output(int8_t * output_data,int output_size)1331 static int write_oss_output(int8_t *output_data, int output_size) {
1332     int res = 0;
1333     while (output_size > 0) {
1334         res = write(audio_fd, output_data, output_size);
1335         if (res > 0) {
1336             output_size -= res;
1337             output_data += res;
1338         } else {
1339             fprintf(stderr, "\nOSS: write failure to dsp: %s.\r\n",
1340                     strerror(errno));
1341             return (-1);
1342         }
1343     }
1344     return (0);
1345 }
1346 
close_oss_output(void)1347 static void close_oss_output(void) {
1348     if (audio_fd < 0)
1349         return;
1350     printf("Shutting down sound output\r\n");
1351     ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
1352     close(audio_fd);
1353     audio_fd = -1;
1354 }
1355 
1356 #elif defined AUDIODRV_OPENAL
1357 
1358 #define NUM_BUFFERS 4
1359 
1360 static ALCdevice *device;
1361 static ALCcontext *context;
1362 static ALuint sourceId = 0;
1363 static ALuint buffers[NUM_BUFFERS];
1364 static ALuint frames = 0;
1365 
1366 #define open_audio_output open_openal_output
1367 
pause_output_openal(void)1368 static void pause_output_openal(void) {
1369     alSourcePause(sourceId);
1370 }
1371 
write_openal_output(int8_t * output_data,int output_size)1372 static int write_openal_output(int8_t *output_data, int output_size) {
1373     ALint processed, state;
1374     ALuint bufid;
1375 
1376     if (frames < NUM_BUFFERS) { /* initial state: fill the buffers */
1377         alBufferData(buffers[frames], AL_FORMAT_STEREO16, output_data,
1378                      output_size, rate);
1379 
1380         /* Now queue and start playback! */
1381         if (++frames == NUM_BUFFERS) {
1382             alSourceQueueBuffers(sourceId, frames, buffers);
1383             alSourcePlay(sourceId);
1384         }
1385         return 0;
1386     }
1387 
1388     /* Get relevant source info */
1389     alGetSourcei(sourceId, AL_SOURCE_STATE, &state);
1390     if (state == AL_PAUSED) { /* resume it, then.. */
1391         alSourcePlay(sourceId);
1392         if (alGetError() != AL_NO_ERROR) {
1393             fprintf(stderr, "\nError restarting playback\r\n");
1394             return (-1);
1395         }
1396     }
1397 
1398     processed = 0;
1399     while (processed == 0) { /* Wait until we have a processed buffer */
1400         alGetSourcei(sourceId, AL_BUFFERS_PROCESSED, &processed);
1401     }
1402 
1403     /* Unqueue and handle each processed buffer */
1404     alSourceUnqueueBuffers(sourceId, 1, &bufid);
1405 
1406     /* Read the next chunk of data, refill the buffer, and queue it
1407      * back on the source */
1408     alBufferData(bufid, AL_FORMAT_STEREO16, output_data, output_size, rate);
1409     alSourceQueueBuffers(sourceId, 1, &bufid);
1410     if (alGetError() != AL_NO_ERROR) {
1411         fprintf(stderr, "\nError buffering data\r\n");
1412         return (-1);
1413     }
1414 
1415     /* Make sure the source hasn't underrun */
1416     alGetSourcei(sourceId, AL_SOURCE_STATE, &state);
1417     /*printf("STATE: %#08x - %d\n", state, queued);*/
1418     if (state != AL_PLAYING) {
1419         ALint queued;
1420 
1421         /* If no buffers are queued, playback is finished */
1422         alGetSourcei(sourceId, AL_BUFFERS_QUEUED, &queued);
1423         if (queued == 0) {
1424             fprintf(stderr, "\nNo buffers queued for playback\r\n");
1425             return (-1);
1426         }
1427 
1428         alSourcePlay(sourceId);
1429     }
1430 
1431     return (0);
1432 }
1433 
close_openal_output(void)1434 static void close_openal_output(void) {
1435     if (!context) return;
1436     printf("Shutting down sound output\r\n");
1437     alSourceStop(sourceId);         /* stop playing */
1438     alSourcei(sourceId, AL_BUFFER, 0);  /* unload buffer from source */
1439     alDeleteBuffers(NUM_BUFFERS, buffers);
1440     alDeleteSources(1, &sourceId);
1441     alcDestroyContext(context);
1442     alcCloseDevice(device);
1443     context = NULL;
1444     device = NULL;
1445     frames = 0;
1446 }
1447 
open_openal_output(void)1448 static int open_openal_output(void) {
1449     /* setup our audio devices and contexts */
1450     device = alcOpenDevice(NULL);
1451     if (!device) {
1452         fprintf(stderr, "OpenAL: Unable to open default device.\r\n");
1453         return (-1);
1454     }
1455 
1456     context = alcCreateContext(device, NULL);
1457     if (context == NULL || alcMakeContextCurrent(context) == ALC_FALSE) {
1458         if (context != NULL)
1459             alcDestroyContext(context);
1460         alcCloseDevice(device);
1461         context = NULL;
1462         device = NULL;
1463         fprintf(stderr, "OpenAL: Failed to create the default context.\r\n");
1464         return (-1);
1465     }
1466 
1467     /* setup our sources and buffers */
1468     alGenSources(1, &sourceId);
1469     alGenBuffers(NUM_BUFFERS, buffers);
1470 
1471     send_output = write_openal_output;
1472     close_output = close_openal_output;
1473     pause_output = pause_output_openal;
1474     resume_output = resume_output_nop;
1475     return (0);
1476 }
1477 
1478 #else /* no audio output driver compiled in: */
1479 
1480 #define open_audio_output open_noaudio_output
open_noaudio_output(void)1481 static int open_noaudio_output(void) {
1482     fprintf(stderr, "No audio output driver was selected at compile time.\r\n");
1483     return -1;
1484 }
1485 
1486 #endif /* AUDIODRV_ALSA */
1487 #endif /* _WIN32 || __CYGWIN__ */
1488 
1489 static struct option const long_options[] = {
1490     { "version", 0, 0, 'v' },
1491     { "help", 0, 0, 'h' },
1492     { "rate", 1, 0, 'r' },
1493     { "mastervol", 1, 0, 'm' },
1494     { "config", 1, 0, 'c' },
1495     { "wavout", 1, 0, 'o' },
1496     { "tomidi", 1, 0, 'x' },
1497     { "convert", 1, 0, 'g' },
1498     { "frequency", 1, 0, 'f' },
1499     { "log_vol", 0, 0, 'l' },
1500     { "reverb", 0, 0, 'b' },
1501     { "test_midi", 0, 0, 't' },
1502     { "test_bank", 1, 0, 'k' },
1503     { "test_patch", 1, 0, 'p' },
1504     { "enhanced", 0, 0, 'e' },
1505 #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA)
1506     { "device", 1, 0, 'd' },
1507 #endif
1508     { "roundtempo", 0, 0, 'n' },
1509     { "skipsilentstart", 0, 0, 's' },
1510     { "textaslyric", 0, 0, 'a' },
1511     { "playfrom", 1, 0, 'i'},
1512     { "playto", 1, 0, 'j'},
1513     { NULL, 0, NULL, 0 }
1514 };
1515 
do_help(void)1516 static void do_help(void) {
1517     printf("  -v    --version     Display version info and exit\n");
1518     printf("  -h    --help        Display this help and exit\n");
1519 #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA)
1520     printf("  -d D  --device=D    Use device D for audio output instead of default\n");
1521 #endif
1522     printf("MIDI Options:\n");
1523     printf("  -n    --roundtempo  Round tempo to nearest whole number\n");
1524     printf("  -s    --skipsilentstart Skips any silence at the start of playback\n");
1525     printf("  -t    --test_midi   Listen to test MIDI\n");
1526     printf("Non-MIDI Options:\n");
1527     printf("  -x    --tomidi      Convert file to midi and save to file\n");
1528     printf("  -g    --convert     Convert XMI: 0 - No Conversion (default)\n");
1529     printf("                                   1 - MT32 to GM\n");
1530     printf("                                   2 - MT32 to GS\n");
1531     printf("  -f F  --frequency=F Use frequency F Hz for playback (MUS)\n");
1532     printf("Software Wavetable Options:\n");
1533     printf("  -o W  --wavout=W    Save output to W in 16bit stereo format wav file\n");
1534     printf("  -l    --log_vol     Use log volume adjustments\n");
1535     printf("  -r N  --rate=N      Set sample rate to N samples per second (Hz)\n");
1536     printf("  -c P  --config=P    Point to your wildmidi.cfg config file name/path\n");
1537     printf("                      defaults to: %s\n", WILDMIDI_CFG);
1538     printf("  -m V  --mastervol=V Set the master volume (0..127), default is 100\n");
1539     printf("  -b    --reverb      Enable final output reverb engine\n");
1540 }
1541 
do_version(void)1542 static void do_version(void) {
1543     printf("\nWildMidi %s Open Source Midi Sequencer\n", PACKAGE_VERSION);
1544     printf("Copyright (C) WildMIDI Developers 2001-2016\n\n");
1545     printf("WildMidi comes with ABSOLUTELY NO WARRANTY\n");
1546     printf("This is free software, and you are welcome to redistribute it under\n");
1547     printf("the terms and conditions of the GNU General Public License version 3.\n");
1548     printf("For more information see COPYING\n\n");
1549     printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
1550     printf("WildMIDI homepage is at %s\n\n", PACKAGE_URL);
1551 }
1552 
do_syntax(void)1553 static void do_syntax(void) {
1554     printf("Usage: wildmidi [options] filename.mid\n\n");
1555 }
1556 
1557 static char config_file[1024];
1558 
main(int argc,char ** argv)1559 int main(int argc, char **argv) {
1560     struct _WM_Info *wm_info;
1561     int i, res;
1562     int option_index = 0;
1563     uint16_t mixer_options = 0;
1564     void *midi_ptr;
1565     uint8_t master_volume = 100;
1566     int8_t *output_buffer;
1567     uint32_t perc_play;
1568     uint32_t pro_mins;
1569     uint32_t pro_secs;
1570     uint32_t apr_mins;
1571     uint32_t apr_secs;
1572     char modes[5];
1573     uint8_t ch;
1574     int test_midi = 0;
1575     int test_count = 0;
1576     uint8_t *test_data;
1577     uint8_t test_bank = 0;
1578     uint8_t test_patch = 0;
1579     static char spinner[] = "|/-\\";
1580     static int spinpoint = 0;
1581     unsigned long int seek_to_sample;
1582     uint32_t samples = 0;
1583     int inpause = 0;
1584     char * ret_err = NULL;
1585     long libraryver;
1586     char * lyric = NULL;
1587     char *last_lyric = NULL;
1588     size_t last_lyric_length = 0;
1589     int8_t kareoke = 0;
1590 #define MAX_LYRIC_CHAR 128
1591     char lyrics[MAX_LYRIC_CHAR + 1];
1592 #define MAX_DISPLAY_LYRICS 29
1593     char display_lyrics[MAX_DISPLAY_LYRICS + 1];
1594 
1595     unsigned long int play_from = 0;
1596     unsigned long int play_to = 0;
1597 
1598     memset(lyrics,' ',MAX_LYRIC_CHAR);
1599     memset(display_lyrics,' ',MAX_DISPLAY_LYRICS);
1600 
1601 #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA)
1602     pcmname[0] = 0;
1603 #endif
1604     config_file[0] = 0;
1605     wav_file[0] = 0;
1606     midi_file[0] = 0;
1607 
1608     do_version();
1609     while (1) {
1610         i = getopt_long(argc, argv, "0vho:tx:g:f:lr:c:m:btak:p:ed:nsi:j:", long_options,
1611                 &option_index);
1612         if (i == -1)
1613             break;
1614         switch (i) {
1615         case 'v': /* Version */
1616             return (0);
1617         case 'h': /* help */
1618             do_syntax();
1619             do_help();
1620             return (0);
1621         case 'r': /* Sample Rate */
1622             res = atoi(optarg);
1623             if (res < 0 || res > 65535) {
1624                 fprintf(stderr, "Error: bad rate %i.\n", res);
1625                 return (1);
1626             }
1627             rate = (uint32_t) res;
1628             break;
1629         case 'b': /* Reverb */
1630             mixer_options |= WM_MO_REVERB;
1631             break;
1632         case 'm': /* Master Volume */
1633             master_volume = (uint8_t) atoi(optarg);
1634             break;
1635         case 'o': /* Wav Output */
1636             if (!*optarg) {
1637                 fprintf(stderr, "Error: empty wavfile name.\n");
1638                 return (1);
1639             }
1640             strncpy(wav_file, optarg, sizeof(wav_file));
1641             wav_file[sizeof(wav_file) - 1] = 0;
1642             break;
1643         case 'g': /* XMIDI Conversion */
1644             WildMidi_SetCvtOption(WM_CO_XMI_TYPE, (uint16_t) atoi(optarg));
1645             break;
1646         case 'f': /* MIDI-like Conversion */
1647             WildMidi_SetCvtOption(WM_CO_FREQUENCY, (uint16_t) atoi(optarg));
1648             break;
1649         case 'x': /* MIDI Output */
1650             if (!*optarg) {
1651                 fprintf(stderr, "Error: empty midi name.\n");
1652                 return (1);
1653             }
1654             strncpy(midi_file, optarg, sizeof(midi_file));
1655             midi_file[sizeof(midi_file) - 1] = 0;
1656             break;
1657         case 'c': /* Config File */
1658             if (!*optarg) {
1659                 fprintf(stderr, "Error: empty config name.\n");
1660                 return (1);
1661             }
1662             strncpy(config_file, optarg, sizeof(config_file));
1663             config_file[sizeof(config_file) - 1] = 0;
1664             break;
1665 #if defined(AUDIODRV_OSS) || defined(AUDIODRV_ALSA)
1666         case 'd': /* Output device */
1667             if (!*optarg) {
1668                 fprintf(stderr, "Error: empty device name.\n");
1669                 return (1);
1670             }
1671             strncpy(pcmname, optarg, sizeof(pcmname));
1672             pcmname[sizeof(pcmname) - 1] = 0;
1673             break;
1674 #endif
1675         case 'e': /* Enhanced Resampling */
1676             mixer_options |= WM_MO_ENHANCED_RESAMPLING;
1677             break;
1678         case 'l': /* log volume */
1679             mixer_options |= WM_MO_LOG_VOLUME;
1680             break;
1681         case 't': /* play test midis */
1682             test_midi = 1;
1683             break;
1684         case 'k': /* set test bank */
1685             test_bank = (uint8_t) atoi(optarg);
1686             break;
1687         case 'p': /* set test patch */
1688             test_patch = (uint8_t) atoi(optarg);
1689             break;
1690         case 'n': /* whole number tempo */
1691             mixer_options |= WM_MO_ROUNDTEMPO;
1692             break;
1693         case 'a':
1694             /* Some files have the lyrics in the text meta event.
1695              * This option reads lyrics from there instead.  */
1696             mixer_options |= WM_MO_TEXTASLYRIC;
1697             break;
1698         case 's': /* strip silence at start */
1699             mixer_options |= WM_MO_STRIPSILENCE;
1700             break;
1701         case '0': /* treat as type 2 midi when writing to file */
1702             mixer_options |= WM_MO_SAVEASTYPE0;
1703             break;
1704         case 'i':
1705             play_from = (unsigned long int)(atof(optarg) * (double)rate);
1706             break;
1707         case 'j':
1708             play_to = (unsigned long int)(atof(optarg) * (double)rate);
1709             break;
1710         default:
1711             do_syntax();
1712             return (1);
1713         }
1714     }
1715 
1716     if (optind >= argc && !test_midi) {
1717         fprintf(stderr, "ERROR: No midi file given\r\n");
1718         do_syntax();
1719         return (1);
1720     }
1721 
1722     if (test_midi) {
1723         if (midi_file[0] != '\0') {
1724             fprintf(stderr, "--test_midi and --convert cannot be used together.\n");
1725             return (1);
1726         }
1727     }
1728 
1729     /* check if we only need to convert a file to midi */
1730     if (midi_file[0] != '\0') {
1731         const char *real_file = FIND_LAST_DIRSEP(argv[optind]);
1732         uint32_t size;
1733         uint8_t *data;
1734 
1735         if (!real_file) real_file = argv[optind];
1736         else real_file++;
1737 
1738         printf("Converting %s\r\n", real_file);
1739         if (WildMidi_ConvertToMidi(argv[optind], &data, &size) < 0) {
1740             fprintf(stderr, "Conversion failed: %s.\r\n", WildMidi_GetError());
1741             WildMidi_ClearError();
1742             return (1);
1743         }
1744 
1745         printf("Writing %s: %u bytes.\r\n", midi_file, size);
1746         write_midi_output(data, size);
1747         free(data);
1748         return (0);
1749     }
1750 
1751     if (!config_file[0]) {
1752         strncpy(config_file, WILDMIDI_CFG, sizeof(config_file));
1753         config_file[sizeof(config_file) - 1] = 0;
1754     }
1755 
1756     printf("Initializing Sound System\n");
1757     if (wav_file[0] != '\0') {
1758         if (open_wav_output() == -1) {
1759             return (1);
1760         }
1761     } else {
1762         if (open_audio_output() == -1) {
1763             return (1);
1764         }
1765     }
1766 
1767     libraryver = WildMidi_GetVersion();
1768     printf("Initializing libWildMidi %ld.%ld.%ld\n\n",
1769                         (libraryver>>16) & 255,
1770                         (libraryver>> 8) & 255,
1771                         (libraryver    ) & 255);
1772     if (WildMidi_Init(config_file, rate, mixer_options) == -1) {
1773         fprintf(stderr, "%s\r\n", WildMidi_GetError());
1774         WildMidi_ClearError();
1775         return (1);
1776     }
1777 
1778     printf(" +  Volume up        e  Better resampling    n  Next Midi\n");
1779     printf(" -  Volume down      l  Log volume           q  Quit\n");
1780     printf(" ,  1sec Seek Back   r  Reverb               .  1sec Seek Forward\n");
1781     printf(" m  save as midi     p  Pause On/Off\n\n");
1782 
1783     output_buffer = (int8_t *) malloc(16384);
1784     if (output_buffer == NULL) {
1785         fprintf(stderr, "Not enough memory, exiting\n");
1786         WildMidi_Shutdown();
1787         return (1);
1788     }
1789 
1790     wm_inittty();
1791 #ifdef WILDMIDI_AMIGA
1792     amiga_sysinit();
1793 #endif
1794 
1795     WildMidi_MasterVolume(master_volume);
1796 
1797     while (optind < argc || test_midi) {
1798         WildMidi_ClearError();
1799         if (!test_midi) {
1800             const char *real_file = FIND_LAST_DIRSEP(argv[optind]);
1801 
1802             if (!real_file) real_file = argv[optind];
1803             else real_file++;
1804             printf("\rPlaying %s ", real_file);
1805 
1806             midi_ptr = WildMidi_Open(argv[optind]);
1807             optind++;
1808             if (midi_ptr == NULL) {
1809                 ret_err = WildMidi_GetError();
1810                 printf(" Skipping: %s\r\n",ret_err);
1811                 continue;
1812             }
1813         } else {
1814             if (test_count == midi_test_max) {
1815                 break;
1816             }
1817             test_data = (uint8_t *) malloc(midi_test[test_count].size);
1818             memcpy(test_data, midi_test[test_count].data,
1819                     midi_test[test_count].size);
1820             test_data[25] = test_bank;
1821             test_data[28] = test_patch;
1822             midi_ptr = WildMidi_OpenBuffer(test_data, 633);
1823             test_count++;
1824             if (midi_ptr == NULL) {
1825                 fprintf(stderr, "\rFailed loading test midi no. %i\r\n", test_count);
1826                 continue;
1827             }
1828             printf("\rPlaying test midi no. %i ", test_count);
1829         }
1830 
1831         wm_info = WildMidi_GetInfo(midi_ptr);
1832 
1833         apr_mins = wm_info->approx_total_samples / (rate * 60);
1834         apr_secs = (wm_info->approx_total_samples % (rate * 60)) / rate;
1835         mixer_options = wm_info->mixer_options;
1836         modes[0] = (mixer_options & WM_MO_LOG_VOLUME)? 'l' : ' ';
1837         modes[1] = (mixer_options & WM_MO_REVERB)? 'r' : ' ';
1838         modes[2] = (mixer_options & WM_MO_ENHANCED_RESAMPLING)? 'e' : ' ';
1839         modes[3] = ' ';
1840         modes[4] = '\0';
1841 
1842         printf("\r\n[Approx %2um %2us Total]\r\n", apr_mins, apr_secs);
1843         fprintf(stderr, "\r");
1844 
1845         memset(lyrics,' ',MAX_LYRIC_CHAR);
1846         memset(display_lyrics,' ',MAX_DISPLAY_LYRICS);
1847 
1848         if (play_from != 0) {
1849             WildMidi_FastSeek(midi_ptr, &play_from);
1850             if (play_to < play_from) {
1851                 // Ignore --playto if set less than --playfrom
1852                 play_to = 0;
1853             }
1854         }
1855 
1856         while (1) {
1857             ch = 0;
1858 #ifdef _WIN32
1859             if (_kbhit()) {
1860                 ch = _getch();
1861                 _putch(ch);
1862             }
1863 #elif defined(__DJGPP__) || defined(__OS2__) || defined(__EMX__)
1864             if (kbhit()) {
1865                 ch = getch();
1866                 putch(ch);
1867             }
1868 #elif defined(WILDMIDI_AMIGA)
1869             amiga_getch (&ch);
1870 #else
1871             if (read(STDIN_FILENO, &ch, 1) != 1)
1872                 ch = 0;
1873 #endif
1874             if (ch) {
1875                 switch (ch) {
1876                 case 'l':
1877                     WildMidi_SetOption(midi_ptr, WM_MO_LOG_VOLUME,
1878                                        ((mixer_options & WM_MO_LOG_VOLUME) ^ WM_MO_LOG_VOLUME));
1879                     mixer_options ^= WM_MO_LOG_VOLUME;
1880                     modes[0] = (mixer_options & WM_MO_LOG_VOLUME)? 'l' : ' ';
1881                     break;
1882                 case 'r':
1883                     WildMidi_SetOption(midi_ptr, WM_MO_REVERB,
1884                                        ((mixer_options & WM_MO_REVERB) ^ WM_MO_REVERB));
1885                     mixer_options ^= WM_MO_REVERB;
1886                     modes[1] = (mixer_options & WM_MO_REVERB)? 'r' : ' ';
1887                     break;
1888                 case 'e':
1889                     WildMidi_SetOption(midi_ptr, WM_MO_ENHANCED_RESAMPLING,
1890                                        ((mixer_options & WM_MO_ENHANCED_RESAMPLING) ^ WM_MO_ENHANCED_RESAMPLING));
1891                     mixer_options ^= WM_MO_ENHANCED_RESAMPLING;
1892                     modes[2] = (mixer_options & WM_MO_ENHANCED_RESAMPLING)? 'e' : ' ';
1893                     break;
1894                 case 'a':
1895                     WildMidi_SetOption(midi_ptr, WM_MO_TEXTASLYRIC,
1896                                        ((mixer_options & WM_MO_TEXTASLYRIC) ^ WM_MO_TEXTASLYRIC));
1897                     mixer_options ^= WM_MO_TEXTASLYRIC;
1898                     break;
1899                 case 'n':
1900                     goto NEXTMIDI;
1901                 case 'p':
1902                     if (inpause) {
1903                         inpause = 0;
1904                         fprintf(stderr, "       \r");
1905                         resume_output();
1906                     } else {
1907                         inpause = 1;
1908                         fprintf(stderr, "Paused \r");
1909                         pause_output();
1910                         continue;
1911                     }
1912                     break;
1913                 case 'q':
1914                     printf("\r\n");
1915                     if (inpause) goto end2;
1916                     goto end1;
1917                 case '-':
1918                     if (master_volume > 0) {
1919                         master_volume--;
1920                         WildMidi_MasterVolume(master_volume);
1921                     }
1922                     break;
1923                 case '+':
1924                     if (master_volume < 127) {
1925                         master_volume++;
1926                         WildMidi_MasterVolume(master_volume);
1927                     }
1928                     break;
1929                 case ',': /* fast seek backwards */
1930                     if (wm_info->current_sample < rate) {
1931                         seek_to_sample = 0;
1932                     } else {
1933                         seek_to_sample = wm_info->current_sample - rate;
1934                     }
1935                     WildMidi_FastSeek(midi_ptr, &seek_to_sample);
1936                     break;
1937                 case '.': /* fast seek forwards */
1938                     if ((wm_info->approx_total_samples
1939                             - wm_info->current_sample) < rate) {
1940                         seek_to_sample = wm_info->approx_total_samples;
1941                     } else {
1942                         seek_to_sample = wm_info->current_sample + rate;
1943                     }
1944                     WildMidi_FastSeek(midi_ptr, &seek_to_sample);
1945                     break;
1946                 case '<':
1947                     WildMidi_SongSeek (midi_ptr, -1);
1948                     break;
1949                 case '>':
1950                     WildMidi_SongSeek (midi_ptr, 1);
1951                     break;
1952                 case '/':
1953                     WildMidi_SongSeek (midi_ptr, 0);
1954                     break;
1955                 case 'm': /* save as midi */ {
1956                     int8_t *getmidibuffer = NULL;
1957                     uint32_t getmidisize = 0;
1958                     int32_t getmidiret = 0;
1959 
1960                     getmidiret = WildMidi_GetMidiOutput(midi_ptr, &getmidibuffer, &getmidisize);
1961                     if (getmidiret == -1) {
1962                         fprintf(stderr, "\r\n\nFAILED to convert events to midi\r\n");
1963                         ret_err = WildMidi_GetError();
1964                         fprintf(stderr, "%s\r\n",ret_err);
1965                         WildMidi_ClearError();
1966                     } else {
1967                         char *real_file = FIND_LAST_DIRSEP(argv[optind-1]);
1968                         if (!real_file) real_file = argv[optind];
1969                         else real_file++;
1970 
1971                         strncpy(midi_file, real_file, strlen(real_file));
1972                         midi_file[strlen(real_file)-4] = '.';
1973                         midi_file[strlen(real_file)-3] = 'm';
1974                         midi_file[strlen(real_file)-2] = 'i';
1975                         midi_file[strlen(real_file)-1] = 'd';
1976 
1977                         printf("\rWriting %s: %u bytes.\r\n", midi_file, getmidisize);
1978                         write_midi_output(getmidibuffer,getmidisize);
1979                         free(getmidibuffer);
1980                     }
1981                   } break;
1982                 case 'k': /* Kareoke */
1983                           /* Enables/Disables the display of lyrics */
1984                     kareoke ^= 1;
1985                     break;
1986                 default:
1987                     break;
1988                 }
1989             }
1990 
1991             if (inpause) {
1992                 wm_info = WildMidi_GetInfo(midi_ptr);
1993                 perc_play = (wm_info->current_sample * 100)
1994                             / wm_info->approx_total_samples;
1995                 pro_mins = wm_info->current_sample / (rate * 60);
1996                 pro_secs = (wm_info->current_sample % (rate * 60)) / rate;
1997                 fprintf(stderr,
1998                         "%s [%s] [%3i] [%2um %2us Processed] [%2u%%] P  \r",
1999                         display_lyrics, modes, (int)master_volume, pro_mins,
2000                         pro_secs, perc_play);
2001                 msleep(5);
2002                 continue;
2003             }
2004 
2005             if (play_to != 0) {
2006                 if ((wm_info->current_sample + 4096) <= play_to) {
2007                     samples = 16384;
2008                 } else {
2009                     samples = (play_to - wm_info->current_sample) << 2;
2010                     if (!samples) {
2011                         // We are at or past where we wanted to play to
2012                         break;
2013                     }
2014                 }
2015             }
2016             else {
2017                 samples = 16384;
2018             }
2019             res = WildMidi_GetOutput(midi_ptr, output_buffer, samples);
2020 
2021             if (res <= 0)
2022                 break;
2023 
2024             wm_info = WildMidi_GetInfo(midi_ptr);
2025             lyric = WildMidi_GetLyric(midi_ptr);
2026 
2027             memmove(lyrics, &lyrics[1], MAX_LYRIC_CHAR - 1);
2028             lyrics[MAX_LYRIC_CHAR - 1] = ' ';
2029 
2030             if ((lyric != NULL) && (lyric != last_lyric) && (kareoke)) {
2031                 last_lyric = lyric;
2032                 if (last_lyric_length != 0) {
2033                     memcpy(lyrics, &lyrics[last_lyric_length], MAX_LYRIC_CHAR - last_lyric_length);
2034                 }
2035                 memcpy(&lyrics[MAX_DISPLAY_LYRICS], lyric, strlen(lyric));
2036                 last_lyric_length = strlen(lyric);
2037             } else {
2038                 if (last_lyric_length != 0) last_lyric_length--;
2039             }
2040 
2041             memcpy(display_lyrics,lyrics,MAX_DISPLAY_LYRICS);
2042             display_lyrics[MAX_DISPLAY_LYRICS] = '\0';
2043 
2044             perc_play = (wm_info->current_sample * 100)
2045                         / wm_info->approx_total_samples;
2046             pro_mins = wm_info->current_sample / (rate * 60);
2047             pro_secs = (wm_info->current_sample % (rate * 60)) / rate;
2048             fprintf(stderr,
2049                 "%s [%s] [%3i] [%2um %2us Processed] [%2u%%] %c  \r",
2050                 display_lyrics, modes, (int)master_volume, pro_mins,
2051                 pro_secs, perc_play, spinner[spinpoint++ % 4]);
2052 
2053             if (send_output(output_buffer, res) < 0) {
2054             /* driver prints an error message already. */
2055                 printf("\r");
2056                 goto end2;
2057             }
2058         }
2059         NEXTMIDI: fprintf(stderr, "\r\n");
2060         if (WildMidi_Close(midi_ptr) == -1) {
2061             ret_err = WildMidi_GetError();
2062             fprintf(stderr, "OOPS: failed closing midi handle!\r\n%s\r\n",ret_err);
2063         }
2064         memset(output_buffer, 0, 16384);
2065         send_output(output_buffer, 16384);
2066     }
2067 end1: memset(output_buffer, 0, 16384);
2068     send_output(output_buffer, 16384);
2069     msleep(5);
2070 end2: close_output();
2071     free(output_buffer);
2072     if (WildMidi_Shutdown() == -1) {
2073         ret_err = WildMidi_GetError();
2074         fprintf(stderr, "OOPS: failure shutting down libWildMidi\r\n%s\r\n", ret_err);
2075         WildMidi_ClearError();
2076     }
2077     wm_resetty();
2078 
2079     printf("\r\n");
2080     return (0);
2081 }
2082 
2083 /* helper / replacement functions: */
2084 
2085 #if !(defined(_WIN32) || defined(__DJGPP__) || defined(WILDMIDI_AMIGA) || defined(__OS2__) || defined(__EMX__))
msleep(unsigned long milisec)2086 static int msleep(unsigned long milisec) {
2087     struct timespec req = { 0, 0 };
2088     time_t sec = (int) (milisec / 1000);
2089     milisec = milisec - (sec * 1000);
2090     req.tv_sec = sec;
2091     req.tv_nsec = milisec * 1000000L;
2092     while (nanosleep(&req, &req) == -1)
2093         continue;
2094     return (1);
2095 }
2096 #endif
2097