This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / i386 / isa / sound / gustest / pmtest.c
CommitLineData
78ed81a3 1/*
2 * CAUTION! This program is just an incompletely implemented version
3 * of the patch manager daemon for GUS. Using this program
4 * with the driver version 1.99.9 will hang your system
5 * completely (sooner or later).
6 *
7 * This program is for information only. The final
8 * implementation of the patch manager will not be
9 * compatible with this one.
10 */
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <sys/ioctl.h>
16#include <sys/soundcard.h>
17#include <sys/ultrasound.h>
18#include <strings.h>
19#include <sys/errno.h>
20#include "gmidi.h"
21
22#ifndef PATCH_PATH
23#define PATCH_PATH "/D/ultrasnd/midi"
24#endif
25
26char loadmap[256] =
27{0}; /* 1 if the patch is already loaded */
28
29struct pat_header
30 {
31 char magic[12];
32 char version[10];
33 char description[60];
34 unsigned char instruments;
35 char voices;
36 char channels;
37 unsigned short nr_waveforms;
38 unsigned short master_volume;
39 unsigned long data_size;
40 };
41
42struct sample_header
43 {
44 char name[7];
45 unsigned char fractions;
46 long len;
47 long loop_start;
48 long loop_end;
49 unsigned short base_freq;
50 long low_note;
51 long high_note;
52 long base_note;
53 short detune;
54 unsigned char panning;
55
56 unsigned char envelope_rate[6];
57 unsigned char envelope_offset[6];
58
59 unsigned char tremolo_sweep;
60 unsigned char tremolo_rate;
61 unsigned char tremolo_depth;
62
63 unsigned char vibrato_sweep;
64 unsigned char vibrato_rate;
65 unsigned char vibrato_depth;
66
67 char modes;
68
69 short scale_frequency;
70 unsigned short scale_factor;
71 };
72int seqfd = 0, gus_dev = -1;
73
74struct patch_info *patch;
75
76int
77do_load_patch (struct patmgr_info *rec)
78{
79 int i, patfd, pgm, print_only = 0;
80 struct pat_header header;
81 struct sample_header sample;
82 char buf[256];
83 char name[256];
84 long offset;
85
86 pgm = rec->data.data8[0];
87
88 if (loadmap[pgm])
89 return 0; /* Already loaded */
90
91 sprintf (name, PATCH_PATH "/%s.pat", patch_names[pgm]);
92
93 if ((patfd = open (name, O_RDONLY, 0)) == -1)
94 {
95 perror (name);
96 return errno;
97 }
98
99 if (read (patfd, buf, 0xef) != 0xef)
100 {
101 fprintf (stderr, "%s: Short file\n", name);
102 return EIO;
103 }
104
105 memcpy ((char *) &header, buf, sizeof (header));
106
107 if (strncmp (header.magic, "GF1PATCH110", 12))
108 {
109 fprintf (stderr, "%s: Not a patch file\n", name);
110 return EINVAL;
111 }
112
113 if (strncmp (header.version, "ID#000002", 10))
114 {
115 fprintf (stderr, "%s: Incompatible patch file version\n", name);
116 return EINVAL;
117 }
118
119 header.nr_waveforms = *(unsigned short *) &buf[85];
120 header.master_volume = *(unsigned short *) &buf[87];
121
122 printf ("GUS: Loading: %s\n", name);
123
124 offset = 0xef;
125
126 for (i = 0; i < header.nr_waveforms; i++)
127 {
128 if (lseek (patfd, offset, 0) == -1)
129 {
130 perror (name);
131 return errno;
132 }
133
134 if (read (patfd, &buf, sizeof (sample)) != sizeof (sample))
135 {
136 fprintf (stderr, "%s: Short file\n", name);
137 return EIO;
138 }
139
140 memcpy ((char *) &sample, buf, sizeof (sample));
141
142 /*
143 * Since some fields of the patch record are not 32bit aligned, we must
144 * handle them specially.
145 */
146 sample.low_note = *(long *) &buf[22];
147 sample.high_note = *(long *) &buf[26];
148 sample.base_note = *(long *) &buf[30];
149 sample.detune = *(short *) &buf[34];
150 sample.panning = (unsigned char) buf[36];
151
152 memcpy (sample.envelope_rate, &buf[37], 6);
153 memcpy (sample.envelope_offset, &buf[43], 6);
154
155 sample.tremolo_sweep = (unsigned char) buf[49];
156 sample.tremolo_rate = (unsigned char) buf[50];
157 sample.tremolo_depth = (unsigned char) buf[51];
158
159 sample.vibrato_sweep = (unsigned char) buf[52];
160 sample.vibrato_rate = (unsigned char) buf[53];
161 sample.vibrato_depth = (unsigned char) buf[54];
162 sample.modes = (unsigned char) buf[55];
163 sample.scale_frequency = *(short *) &buf[56];
164 sample.scale_factor = *(unsigned short *) &buf[58];
165
166 if (print_only)
167 {
168 printf ("\nSample: %03d / %s\n", i, sample.name);
169 printf ("Len: %d, Loop start: %d, Loop end: %d\n", sample.len, sample.loop_start, sample.loop_end);
170 printf ("Flags: ");
171 if (sample.modes & WAVE_16_BITS)
172 printf ("16 bit ");
173 if (sample.modes & WAVE_UNSIGNED)
174 printf ("unsigned ");
175 if (sample.modes & WAVE_LOOP_BACK)
176 printf ("reverse ");
177 if (sample.modes & WAVE_BIDIR_LOOP)
178 printf ("bidir ");
179 if (sample.modes & WAVE_LOOPING)
180 printf ("looping ");
181 else
182 printf ("one_shot");
183 if (sample.modes & WAVE_SUSTAIN_ON)
184 printf ("sustain ");
185 if (sample.modes & WAVE_ENVELOPES)
186 printf ("enveloped ");
187 printf ("\n");
188
189 if (sample.modes & WAVE_ENVELOPES)
190 {
191 int i;
192
193 printf ("Envelope info: ");
194 for (i = 0; i < 6; i++)
195 {
196 printf ("%d/%d ", sample.envelope_rate[i],
197 sample.envelope_offset[i]);
198 }
199 printf ("\n");
200 }
201
202 printf ("Tremolo: sweep=%d, rate=%d, depth=%d\n",
203 sample.tremolo_sweep,
204 sample.tremolo_rate,
205 sample.tremolo_depth);
206
207 printf ("Vibrato: sweep=%d, rate=%d, depth=%d\n",
208 sample.vibrato_sweep,
209 sample.vibrato_rate,
210 sample.vibrato_depth);
211 }
212
213 offset = offset + 96;
214 patch = (struct patch_info *) malloc (sizeof (*patch) + sample.len);
215
216 patch->key = GUS_PATCH;
217 patch->device_no = gus_dev;
218 patch->instr_no = pgm;
219 patch->mode = sample.modes | WAVE_TREMOLO |
220 WAVE_VIBRATO | WAVE_SCALE;
221 patch->len = sample.len;
222 patch->loop_start = sample.loop_start;
223 patch->loop_end = sample.loop_end;
224 patch->base_note = sample.base_note;
225 patch->high_note = sample.high_note;
226 patch->low_note = sample.low_note;
227 patch->base_freq = sample.base_freq;
228 patch->detuning = sample.detune;
229 patch->panning = (sample.panning - 7) * 16;
230
231 memcpy (patch->env_rate, sample.envelope_rate, 6);
232 memcpy (patch->env_offset, sample.envelope_offset, 6);
233
234 patch->tremolo_sweep = sample.tremolo_sweep;
235 patch->tremolo_rate = sample.tremolo_rate;
236 patch->tremolo_depth = sample.tremolo_depth;
237
238 patch->vibrato_sweep = sample.vibrato_sweep;
239 patch->vibrato_rate = sample.vibrato_rate;
240 patch->vibrato_depth = sample.vibrato_depth;
241
242 patch->scale_frequency = sample.scale_frequency;
243 patch->scale_factor = sample.scale_factor;
244
245 patch->volume = header.master_volume;
246
247 if (lseek (patfd, offset, 0) == -1)
248 {
249 perror (name);
250 return errno;
251 }
252
253 if (!print_only)
254 {
255 if (read (patfd, patch->data, sample.len) != sample.len)
256 {
257 fprintf (stderr, "%s: Short file\n", name);
258 return EIO;
259 }
260
261 if (write (seqfd, patch, sizeof (*patch) + sample.len) == -1)
262 {
263 perror ("/dev/pmgr0");
264 return errno;
265 }
266 }
267
268 offset = offset + sample.len;
269 }
270
271 loadmap[pgm] = 1;
272 return 0;
273}
274
275int
276main (int argc, char *argv[])
277{
278 struct patmgr_info inf;
279 int err, i, n;
280 struct synth_info info;
281
282 if ((seqfd = open ("/dev/patmgr0", O_RDWR, 0)) == -1)
283 {
284 fprintf (stderr, "Cannot open\n");
285 perror ("/dev/patmgr0");
286 exit (-1);
287 }
288
289 if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
290 {
291 perror ("NRSYNTH: /dev/patmgr0");
292 exit (-1);
293 }
294
295 for (i = 0; i < n; i++)
296 {
297 info.device = i;
298
299 if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
300 {
301 perror ("SYNTH_INFO: /dev/patmgr0");
302 exit (-1);
303 }
304
305 if (info.synth_type == SYNTH_TYPE_SAMPLE
306 && info.synth_subtype == SAMPLE_TYPE_GUS)
307 gus_dev = i;
308 }
309
310 if (gus_dev == -1)
311 {
312 fprintf (stderr, "Error: Gravis Ultrasound not detected\n");
313 exit (-1);
314 }
315
316 if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
317 perror ("Sample reset");
318
319 for (i = 0; i < 256; i++)
320 loadmap[i] = 0;
321
322 while (1)
323 {
324 if (read (seqfd, (char *) &inf, sizeof (inf)) != sizeof (inf))
325 {
326 perror ("Read");
327 exit (-1);
328 }
329
330 if (inf.key == PM_K_EVENT)
331 switch (inf.command)
332 {
333 case PM_E_OPENED:
334 printf ("Opened\n");
335 break;
336
337 case PM_E_CLOSED:
338 printf ("Closed\n");
339 if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
340 perror ("Sample reset");
341 for (i = 0; i < 256; i++)
342 loadmap[i] = 0;
343 break;
344
345 case PM_E_PATCH_RESET:
346 printf ("Patch reset called\n");
347 for (i = 0; i < 256; i++)
348 loadmap[i] = 0;
349 break;
350
351 case PM_E_PATCH_LOADED:
352 printf ("Patch loaded by client\n");
353 break;
354
355 default:
356 printf ("Unknown event %d\n", inf.command);
357 inf.key = PM_ERROR;
358 inf.parm1 = EINVAL;
359 }
360 else if (inf.key == PM_K_COMMAND)
361 switch (inf.command)
362 {
363 case _PM_LOAD_PATCH:
364 if ((err = do_load_patch (&inf)))
365 if (err == ENOSPC)
366 {
367 if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
368 {
369 perror ("Sample reset");
370 return errno;
371 }
372
373 for (i = 0; i < 256; i++)
374 loadmap[i] = 0;
375 err = do_load_patch (&inf);
376 }
377
378 if (err)
379 {
380 inf.key = PM_ERROR;
381 inf.parm1 = err;
382 printf("Error = %d\n", err);
383 }
384 else
385 {
386 inf.key = PM_K_COMMAND;
387 inf.parm1 = 0;
388 }
389 break;
390
391 default:
392 printf ("Unknown command %d\n", inf.command);
393 inf.key = PM_ERROR;
394 inf.parm1 = EINVAL;
395 }
396 else
397 {
398 printf ("Unknown event %d/%d\n", inf.key, inf.command);
399 inf.key = PM_ERROR;
400 inf.parm1 = EINVAL;
401 }
402
403 if (write (seqfd, (char *) &inf, sizeof (inf)) != sizeof (inf))
404 {
405 perror ("write");
406 exit (-1);
407 }
408 }
409
410 exit (0);
411}