source: GPL/branches/uniaud-2.0/lib32/fminstrload.c@ 305

Last change on this file since 305 was 305, checked in by Paul Smedley, 17 years ago

Update source to ALSA 1.0.16 level

File size: 14.5 KB
Line 
1/*
2 * FM instrument loader
3 *
4 * (C) 2002 InnoTek Systemberatung GmbH
5 * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/core.h>
24#include <sound/control.h>
25#include <sound/info.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/minors.h>
29#include <sound/asequencer.h>
30#include <sound/asound_fm.h>
31//#include <sound/ainstr_fm.h>
32#include <sound/seq_kernel.h>
33#include <sound/instr.h>
34#include <linux/file.h>
35#include <linux/soundcard.h>
36
37#define LINUX
38#include <ossidc32.h>
39#include <stacktoflat.h>
40#include <stdlib.h>
41#include "soundoss.h"
42#include "instrfm.h"
43
44#define assert(a)
45
46typedef struct sbi_header
47{
48 char key[4];
49 char name[32];
50}
51sbi_header_t;
52
53typedef struct sbi_inst
54{
55 sbi_header_t header;
56#define DATA_LEN_2OP 16
57#define DATA_LEN_4OP 24
58 char data[DATA_LEN_4OP];
59}
60sbi_inst_t;
61
62/* offsets for SBI params */
63#define AM_VIB 0
64#define KSL_LEVEL 2
65#define ATTACK_DECAY 4
66#define SUSTAIN_RELEASE 6
67#define WAVE_SELECT 8
68
69/* offset for SBI instrument */
70#define CONNECTION 10
71#define OFFSET_4OP 11
72
73/* offsets in sbi_header.name for SBI extensions */
74#define ECHO_DELAY 25
75#define ECHO_ATTEN 26
76#define CHORUS_SPREAD 27
77#define TRNSPS 28
78#define FIX_DUR 29
79#define MODES 30
80#define FIX_KEY 31
81
82/* Number of elements in an array */
83#define NELEM(a) ( sizeof(a)/sizeof((a)[0]) )
84
85#define ADDR_PARTS 4 /* Number of part in a port description addr 1:2:3:4 */
86#define SEP ", \t" /* Separators for port description */
87
88#define SBI_FILE_TYPE_2OP 0
89#define SBI_FILE_TYPE_4OP 1
90
91static BOOL fInstumentsLoaded = FALSE;
92/* Default file type */
93static int file_type = SBI_FILE_TYPE_2OP;
94
95
96static void load_sb (midihandle *pHandle, char *pFile, int filesize, int bank);
97
98//******************************************************************************
99//******************************************************************************
100OSSRET OSS32_FMMidiLoadInstruments(OSSSTREAMID streamid)
101{
102 midihandle *pHandle = (midihandle *)streamid;
103
104 if(pHandle == NULL || pHandle->magic != MAGIC_MIDI_ALSA32) {
105 DebugInt3();
106 return OSSERR_INVALID_STREAMID;
107 }
108 if(fInstumentsLoaded) return OSSERR_SUCCESS;
109 fInstumentsLoaded = TRUE;
110
111 file_type = SBI_FILE_TYPE_4OP;
112
113 //set operation to non-blocking
114 pHandle->file.f_flags = O_NONBLOCK;
115
116 //load instruments
117 load_sb(pHandle, stdopl3, sizeof(stdopl3), 0);
118
119 //load drums
120 load_sb(pHandle, drumsopl3, sizeof(drumsopl3), 128);
121
122 return OSSERR_SUCCESS;
123}
124//******************************************************************************
125//******************************************************************************
126
127#if 0
128//def DEBUG
129/*
130 * Show instrument FM operators
131 */
132static void
133show_op (fm_instrument_t * fm_instr) {
134 int i = 0;
135
136 do {
137 dprintf( (" OP%d: flags: %s %s %s %s\011OP%d: flags: %s %s %s %s\n",
138 i,
139 fm_instr->op[i].am_vib & (1 << 7) ? "AM" : " ",
140 fm_instr->op[i].am_vib & (1 << 6) ? "VIB" : " ",
141 fm_instr->op[i].am_vib & (1 << 5) ? "EGT" : " ",
142 fm_instr->op[i].am_vib & (1 << 4) ? "KSR" : " ",
143 i + 1,
144 fm_instr->op[i + 1].am_vib & (1 << 7) ? "AM" : " ",
145 fm_instr->op[i + 1].am_vib & (1 << 6) ? "VIB" : " ",
146 fm_instr->op[i + 1].am_vib & (1 << 5) ? "EGT" : " ",
147 fm_instr->op[i + 1].am_vib & (1 << 4) ? "KSR" : ""));
148 dprintf((" OP%d: MULT = 0x%x" "\011\011OP%d: MULT = 0x%x\n",
149 i, fm_instr->op[i].am_vib & 0x0f,
150 i + 1, fm_instr->op[i + 1].am_vib & 0x0f));
151 dprintf((" OP%d: KSL = 0x%x TL = 0x%x\011OP%d: KSL = 0x%x TL = 0x%x\n",
152 i, (fm_instr->op[i].ksl_level >> 6) & 0x03, fm_instr->op[i].ksl_level & 0x3f,
153 i + 1, (fm_instr->op[i + 1].ksl_level >> 6) & 0x03, fm_instr->op[i + 1].ksl_level & 0x3f));
154 dprintf((" OP%d: AR = 0x%x DL = 0x%x\011OP%d: AR = 0x%x DL = 0x%x\n",
155 i, (fm_instr->op[i].attack_decay >> 4) & 0x0f, fm_instr->op[i].attack_decay & 0x0f,
156 i + 1, (fm_instr->op[i + 1].attack_decay >> 4) & 0x0f, fm_instr->op[i + 1].attack_decay & 0x0f));
157 dprintf((" OP%d: SL = 0x%x RR = 0x%x\011OP%d: SL = 0x%x RR = 0x%x\n",
158 i, (fm_instr->op[i].sustain_release >> 4) & 0x0f, fm_instr->op[i].sustain_release & 0x0f,
159 i + 1, (fm_instr->op[i + 1].sustain_release >> 4) & 0x0f, fm_instr->op[i + 1].sustain_release & 0x0f));
160 dprintf((" OP%d: WS = 0x%x\011\011OP%d: WS = 0x%x\n",
161 i, fm_instr->op[i].wave_select & 0x07,
162 i + 1, fm_instr->op[i + 1].wave_select & 0x07));
163 dprintf((" FB = 0x%x, %s\n",
164 (fm_instr->feedback_connection[i / 2] >> 1) & 0x07,
165 fm_instr->feedback_connection[i / 2] & (1 << 0) ? "parallel" : "serial"));
166 i += 2;
167 }
168 while (i == (fm_instr->type == FM_PATCH_OPL3) << 1);
169
170 dprintf((" Extended data:\n"
171 " ED = %d EA = %d CS = %d TR = %d\n"
172 " FD = %d MO = %d FK = %d\n",
173 fm_instr->echo_delay, fm_instr->echo_atten, fm_instr->chorus_spread, fm_instr->trnsps,
174 fm_instr->fix_dur, fm_instr->modes, fm_instr->fix_key));
175}
176#endif
177
178/*
179 * Send patch to destination port
180 */
181static int load_patch (midihandle *pHandle, struct fm_instrument * fm_instr, int bank, int prg, char *name)
182{
183 struct sndrv_seq_instr_header *put;
184 struct sndrv_seq_instr id;
185 struct sndrv_seq_event ev;
186
187 size_t size;
188 int err;
189
190#ifdef DEBUG
191// show_op (fm_instr);
192#endif
193 if ((err = snd_instr_fm_convert_to_stream (fm_instr, name, &put, &size)) < 0) {
194 dprintf(("Unable to convert instrument %.3i to stream", prg));
195 return -1;
196 }
197 memset(&id, 0, sizeof(id));
198 id.std = SND_SEQ_INSTR_TYPE2_OPL2_3;
199 id.prg = prg;
200 id.bank = bank;
201 snd_instr_header_set_id(put, &id);
202
203 /* build event */
204 memset (&ev, 0, sizeof (ev));
205 ev.source.client = pHandle->clientid;
206 ev.source.port = pHandle->clientport;
207 ev.dest.client = pHandle->destclient;
208 ev.dest.port = pHandle->destport;
209
210 ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR;
211 ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
212
213 ev.type = SNDRV_SEQ_EVENT_INSTR_PUT;
214 ev.data.ext.len = size;
215 ev.data.ext.ptr = put;
216
217 err = pHandle->file.f_op->write(&pHandle->file, (char *)__Stack32ToFlat(&ev), sizeof(ev), &pHandle->file.f_pos);
218 if(err < 0) {
219 dprintf(("Unable to write an instrument %.3i put event: %x",prg, err));
220 return -1;
221 }
222 return 0;
223}
224
225/*
226 * Parse standard .sb or .o3 file
227 */
228static void load_sb (midihandle *pHandle, char *pFile, int filesize, int bank)
229{
230 int len, i, offset = 0;
231 int prg;
232
233 sbi_inst_t sbi_instr;
234 struct fm_instrument fm_instr;
235 int fm_instr_type;
236
237 len = (file_type == SBI_FILE_TYPE_4OP) ? DATA_LEN_4OP : DATA_LEN_2OP;
238 for (prg = 0;; prg++) {
239 if(offset + sizeof (sbi_header_t) > filesize) {
240 break; //EOF
241 }
242 memcpy(&sbi_instr.header, pFile+offset, sizeof (sbi_header_t));
243 offset += sizeof (sbi_header_t);
244
245 if (!strncmp (sbi_instr.header.key, "SBI\032", 4) || !strncmp (sbi_instr.header.key, "2OP\032", 4)) {
246 fm_instr_type = FM_PATCH_OPL2;
247 }
248 else
249 if (!strncmp (sbi_instr.header.key, "4OP\032", 4)) {
250 fm_instr_type = FM_PATCH_OPL3;
251 }
252 else {
253 fm_instr_type = 0;
254 }
255 if(offset + len > filesize) {
256 break; //EOF
257 }
258 memcpy(&sbi_instr.data, pFile+offset, len);
259 offset += len;
260
261 if (fm_instr_type == 0)
262 continue;
263
264 memset (&fm_instr, 0, sizeof (fm_instr));
265 fm_instr.type = fm_instr_type;
266
267 for (i = 0; i < 2; i++) {
268 fm_instr.op[i].am_vib = sbi_instr.data[AM_VIB + i];
269 fm_instr.op[i].ksl_level = sbi_instr.data[KSL_LEVEL + i];
270 fm_instr.op[i].attack_decay = sbi_instr.data[ATTACK_DECAY + i];
271 fm_instr.op[i].sustain_release = sbi_instr.data[SUSTAIN_RELEASE + i];
272 fm_instr.op[i].wave_select = sbi_instr.data[WAVE_SELECT + i];
273 }
274 fm_instr.feedback_connection[0] = sbi_instr.data[CONNECTION];
275
276 if (fm_instr_type == FM_PATCH_OPL3) {
277 for (i = 0; i < 2; i++) {
278 fm_instr.op[i + 2].am_vib = sbi_instr.data[OFFSET_4OP + AM_VIB + i];
279 fm_instr.op[i + 2].ksl_level = sbi_instr.data[OFFSET_4OP + KSL_LEVEL + i];
280 fm_instr.op[i + 2].attack_decay = sbi_instr.data[OFFSET_4OP + ATTACK_DECAY + i];
281 fm_instr.op[i + 2].sustain_release = sbi_instr.data[OFFSET_4OP + SUSTAIN_RELEASE + i];
282 fm_instr.op[i + 2].wave_select = sbi_instr.data[OFFSET_4OP + WAVE_SELECT + i];
283 }
284 fm_instr.feedback_connection[1] = sbi_instr.data[OFFSET_4OP + CONNECTION];
285 }
286
287 fm_instr.echo_delay = sbi_instr.header.name[ECHO_DELAY];
288 fm_instr.echo_atten = sbi_instr.header.name[ECHO_ATTEN];
289 fm_instr.chorus_spread = sbi_instr.header.name[CHORUS_SPREAD];
290 fm_instr.trnsps = sbi_instr.header.name[TRNSPS];
291 fm_instr.fix_dur = sbi_instr.header.name[FIX_DUR];
292 fm_instr.modes = sbi_instr.header.name[MODES];
293 fm_instr.fix_key = sbi_instr.header.name[FIX_KEY];
294
295 if (load_patch (pHandle, &fm_instr, bank, prg, sbi_instr.header.name) < 0)
296 break;
297 }
298 return;
299}
300/**
301 * \brief Convert the FM instrument to byte stream
302 * \param fm FM instrument handle
303 * \param name FM instrument name
304 * \param __data Result - allocated byte stream
305 * \param __size Result - size of allocated byte stream
306 * \return 0 on success otherwise a negative error code
307 */
308int snd_instr_fm_convert_to_stream(snd_instr_fm_t *fm,
309 const char *name,
310 snd_instr_header_t **__data,
311 size_t *__size)
312{
313 struct snd_instr_header *put;
314 struct fm_instrument *instr;
315 fm_xinstrument_t *xinstr;
316 int idx;
317
318 if (fm == NULL || __data == NULL)
319 return -EINVAL;
320 instr = (struct fm_instrument *)fm;
321 *__data = NULL;
322 *__size = 0;
323 if (snd_instr_header_malloc(&put, sizeof(fm_xinstrument_t)) < 0)
324 return -ENOMEM;
325 /* build header */
326 if (name)
327 snd_instr_header_set_name(put, name);
328 snd_instr_header_set_type(put, SND_SEQ_INSTR_ATYPE_DATA);
329 snd_instr_header_set_format(put, SND_SEQ_INSTR_ID_OPL2_3);
330 /* build data section */
331 xinstr = (fm_xinstrument_t *)snd_instr_header_get_data(put);
332 xinstr->stype = FM_STRU_INSTR;
333 xinstr->share_id[0] = __cpu_to_le32(instr->share_id[0]);
334 xinstr->share_id[1] = __cpu_to_le32(instr->share_id[1]);
335 xinstr->share_id[2] = __cpu_to_le32(instr->share_id[2]);
336 xinstr->share_id[3] = __cpu_to_le32(instr->share_id[3]);
337 xinstr->type = instr->type;
338 for (idx = 0; idx < 4; idx++) {
339 xinstr->op[idx].am_vib = instr->op[idx].am_vib;
340 xinstr->op[idx].ksl_level = instr->op[idx].ksl_level;
341 xinstr->op[idx].attack_decay = instr->op[idx].attack_decay;
342 xinstr->op[idx].sustain_release = instr->op[idx].sustain_release;
343 xinstr->op[idx].wave_select = instr->op[idx].wave_select;
344 }
345 for (idx = 0; idx < 2; idx++) {
346 xinstr->feedback_connection[idx] = instr->feedback_connection[idx];
347 }
348 xinstr->echo_delay = instr->echo_delay;
349 xinstr->echo_atten = instr->echo_atten;
350 xinstr->chorus_spread = instr->chorus_spread;
351 xinstr->trnsps = instr->trnsps;
352 xinstr->fix_dur = instr->fix_dur;
353 xinstr->modes = instr->modes;
354 xinstr->fix_key = instr->fix_key;
355
356 /* write result */
357 *__data = put;
358 *__size = sizeof(*put) + sizeof(fm_xinstrument_t);
359 return 0;
360}
361/**
362 * \brief allocate an empty #snd_instr_header_t using standard malloc
363 * \param ptr returned pointer
364 * \param len additional data length
365 * \return 0 on success otherwise negative error code
366 */
367int snd_instr_header_malloc(snd_instr_header_t **ptr, size_t len)
368{
369 assert(ptr);
370 *ptr = kmalloc(sizeof(snd_instr_header_t) + len, 0);
371 if (!*ptr)
372 return -ENOMEM;
373
374 memset(*ptr, 0, sizeof(snd_instr_header_t) + len);
375 (*ptr)->len = len;
376
377 return 0;
378}
379
380/**
381 * \brief frees a previously allocated #snd_instr_header_t
382 * \param pointer to object to free
383 */
384void snd_instr_header_free(snd_instr_header_t *obj)
385{
386 kfree(obj);
387}
388/**
389 * \brief Set the data type of an instr_header container
390 * \param info instr_header container
391 * \param type the data type
392 */
393void snd_instr_header_set_type(snd_instr_header_t *info, int type)
394{
395 assert(info);
396 info->data.type = type;
397}
398
399/**
400 * \brief Set the data format of an instr_header container
401 * \param info instr_header container
402 * \param format the data format string
403 */
404void snd_instr_header_set_format(snd_instr_header_t *info, const char *format)
405{
406 assert(info && format);
407 strncpy(info->data.data.format, format, sizeof(info->data.data.format));
408}
409
410/**
411 * \brief Set the instrument id of an instr_header container
412 * \param info instr_header container
413 * \param id instrument id pointer
414 */
415void snd_instr_header_set_id(snd_instr_header_t *info, const snd_seq_instr_t *id)
416{
417 assert(info && id);
418// info->id.instr = *(struct snd_seq_instr *)id;
419 info->id.instr = *id;
420}
421
422/**
423 * \brief Set the data name of an instr_header container
424 * \param info instr_header container
425 * \param name the name string
426 */
427void snd_instr_header_set_name(snd_instr_header_t *info, const char *name)
428{
429 assert(info && name);
430 strncpy(info->data.name, name, sizeof(info->data.name));
431}
432
433/**
434 * \brief Get the extra data pointer of an instr_header container
435 * \param info instr_header container
436 * \return the extra data pointer
437 */
438void *snd_instr_header_get_data(const snd_instr_header_t *info)
439{
440 assert(info);
441 return (void*)((char*)info + sizeof(*info));
442}
443
444//******************************************************************************
445//******************************************************************************
446
Note: See TracBrowser for help on using the repository browser.