mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
First IWFFFF code (instrument handling)...
This commit is contained in:
parent
2e07583858
commit
e0741a5863
7 changed files with 920 additions and 3 deletions
|
|
@ -31,5 +31,6 @@ SAVE_LIBRARY_VERSION
|
|||
AC_OUTPUT(Makefile doc/Makefile include/Makefile src/Makefile \
|
||||
src/control/Makefile src/mixer/Makefile src/pcm/Makefile \
|
||||
src/rawmidi/Makefile src/timer/Makefile src/seq/Makefile \
|
||||
src/instr/Makefile \
|
||||
test/Makefile utils/Makefile \
|
||||
utils/alsa-lib.spec)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ sysinclude_HEADERS = asoundlib.h
|
|||
# This is the order they will be concatenated into asoundlib.h!
|
||||
#
|
||||
header_files=header.h version.h error.h control.h mixer.h pcm.h rawmidi.h \
|
||||
timer.h seq.h footer.h
|
||||
timer.h seq.h conv.h instr.h footer.h
|
||||
|
||||
noinst_HEADERS=$(header_files)
|
||||
|
||||
|
|
|
|||
37
include/conv.h
Normal file
37
include/conv.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* conv.h *
|
||||
* Binary Value Conversion *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef SND_LITTLE_ENDIAN
|
||||
|
||||
#define snd_host_to_LE_16(val) (val)
|
||||
#define snd_LE_to_host_16(val) (val)
|
||||
#define snd_host_to_LE_32(val) (val)
|
||||
#define snd_LE_to_host_32(val) (val)
|
||||
#define snd_host_to_BE_16(val) ((((val)>>8)&0xff)|(((val)<<8)&0xff00))
|
||||
#define snd_BE_to_host_16(val) snd_host_to_BE_16(val)
|
||||
#define snd_host_to_BE_32(val) ((((val)>>24)&0xff)|(((val)>>16)&0xff00)|\
|
||||
(((val)<<16)&0xff0000)|(((val)<<24)&0xff000000)
|
||||
#define snd_BE_to_host_32(val) snd_host_to_BE_32(val)
|
||||
|
||||
#else
|
||||
|
||||
#define snd_host_to_BE_16(val) (val)
|
||||
#define snd_BE_to_host_16(val) (val)
|
||||
#define snd_host_to_BE_16(val) (val)
|
||||
#define snd_BE_to_host_16(val) (val)
|
||||
#define snd_host_to_LE_16(val) ((((val)>>8)&0xff)|(((val)<<8)&0xff00))
|
||||
#define snd_LE_to_host_16(val) snd_host_to_BE_16(val)
|
||||
#define snd_host_to_LE_32(val) ((((val)>>24)&0xff)|(((val)>>16)&0xff00)|\
|
||||
(((val)<<16)&0xff0000)|(((val)<<24)&0xff000000)
|
||||
#define snd_LE_to_host_32(val) snd_host_to_BE_32(val)
|
||||
|
||||
#endif
|
||||
|
||||
27
include/instr.h
Normal file
27
include/instr.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/****************************************************************************
|
||||
* *
|
||||
* instr.h *
|
||||
* Instrument Interface *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
typedef void snd_instr_iwffff_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* InterWave FFFF support */
|
||||
int snd_instr_iwffff_open(void **handle, const char *name_fff, const char *name_dta);
|
||||
int snd_instr_iwffff_open_rom(void **handle, int card, int bank, int file);
|
||||
int snd_instr_iwffff_open_rom_file(void **handle, const char *name, int bank, int file);
|
||||
int snd_instr_iwffff_close(void *handle);
|
||||
int snd_instr_iwffff_load(void *handle, int bank, int prg, snd_instr_iwffff_t **iwffff);
|
||||
int snd_instr_iwffff_convert_to_stream(snd_instr_iwffff_t *iwffff, const char *name, snd_seq_instr_data_t **data, int *size);
|
||||
int snd_instr_iwffff_convert_from_stream(snd_seq_instr_data_t *data, int size, snd_instr_iwffff_t **iwffff);
|
||||
int snd_instr_iwffff_free(snd_instr_iwffff_t *iwffff);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
SUBDIRS=control mixer pcm rawmidi timer seq
|
||||
SUBDIRS=control mixer pcm rawmidi timer seq instr
|
||||
|
||||
lib_LTLIBRARIES = libasound.la
|
||||
libasound_la_SOURCES = error.c
|
||||
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
|
||||
rawmidi/librawmidi.la timer/libtimer.la seq/libseq.la
|
||||
rawmidi/librawmidi.la timer/libtimer.la seq/libseq.la \
|
||||
instr/libinstr.la
|
||||
libasound_la_LDFLAGS = -version-info 3:0:3
|
||||
|
||||
control/libcontrol.la:
|
||||
|
|
|
|||
7
src/instr/Makefile.am
Normal file
7
src/instr/Makefile.am
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
EXTRA_LTLIBRARIES=libinstr.la
|
||||
|
||||
libinstr_la_SOURCES = iwffff.c
|
||||
all: libinstr.la
|
||||
|
||||
|
||||
INCLUDES=-I$(top_srcdir)/include
|
||||
844
src/instr/iwffff.c
Normal file
844
src/instr/iwffff.c
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
/*
|
||||
* InterWave FFFF Format Support
|
||||
* Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include "asoundlib.h"
|
||||
#include <linux/ainstr_iw.h>
|
||||
|
||||
/*
|
||||
* defines
|
||||
*/
|
||||
|
||||
#define IW_RAM_FILE "/proc/asound/%i/gus-ram-%i"
|
||||
#define IW_ROM_FILE "/proc/asound/%i/gus-rom-%i"
|
||||
|
||||
#undef IW_ROM_DEBUG
|
||||
|
||||
#define IW_ROM_PROGRAM_VERSION_MAJOR 1
|
||||
#define IW_ROM_PROGRAM_VERSION_MINOR 0
|
||||
|
||||
#define IW_FORMAT_8BIT 0x01
|
||||
#define IW_FORMAT_SIGNED 0x02
|
||||
#define IW_FORMAT_FORWARD 0x04
|
||||
#define IW_FORMAT_LOOP 0x08
|
||||
#define IW_FORMAT_BIDIR 0x10
|
||||
#define IW_FORMAT_ULAW 0x20
|
||||
#define IW_FORMAT_ROM 0x80
|
||||
|
||||
/*
|
||||
* structures
|
||||
*/
|
||||
|
||||
typedef __u32 ID;
|
||||
|
||||
struct header {
|
||||
ID id;
|
||||
__u32 length;
|
||||
};
|
||||
|
||||
struct program {
|
||||
/* 00 */ ID id;
|
||||
/* 04 */ ID version;
|
||||
};
|
||||
|
||||
#define PATCH_SIZE 20
|
||||
|
||||
struct patch {
|
||||
/* 00 */ ID id;
|
||||
/* 04 */ __u16 nlayers;
|
||||
/* 06 */ __u8 layer_mode;
|
||||
/* 07 */ __u8 exclusion_mode;
|
||||
/* 08 */ __u16 exclusion_group;
|
||||
/* 10 */ __u8 effect1;
|
||||
/* 11 */ __u8 effect1_depth;
|
||||
/* 12 */ __u8 effect2;
|
||||
/* 13 */ __u8 effect2_depth;
|
||||
/* 14 */ __u8 bank;
|
||||
/* 15 */ __u8 program;
|
||||
/* 16 */ char *__layer; /* don't use */
|
||||
};
|
||||
|
||||
#define LFO_SIZE 8
|
||||
|
||||
struct LFO {
|
||||
/* 00 */ __u16 freq;
|
||||
/* 02 */ __s16 depth;
|
||||
/* 04 */ __s16 sweep;
|
||||
/* 06 */ __u8 shape;
|
||||
/* 07 */ __u8 delay;
|
||||
};
|
||||
|
||||
#define LAYER_SIZE 42
|
||||
|
||||
struct layer {
|
||||
/* 00 */ ID id;
|
||||
/* 04 */ __u8 nwaves;
|
||||
/* 05 */ __u8 flags;
|
||||
/* 06 */ __u8 high_range;
|
||||
/* 07 */ __u8 low_range;
|
||||
/* 08 */ __u8 pan;
|
||||
/* 09 */ __u8 pan_freq_scale;
|
||||
/* 10 */ struct LFO tremolo;
|
||||
/* 18 */ struct LFO vibrato;
|
||||
/* 26 */ __u8 velocity_mode;
|
||||
/* 27 */ __u8 attenuation;
|
||||
/* 28 */ __u16 freq_scale;
|
||||
/* 30 */ __u8 freq_center;
|
||||
/* 31 */ __u8 layer_event;
|
||||
/* 32 */ ID penv;
|
||||
/* 34 */ ID venv;
|
||||
/* 38 */ char *wave;
|
||||
};
|
||||
|
||||
#define WAVE_SIZE 37
|
||||
|
||||
struct wave {
|
||||
/* 00 */ ID id;
|
||||
/* 04 */ __u32 size;
|
||||
/* 08 */ __u32 start;
|
||||
/* 12 */ __u32 loopstart;
|
||||
/* 16 */ __u32 loopend;
|
||||
/* 20 */ __u32 m_start;
|
||||
/* 24 */ __u32 sample_ratio;
|
||||
/* 28 */ __u8 attenuation;
|
||||
/* 29 */ __u8 low_note;
|
||||
/* 30 */ __u8 high_note;
|
||||
/* 31 */ __u8 format;
|
||||
/* 32 */ __u8 m_format;
|
||||
/* 33 */ ID data_id;
|
||||
};
|
||||
|
||||
#define ENVELOPE_SIZE 8
|
||||
|
||||
struct envelope {
|
||||
/* 00 */ ID id;
|
||||
/* 04 */ __u8 num_envelopes;
|
||||
/* 05 */ __u8 flags;
|
||||
/* 06 */ __u8 mode;
|
||||
/* 07 */ __u8 index_type;
|
||||
};
|
||||
|
||||
#define ENVELOPE_RECORD_SIZE 12
|
||||
|
||||
struct envelope_record {
|
||||
/* 00 */ __u16 nattack;
|
||||
/* 02 */ __u16 nrelease;
|
||||
/* 04 */ __u16 sustain_offset;
|
||||
/* 06 */ __u16 sustain_rate;
|
||||
/* 08 */ __u16 release_rate;
|
||||
/* 10 */ __u8 hirange;
|
||||
/* 11 */ __u8 pad;
|
||||
};
|
||||
|
||||
/*
|
||||
* variables
|
||||
*/
|
||||
|
||||
#define IW_ID_VALUE(a, b, c, d) (a|(b<<8)|(c<<16)|(d<<24))
|
||||
|
||||
#define file_header IW_ID_VALUE('F', 'F', 'F', 'F')
|
||||
#define patch_header IW_ID_VALUE('P', 'T', 'C', 'H')
|
||||
#define program_header IW_ID_VALUE('P', 'R', 'O', 'G')
|
||||
#define layer_header IW_ID_VALUE('L', 'A', 'Y', 'R')
|
||||
#define wave_header IW_ID_VALUE('W', 'A', 'V', 'E')
|
||||
#define envp_header IW_ID_VALUE('E', 'N', 'V', 'P')
|
||||
#if 0
|
||||
#define text_header IW_ID_VALUE('T', 'E', 'X', 'T')
|
||||
#define data_header IW_ID_VALUE('D', 'A', 'T', 'A')
|
||||
#define copyright_header IW_ID_VALUE('C', 'P', 'R', 'T')
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int rom;
|
||||
unsigned char *fff_data;
|
||||
unsigned int fff_size;
|
||||
char *fff_filename;
|
||||
char *dat_filename;
|
||||
unsigned int start_addr;
|
||||
unsigned int share_id1;
|
||||
unsigned int share_id2;
|
||||
unsigned int share_id3;
|
||||
} iwffff_t;
|
||||
|
||||
/*
|
||||
* local functions
|
||||
*/
|
||||
|
||||
static int iwffff_get_rom_header(int card, int bank, iwffff_rom_header_t *header)
|
||||
{
|
||||
int fd;
|
||||
char filename[128];
|
||||
|
||||
sprintf(filename, IW_ROM_FILE, card, bank);
|
||||
if ((fd = open(filename, O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
if (read(fd, header, sizeof(*header)) != sizeof(*header)) {
|
||||
close(fd);
|
||||
return -EIO;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_open(void **handle, const char *name_fff, const char *name_dat)
|
||||
{
|
||||
iwffff_t *iwf;
|
||||
struct stat info;
|
||||
struct header ffff;
|
||||
int fd;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
*handle = NULL;
|
||||
if (stat(name_fff, &info) < 0)
|
||||
return -ENOENT;
|
||||
if (stat(name_dat, &info) < 0)
|
||||
return -ENOENT;
|
||||
/* ok.. at first - look for FFFF ROM */
|
||||
if ((fd = open(name_fff, O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
if (read(fd, &ffff, sizeof(ffff)) != sizeof(ffff)) {
|
||||
close(fd);
|
||||
return -EIO;
|
||||
}
|
||||
if ((iwf = malloc(sizeof(*iwf))) == NULL) {
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(iwf, 0, sizeof(*iwf));
|
||||
iwf->fff_size = snd_LE_to_host_32(ffff.length);
|
||||
iwf->fff_filename = strdup(name_fff);
|
||||
iwf->dat_filename = strdup(name_dat);
|
||||
iwf->fff_data = malloc(iwf->fff_size);
|
||||
if (iwf->fff_data == NULL) {
|
||||
free(iwf);
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (read(fd, iwf->fff_data, iwf->fff_size) != iwf->fff_size) {
|
||||
free(iwf->fff_data);
|
||||
free(iwf);
|
||||
close(fd);
|
||||
return -EIO;
|
||||
}
|
||||
iwf->share_id1 = IWFFFF_SHARE_FILE;
|
||||
#ifdef __alpha__
|
||||
iwf->share_id2 = (info.st_dev << 16) | ((info.st_ino >> 32) & 0xffff);
|
||||
#else
|
||||
iwf->share_id2 = info.st_dev << 16;
|
||||
#endif
|
||||
iwf->share_id3 = info.st_ino; /* can be 64-bit -> overflow */
|
||||
*handle = iwf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_open_rom(void **handle, int card, int bank, int file)
|
||||
{
|
||||
unsigned int next_ffff;
|
||||
struct header ffff;
|
||||
iwffff_t *iwf;
|
||||
iwffff_rom_header_t header;
|
||||
int fd, index;
|
||||
|
||||
if (handle == NULL)
|
||||
return -EINVAL;
|
||||
*handle = NULL;
|
||||
index = 0;
|
||||
if (bank > 4 || file > 255)
|
||||
return -1;
|
||||
fd = iwffff_get_rom_header(card, bank, &header);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
while (read(fd, (char *)&ffff, sizeof(ffff)) == sizeof(ffff)) {
|
||||
if (ffff.id != file_header)
|
||||
break;
|
||||
ffff.length = snd_LE_to_host_32(ffff.length);
|
||||
next_ffff = lseek(fd, 0, SEEK_CUR) + ffff.length;
|
||||
if (file == index) {
|
||||
#ifdef IW_ROM_DEBUG
|
||||
fprintf(stderr, "file header at 0x%x size 0x%x\n", rom_pos - sizeof(ffff), ffff.length);
|
||||
#endif
|
||||
iwf = malloc(sizeof(*iwf));
|
||||
if (iwf == NULL) {
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(iwf, 0, sizeof(*iwf));
|
||||
iwf->fff_data = malloc(iwf->fff_size = ffff.length);
|
||||
if (iwf->fff_data == NULL) {
|
||||
free(iwf);
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (read(fd, iwf->fff_data, ffff.length) != ffff.length) {
|
||||
free(iwf->fff_data);
|
||||
free(iwf);
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
close(fd);
|
||||
iwf->start_addr = bank*4L*1024L*1024L;
|
||||
iwf->rom = 1;
|
||||
*handle = iwf;
|
||||
return 0;
|
||||
}
|
||||
index++;
|
||||
lseek(fd, SEEK_CUR, next_ffff);
|
||||
}
|
||||
close(fd);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_close(void *handle)
|
||||
{
|
||||
iwffff_t *iwf;
|
||||
|
||||
if (handle == NULL)
|
||||
return -ENOENT;
|
||||
iwf = (iwffff_t *)handle;
|
||||
if (iwf->dat_filename)
|
||||
free(iwf->dat_filename);
|
||||
if (iwf->fff_filename)
|
||||
free(iwf->fff_filename);
|
||||
if (iwf->fff_data)
|
||||
free(iwf->fff_data);
|
||||
free(iwf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_wave(iwffff_wave_t *wave)
|
||||
{
|
||||
if (wave == NULL)
|
||||
return;
|
||||
if (wave->address.ptr != NULL)
|
||||
free(wave->address.ptr);
|
||||
free(wave);
|
||||
}
|
||||
|
||||
static void free_envelope(iwffff_env_t *envp)
|
||||
{
|
||||
iwffff_env_record_t *rec, *nrec;
|
||||
|
||||
if (envp == NULL)
|
||||
return;
|
||||
rec = envp->record;
|
||||
while (rec != NULL) {
|
||||
nrec = rec->next;
|
||||
free(rec);
|
||||
rec = nrec;
|
||||
}
|
||||
free(envp);
|
||||
}
|
||||
|
||||
static void free_layer(iwffff_layer_t *layer)
|
||||
{
|
||||
iwffff_wave_t *wave, *nwave;
|
||||
|
||||
if (layer == NULL)
|
||||
return;
|
||||
|
||||
free_envelope(&layer->penv);
|
||||
free_envelope(&layer->venv);
|
||||
|
||||
wave = layer->wave;
|
||||
while (wave != NULL) {
|
||||
nwave = wave->next;
|
||||
free_wave(wave);
|
||||
wave = nwave;
|
||||
}
|
||||
|
||||
free(layer);
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_free(snd_instr_iwffff_t *__instr)
|
||||
{
|
||||
iwffff_instrument_t *instr = (iwffff_instrument_t *)__instr;
|
||||
iwffff_layer_t *layer, *nlayer;
|
||||
|
||||
if (instr == NULL)
|
||||
return -EINVAL;
|
||||
layer = instr->layer;
|
||||
while (layer != NULL) {
|
||||
nlayer = layer->next;
|
||||
free_layer(layer);
|
||||
layer = nlayer;
|
||||
}
|
||||
free(instr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *look_for_id(iwffff_t *iwf, unsigned char *start,
|
||||
unsigned char *end, ID id)
|
||||
{
|
||||
if (!start)
|
||||
return NULL;
|
||||
while ((long)start < (long)end) {
|
||||
if (((struct header *)start)->id == id)
|
||||
return start;
|
||||
start += sizeof(struct header) + snd_LE_to_host_32(((struct header *)start)->length);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void copy_modulation(iwffff_lfo_t *glfo, unsigned char *buffer)
|
||||
{
|
||||
glfo->freq = snd_LE_to_host_16(*(((unsigned short *)buffer) + 0/2));
|
||||
glfo->depth = snd_LE_to_host_16(*(((unsigned short *)buffer) + 2/1));
|
||||
glfo->sweep = snd_LE_to_host_16(*(((unsigned short *)buffer) + 4/2));
|
||||
glfo->shape = buffer[6];
|
||||
glfo->delay = buffer[7];
|
||||
}
|
||||
|
||||
static int copy_envelope(iwffff_t *iwf, iwffff_env_t *genv, ID eid)
|
||||
{
|
||||
int idx, idx1;
|
||||
unsigned char *ptr, *end;
|
||||
unsigned char *envelope, *record;
|
||||
iwffff_env_record_t *grecord, *precord;
|
||||
unsigned short nattack, nrelease, *points;
|
||||
iwffff_env_point_t *rpoints;
|
||||
|
||||
if (eid == 0)
|
||||
return -EINVAL;
|
||||
ptr = iwf->fff_data;
|
||||
end = iwf->fff_data + iwf->fff_size;
|
||||
while (1) {
|
||||
ptr = look_for_id(iwf, ptr, end, envp_header);
|
||||
if (ptr == NULL)
|
||||
return -ENOENT;
|
||||
envelope = ptr + sizeof(struct header);
|
||||
if (*((ID *)envelope) == eid) {
|
||||
genv->flags = envelope[5];
|
||||
genv->mode = envelope[6];
|
||||
genv->index = envelope[7];
|
||||
genv->record = precord = NULL;
|
||||
record = envelope + ENVELOPE_SIZE;
|
||||
for (idx = 0; idx < envelope[4]; idx++) {
|
||||
nattack = snd_LE_to_host_16(*(((unsigned short *)record) + 0/2));
|
||||
nrelease = snd_LE_to_host_16(*(((unsigned short*)record) + 2/2));
|
||||
grecord = calloc(1, sizeof(*grecord) + (nattack + nrelease) * sizeof(iwffff_env_point_t));
|
||||
if (grecord == NULL)
|
||||
return -ENOMEM;
|
||||
grecord->nattack = nattack;
|
||||
grecord->nrelease = nrelease;
|
||||
grecord->sustain_offset = snd_LE_to_host_16(*(((unsigned short*)record) + 4/2));
|
||||
grecord->sustain_rate = snd_LE_to_host_16(*(((unsigned short *)record) + 6/2));
|
||||
grecord->release_rate = snd_LE_to_host_16(*(((unsigned short *)record) + 8/2));
|
||||
grecord->hirange = record[10];
|
||||
points = (short *)(record + ENVELOPE_RECORD_SIZE);
|
||||
rpoints = (iwffff_env_point_t *)(grecord + 1);
|
||||
for (idx1 = 0; idx1 < grecord->nattack + grecord->nrelease; idx1++) {
|
||||
rpoints[idx1].offset = *points++;
|
||||
rpoints[idx1].rate = *points++;
|
||||
}
|
||||
grecord->next = NULL;
|
||||
if (genv->record == NULL) {
|
||||
genv->record = grecord;
|
||||
} else {
|
||||
precord->next = grecord;
|
||||
}
|
||||
precord = grecord;
|
||||
record += ENVELOPE_RECORD_SIZE + 2 * sizeof(short) * (grecord->nattack + grecord->nrelease);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ptr += sizeof(struct header) + snd_LE_to_host_32(((struct header *)ptr)->length);
|
||||
}
|
||||
}
|
||||
|
||||
static int load_iw_wave(iwffff_t *file,
|
||||
unsigned int start,
|
||||
unsigned int size,
|
||||
unsigned char **result)
|
||||
{
|
||||
int fd, res;
|
||||
|
||||
*result = NULL;
|
||||
if ((fd = open(file->dat_filename, O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
if (lseek(fd, start, SEEK_SET) < 0) {
|
||||
res = -errno;
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
*result = malloc(size);
|
||||
if (*result == NULL) {
|
||||
close(fd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (read(fd, result, size) != size) {
|
||||
free(*result);
|
||||
*result = NULL;
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_iw_patch(iwffff_t *iwf, iwffff_instrument_t *instr,
|
||||
unsigned char *patch)
|
||||
{
|
||||
unsigned char *layer, *wave;
|
||||
iwffff_layer_t *glayer, *player;
|
||||
iwffff_wave_t *gwave, *pwave;
|
||||
int idx_layer, idx_wave, result;
|
||||
unsigned char *current;
|
||||
|
||||
#ifdef IW_ROM_DEBUG
|
||||
fprintf(stderr, "load_iw_patch - nlayers = %i\n", snd_LE_to_host_16(*(((unsigned short *)patch) + 8/2));
|
||||
#endif
|
||||
instr->layer_type = patch[6];
|
||||
instr->exclusion = patch[7];
|
||||
instr->exclusion_group = snd_LE_to_host_16(*(((unsigned short *)patch) + 8/2));
|
||||
instr->effect1 = patch[10];
|
||||
instr->effect1_depth = patch[11];
|
||||
instr->effect2 = patch[12];
|
||||
instr->effect2_depth = patch[13];
|
||||
current = (char *)patch + sizeof(struct patch);
|
||||
instr->layer = player = NULL;
|
||||
for (idx_layer = 0; idx_layer < snd_LE_to_host_16(*(((unsigned short *)patch) + 4/2)); idx_layer++) {
|
||||
if (((struct header *)current)->id != layer_header) {
|
||||
return -EIO;
|
||||
}
|
||||
layer = current + sizeof(struct header);
|
||||
glayer = calloc(1, sizeof(*glayer));
|
||||
glayer->flags = layer[5];
|
||||
glayer->high_range = layer[6];
|
||||
glayer->low_range = layer[7];
|
||||
glayer->pan = layer[8];
|
||||
glayer->pan_freq_scale = layer[9];
|
||||
copy_modulation(&glayer->tremolo, layer + 10);
|
||||
copy_modulation(&glayer->vibrato, layer + 18);
|
||||
glayer->velocity_mode = layer[26];
|
||||
glayer->attenuation = layer[27];
|
||||
glayer->freq_scale = snd_LE_to_host_16(*(((unsigned short *)layer) + 28/2));
|
||||
glayer->freq_center = layer[30];
|
||||
glayer->layer_event = layer[31];
|
||||
if (copy_envelope(iwf, &glayer->penv, *((ID *)(layer + 32))) < 0) {
|
||||
free_layer(glayer);
|
||||
return -EIO;
|
||||
}
|
||||
if (copy_envelope(iwf, &glayer->venv, *((ID *)(layer + 36))) < 0) {
|
||||
free_layer(glayer);
|
||||
return -EIO;
|
||||
}
|
||||
current += sizeof(struct header) + snd_LE_to_host_32(((struct header *)current)->length);
|
||||
glayer->wave = pwave = NULL;
|
||||
for (idx_wave = 0; idx_wave < layer[4]; idx_wave++) {
|
||||
unsigned char format;
|
||||
int w_16;
|
||||
|
||||
if (((struct header *)current)->id != wave_header) {
|
||||
free_layer(glayer);
|
||||
return -EIO;
|
||||
}
|
||||
wave = current + sizeof(struct header);
|
||||
format = wave[31];
|
||||
w_16 = format & IW_FORMAT_8BIT ? 1 : 2;
|
||||
gwave = calloc(1, sizeof(*gwave));
|
||||
gwave->size = snd_LE_to_host_32(*(((unsigned int *)wave) + 4/4)) * w_16;
|
||||
gwave->start = iwf->start_addr;
|
||||
gwave->loop_start = snd_LE_to_host_32(*(((unsigned int *)wave) + 12/4)) * w_16;
|
||||
gwave->loop_end = snd_LE_to_host_32(*(((unsigned int *)wave) + 16/4)) * w_16;
|
||||
gwave->sample_ratio = snd_LE_to_host_32(*(((unsigned int *)wave) + 24/4));
|
||||
gwave->attenuation = wave[28];
|
||||
gwave->low_note = wave[29];
|
||||
gwave->high_note = wave[30];
|
||||
if (!(format & IW_FORMAT_8BIT))
|
||||
gwave->format |= IWFFFF_WAVE_16BIT;
|
||||
if (!(format & IW_FORMAT_SIGNED))
|
||||
gwave->format |= IWFFFF_WAVE_UNSIGNED;
|
||||
if (!(format & IW_FORMAT_FORWARD))
|
||||
gwave->format |= IWFFFF_WAVE_BACKWARD;
|
||||
if (format & IW_FORMAT_LOOP)
|
||||
gwave->format |= IWFFFF_WAVE_LOOP;
|
||||
if (format & IW_FORMAT_BIDIR)
|
||||
gwave->format |= IWFFFF_WAVE_BIDIR;
|
||||
if (format & IW_FORMAT_ULAW)
|
||||
gwave->format |= IWFFFF_WAVE_ULAW;
|
||||
if (format & IW_FORMAT_ROM) {
|
||||
gwave->format |= IWFFFF_WAVE_ROM;
|
||||
gwave->address.memory = snd_LE_to_host_32(*(((unsigned int *)wave) + 8/4));
|
||||
} else {
|
||||
gwave->share_id1 = iwf->share_id1;
|
||||
gwave->share_id2 = iwf->share_id2;
|
||||
gwave->share_id3 = iwf->share_id3;
|
||||
gwave->share_id4 = snd_LE_to_host_32(*(((unsigned int *)wave) + 8/4));
|
||||
result = load_iw_wave(iwf, gwave->share_id2, gwave->size, &gwave->address.ptr);
|
||||
if (result < 0) {
|
||||
free_wave(gwave);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (glayer->wave == NULL) {
|
||||
glayer->wave = gwave;
|
||||
} else {
|
||||
pwave->next = gwave;
|
||||
}
|
||||
pwave = gwave;
|
||||
current += sizeof(struct header) + snd_LE_to_host_32(((struct header *)current)->length);
|
||||
}
|
||||
if (instr->layer == NULL) {
|
||||
instr->layer = glayer;
|
||||
} else {
|
||||
player->next = glayer;
|
||||
}
|
||||
player = glayer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_load(void *handle, int bank, int prg, snd_instr_iwffff_t **__iwffff)
|
||||
{
|
||||
iwffff_t *iwf;
|
||||
unsigned char *ptr, *end;
|
||||
unsigned char *program, *patch;
|
||||
struct header *header;
|
||||
iwffff_instrument_t *iwffff;
|
||||
int result;
|
||||
|
||||
if (handle == NULL || __iwffff == NULL)
|
||||
return -EINVAL;
|
||||
__iwffff = NULL;
|
||||
if (bank < 0 || bank > 255 || prg < 0 || prg > 255)
|
||||
return -EINVAL;
|
||||
iwffff = (iwffff_instrument_t *)__iwffff;
|
||||
iwf = (iwffff_t *)handle;
|
||||
ptr = iwf->fff_data;
|
||||
end = iwf->fff_data + iwf->fff_size;
|
||||
while (1) {
|
||||
ptr = look_for_id(iwf, ptr, end, program_header);
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
program = ptr + sizeof(struct header);
|
||||
if (snd_LE_to_host_16(*(((unsigned short *)program) + 4/2)) != IW_ROM_PROGRAM_VERSION_MAJOR ||
|
||||
snd_LE_to_host_16(*(((unsigned short *)program) + 6/2)) != IW_ROM_PROGRAM_VERSION_MINOR)
|
||||
return -EINVAL;
|
||||
header = (struct header *)(ptr + sizeof(struct header) + sizeof(struct program));
|
||||
if (header->id == patch_header) {
|
||||
patch = ptr + sizeof(struct header) + sizeof(struct program) + sizeof(struct header);
|
||||
if (patch[14] == bank && patch[15] == prg) {
|
||||
iwffff = (iwffff_instrument_t *)malloc(sizeof(*iwffff));
|
||||
if (iwffff == NULL)
|
||||
return -ENOMEM;
|
||||
result = load_iw_patch(iwf, iwffff, patch);
|
||||
if (result < 0) {
|
||||
snd_instr_iwffff_free(iwffff);
|
||||
} else {
|
||||
*__iwffff = iwffff;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
ptr += sizeof(struct header) + snd_LE_to_host_32(((struct header *)ptr)->length);
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int iwffff_evp_record_size(iwffff_env_t *env)
|
||||
{
|
||||
iwffff_env_record_t *rec;
|
||||
int size;
|
||||
|
||||
if (env == NULL)
|
||||
return 0;
|
||||
size = 0;
|
||||
for (rec = env->record; rec; rec = rec->next) {
|
||||
size += sizeof(iwffff_xenv_record_t);
|
||||
size += sizeof(iwffff_xenv_point_t) *
|
||||
(rec->nattack + rec->nrelease);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int iwffff_size(iwffff_instrument_t *instr)
|
||||
{
|
||||
int size;
|
||||
iwffff_layer_t *layer;
|
||||
iwffff_wave_t *wave;
|
||||
|
||||
if (instr == NULL)
|
||||
return 0;
|
||||
size = sizeof(iwffff_xinstrument_t);
|
||||
for (layer = instr->layer; layer; layer = layer->next) {
|
||||
size += sizeof(iwffff_xlayer_t);
|
||||
size += iwffff_evp_record_size(&layer->penv);
|
||||
size += iwffff_evp_record_size(&layer->venv);
|
||||
for (wave = layer->wave; wave; wave = wave->next) {
|
||||
size += sizeof(iwffff_xwave_t);
|
||||
if (!(wave->format & IWFFFF_WAVE_ROM))
|
||||
size += wave->size;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static void copy_lfo_to_stream(iwffff_xlfo_t *xlfo, iwffff_lfo_t *lfo)
|
||||
{
|
||||
xlfo->freq = snd_htoi_16(lfo->freq);
|
||||
xlfo->depth = snd_htoi_16(lfo->depth);
|
||||
xlfo->sweep = snd_htoi_16(lfo->sweep);
|
||||
xlfo->shape = lfo->shape;
|
||||
xlfo->delay = lfo->delay;
|
||||
|
||||
}
|
||||
|
||||
static int copy_env_to_stream(iwffff_xenv_t *xenv, iwffff_env_t *env, __u32 stype)
|
||||
{
|
||||
int size, idx;
|
||||
char *ptr;
|
||||
iwffff_xenv_record_t *xrec;
|
||||
iwffff_env_record_t *rec;
|
||||
iwffff_xenv_point_t *xpoint;
|
||||
iwffff_env_point_t *point;
|
||||
|
||||
xenv->flags = env->flags;
|
||||
xenv->mode = env->mode;
|
||||
xenv->index = env->index;
|
||||
size = 0;
|
||||
ptr = (char *)(xenv + 1);
|
||||
for (rec = env->record; rec; rec = rec->next) {
|
||||
xrec = (iwffff_xenv_record_t *)ptr;
|
||||
ptr += sizeof(*xrec);
|
||||
size += sizeof(*xrec);
|
||||
xrec->stype = stype;
|
||||
xrec->nattack = snd_htoi_16(rec->nattack);
|
||||
xrec->nrelease = snd_htoi_16(rec->nrelease);
|
||||
xrec->sustain_offset = snd_htoi_16(rec->sustain_offset);
|
||||
xrec->sustain_rate = snd_htoi_16(rec->sustain_rate);
|
||||
xrec->release_rate = snd_htoi_16(rec->release_rate);
|
||||
xrec->hirange = rec->hirange;
|
||||
point = (iwffff_env_point_t *)(rec + 1);
|
||||
for (idx = 0; idx < xrec->nattack + xrec->nrelease; idx++) {
|
||||
xpoint = (iwffff_xenv_point_t *)ptr;
|
||||
ptr += sizeof(*xpoint);
|
||||
size += sizeof(*xpoint);
|
||||
xpoint->offset = snd_htoi_16(point->offset);
|
||||
xpoint->rate = snd_htoi_16(point->rate);
|
||||
point++;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_conv_to_stream(snd_instr_iwffff_t *iwffff,
|
||||
const char *name,
|
||||
snd_seq_instr_data_t **__data,
|
||||
int *__size)
|
||||
{
|
||||
snd_seq_instr_data_t *data;
|
||||
int size;
|
||||
char *ptr;
|
||||
iwffff_instrument_t *instr;
|
||||
iwffff_xinstrument_t *xinstr;
|
||||
iwffff_layer_t *layer;
|
||||
iwffff_xlayer_t *xlayer;
|
||||
iwffff_wave_t *wave;
|
||||
iwffff_xwave_t *xwave;
|
||||
|
||||
if (iwffff == NULL || __data == NULL)
|
||||
return -EINVAL;
|
||||
instr = (iwffff_instrument_t *)iwffff;
|
||||
*__data = NULL;
|
||||
*__size = 0;
|
||||
size = sizeof(*data) + iwffff_size(iwffff);
|
||||
data = (snd_seq_instr_data_t *)malloc(sizeof(*data) + size);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
/* build header */
|
||||
bzero(data, sizeof(*data));
|
||||
if (name)
|
||||
strncpy(data->name, name, sizeof(data->name)-1);
|
||||
data->type = SND_SEQ_INSTR_ATYPE_DATA;
|
||||
strcpy(data->data.format, SND_SEQ_INSTR_ID_INTERWAVE);
|
||||
/* build data section */
|
||||
xinstr = (iwffff_xinstrument_t *)(data + 1);
|
||||
xinstr->stype = IWFFFF_STRU_INSTR;
|
||||
xinstr->exclusion = snd_htoi_16(instr->exclusion);
|
||||
xinstr->layer_type = snd_htoi_16(instr->layer_type);
|
||||
xinstr->exclusion_group = snd_htoi_16(instr->exclusion_group);
|
||||
xinstr->effect1 = instr->effect1;
|
||||
xinstr->effect1_depth = instr->effect1_depth;
|
||||
xinstr->effect2 = instr->effect2;
|
||||
xinstr->effect2_depth = instr->effect2_depth;
|
||||
ptr = (char *)(xinstr + 1);
|
||||
for (layer = instr->layer; layer; layer = layer->next) {
|
||||
xlayer = (iwffff_xlayer_t *)ptr;
|
||||
ptr += sizeof(*xlayer);
|
||||
xlayer->stype = IWFFFF_STRU_LAYER;
|
||||
xlayer->flags = layer->flags;
|
||||
xlayer->velocity_mode = layer->velocity_mode;
|
||||
xlayer->layer_event = layer->layer_event;
|
||||
xlayer->low_range = layer->low_range;
|
||||
xlayer->high_range = layer->high_range;
|
||||
xlayer->pan = layer->pan;
|
||||
xlayer->pan_freq_scale = layer->pan_freq_scale;
|
||||
xlayer->attenuation = layer->attenuation;
|
||||
copy_lfo_to_stream(&xlayer->tremolo, &layer->tremolo);
|
||||
copy_lfo_to_stream(&xlayer->vibrato, &layer->vibrato);
|
||||
xlayer->freq_scale = snd_htoi_16(layer->freq_scale);
|
||||
xlayer->freq_center = layer->freq_center;
|
||||
ptr += copy_env_to_stream(&xlayer->penv, &layer->penv, IWFFFF_STRU_ENV_RECP);
|
||||
ptr += copy_env_to_stream(&xlayer->venv, &layer->venv, IWFFFF_STRU_ENV_RECV);
|
||||
for (wave = layer->wave; wave; wave = wave->next) {
|
||||
xwave = (iwffff_xwave_t *)ptr;
|
||||
ptr += sizeof(*xwave);
|
||||
xwave->stype = IWFFFF_STRU_WAVE;
|
||||
xwave->share_id1 = snd_htoi_32(wave->share_id1);
|
||||
xwave->share_id2 = snd_htoi_32(wave->share_id2);
|
||||
xwave->share_id3 = snd_htoi_32(wave->share_id3);
|
||||
xwave->share_id4 = snd_htoi_32(wave->share_id4);
|
||||
xwave->format = snd_htoi_32(wave->format);
|
||||
xwave->size = snd_htoi_32(wave->size);
|
||||
xwave->start = snd_htoi_32(wave->start);
|
||||
xwave->loop_start = snd_htoi_32(wave->loop_start);
|
||||
xwave->loop_end = snd_htoi_32(wave->loop_end);
|
||||
xwave->loop_repeat = snd_htoi_32(wave->loop_repeat);
|
||||
xwave->sample_ratio = snd_htoi_32(wave->sample_ratio);
|
||||
xwave->attenuation = wave->attenuation;
|
||||
xwave->low_note = wave->low_note;
|
||||
xwave->high_note = wave->high_note;
|
||||
if (!(xwave->format & IWFFFF_WAVE_ROM)) {
|
||||
memcpy(ptr, wave->address.ptr, xwave->size);
|
||||
ptr += xwave->size;
|
||||
} else {
|
||||
xwave->offset = snd_htoi_32(wave->address.memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* write result */
|
||||
*__data = data;
|
||||
*__size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snd_instr_iwffff_convert_from_stream(snd_seq_instr_data_t *data,
|
||||
int size,
|
||||
snd_instr_iwffff_t **iwffff)
|
||||
{
|
||||
/* TODO */
|
||||
return -ENXIO;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue