source: GPL/branches/uniaud32-2.1.x/lib32/fminstrload.c@ 519

Last change on this file since 519 was 519, checked in by David Azarewicz, 15 years ago

Changes to PCI bus scan, malloc, cleanup all warnings, misc other changes

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.