mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-29 23:33:00 +00:00
900 lines
30 KiB
C++
900 lines
30 KiB
C++
/*
|
|
gus_pat.c
|
|
|
|
Midi Wavetable Processing library
|
|
|
|
Copyright (C) Chris Ison 2001-2011
|
|
Copyright (C) Bret Curtis 2013-2014
|
|
|
|
This file is part of WildMIDI.
|
|
|
|
WildMIDI is free software: you can redistribute and/or modify the player
|
|
under the terms of the GNU General Public License and you can redistribute
|
|
and/or modify the library under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation, either version 3 of
|
|
the licenses, or(at your option) any later version.
|
|
|
|
WildMIDI 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 General Public License and
|
|
the GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License and the
|
|
GNU Lesser General Public License along with WildMIDI. If not, see
|
|
<http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//#include "config.h"
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "gus_pat.h"
|
|
#include "common.h"
|
|
#include "wm_error.h"
|
|
#include "file_io.h"
|
|
|
|
#ifdef DEBUG_GUSPAT
|
|
#define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx)
|
|
|
|
#define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy)
|
|
#define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy)
|
|
#define GUSPAT_START_DEBUG() fprintf(stderr,"\r")
|
|
#define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz)
|
|
#define GUSPAT_END_DEBUG() fprintf(stderr,"\n")
|
|
#else
|
|
#define GUSPAT_FILENAME_DEBUG(dx)
|
|
#define GUSPAT_INT_DEBUG(dx,dy)
|
|
#define GUSPAT_FLOAT_DEBUG(dx,dy)
|
|
#define GUSPAT_START_DEBUG()
|
|
#define GUSPAT_MODE_DEBUG(dx,dy,dz)
|
|
#define GUSPAT_END_DEBUG()
|
|
#endif
|
|
|
|
/*
|
|
* sample data conversion functions
|
|
* convert data to signed shorts
|
|
*/
|
|
|
|
/* 8bit signed */
|
|
static int convert_8s(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data++ = (*read_data++) << 8;
|
|
} while (read_data != read_end);
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR_NEW("(%s:%i) ERROR: calloc failed (%s)", __FUNCTION__, __LINE__,
|
|
strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit signed ping pong */
|
|
static int convert_8sp(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->loop_start;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data++ = (*read_data++) << 8;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = (*read_data++ << 8);
|
|
write_data_a = write_data + dloop_length;
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + dloop_length;
|
|
read_end = data + gus_sample->loop_end;
|
|
do {
|
|
*write_data = (*read_data++) << 8;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = (*read_data++ << 8);
|
|
*write_data_b++ = *write_data;
|
|
read_end = data + gus_sample->data_length;
|
|
if (read_data != read_end) {
|
|
do {
|
|
*write_data_b++ = (*read_data++) << 8;
|
|
} while (read_data != read_end);
|
|
}
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit signed reverse */
|
|
static int convert_8sr(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
unsigned long int tmp_loop = 0;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data + gus_sample->data_length - 1;
|
|
do {
|
|
*write_data-- = (*read_data++) << 8;
|
|
} while (read_data != read_end);
|
|
tmp_loop = gus_sample->loop_end;
|
|
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
|
|
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
|
|
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
|
|
| ((gus_sample->loop_fraction & 0xf0) >> 4);
|
|
gus_sample->modes ^= SAMPLE_REVERSE;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit signed reverse ping pong */
|
|
static int convert_8srp(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data + gus_sample->data_length - 1;
|
|
unsigned char *read_end = data + gus_sample->loop_end;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data++ = (*read_data--) << 8;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = (*read_data-- << 8);
|
|
write_data_a = write_data + dloop_length;
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + dloop_length;
|
|
read_end = data + gus_sample->loop_start;
|
|
do {
|
|
*write_data = (*read_data--) << 8;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = (*read_data-- << 8);
|
|
*write_data_b++ = *write_data;
|
|
read_end = data - 1;
|
|
do {
|
|
*write_data_b++ = (*read_data--) << 8;
|
|
write_data_b++;
|
|
} while (read_data != read_end);
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit unsigned */
|
|
static int convert_8u(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data++ = ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data != read_end);
|
|
gus_sample->modes ^= SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit unsigned ping pong */
|
|
static int convert_8up(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->loop_start;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data++ = ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = ((*read_data++) ^ 0x80) << 8;
|
|
write_data_a = write_data + dloop_length;
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + dloop_length;
|
|
read_end = data + gus_sample->loop_end;
|
|
do {
|
|
*write_data = ((*read_data++) ^ 0x80) << 8;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = ((*read_data++) ^ 0x80) << 8;
|
|
*write_data_b++ = *write_data;
|
|
read_end = data + gus_sample->data_length;
|
|
if (read_data != read_end) {
|
|
do {
|
|
*write_data_b++ = ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data != read_end);
|
|
}
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit unsigned reverse */
|
|
static int convert_8ur(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
unsigned long int tmp_loop = 0;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data + gus_sample->data_length - 1;
|
|
do {
|
|
*write_data-- = ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data != read_end);
|
|
tmp_loop = gus_sample->loop_end;
|
|
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
|
|
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
|
|
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
|
|
| ((gus_sample->loop_fraction & 0xf0) >> 4);
|
|
gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 8bit unsigned reverse ping pong */
|
|
static int convert_8urp(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data + gus_sample->data_length - 1;
|
|
unsigned char *read_end = data + gus_sample->loop_end;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data++ = ((*read_data--) ^ 0x80) << 8;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
write_data_a = write_data + dloop_length;
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + dloop_length;
|
|
read_end = data + gus_sample->loop_start;
|
|
do {
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data != read_end);
|
|
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data_b++ = *write_data;
|
|
read_end = data - 1;
|
|
do {
|
|
*write_data_b++ = ((*read_data--) ^ 0x80) << 8;
|
|
} while (read_data != read_end);
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit signed */
|
|
static int convert_16s(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data = *read_data++;
|
|
*write_data++ |= (*read_data++) << 8;
|
|
} while (read_data < read_end);
|
|
|
|
gus_sample->loop_start >>= 1;
|
|
gus_sample->loop_end >>= 1;
|
|
gus_sample->data_length >>= 1;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit signed ping pong */
|
|
static int convert_16sp(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->loop_start;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data = (*read_data++);
|
|
*write_data++ |= (*read_data++) << 8;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = (*read_data++);
|
|
*write_data |= (*read_data++) << 8;
|
|
write_data_a = write_data + (dloop_length >> 1);
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + (dloop_length >> 1);
|
|
read_end = data + gus_sample->loop_end;
|
|
do {
|
|
*write_data = (*read_data++);
|
|
*write_data |= (*read_data++) << 8;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = *(read_data++);
|
|
*write_data |= (*read_data++) << 8;
|
|
*write_data_b++ = *write_data;
|
|
read_end = data + gus_sample->data_length;
|
|
if (read_data != read_end) {
|
|
do {
|
|
*write_data_b = *(read_data++);
|
|
*write_data_b++ |= (*read_data++) << 8;
|
|
} while (read_data < read_end);
|
|
}
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG;
|
|
gus_sample->loop_start >>= 1;
|
|
gus_sample->loop_end >>= 1;
|
|
gus_sample->data_length >>= 1;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit signed reverse */
|
|
static int convert_16sr(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
unsigned long int tmp_loop = 0;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
|
|
do {
|
|
*write_data = *read_data++;
|
|
*write_data-- |= (*read_data++) << 8;
|
|
} while (read_data < read_end);
|
|
tmp_loop = gus_sample->loop_end;
|
|
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
|
|
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
|
|
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
|
|
| ((gus_sample->loop_fraction & 0xf0) >> 4);
|
|
gus_sample->loop_start >>= 1;
|
|
gus_sample->loop_end >>= 1;
|
|
gus_sample->data_length >>= 1;
|
|
gus_sample->modes ^= SAMPLE_REVERSE;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit signed reverse ping pong */
|
|
static int convert_16srp(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data + gus_sample->data_length - 1;
|
|
unsigned char *read_end = data + gus_sample->loop_end;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data = (*read_data--) << 8;
|
|
*write_data++ |= *read_data--;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = (*read_data-- << 8);
|
|
*write_data |= *read_data--;
|
|
write_data_a = write_data + (dloop_length >> 1);
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + (dloop_length >> 1);
|
|
read_end = data + gus_sample->loop_start;
|
|
do {
|
|
*write_data = (*read_data--) << 8;
|
|
*write_data |= *read_data--;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = ((*read_data--) << 8);
|
|
*write_data |= *read_data--;
|
|
*write_data_b++ = *write_data;
|
|
read_end = data - 1;
|
|
do {
|
|
*write_data_b = (*read_data--) << 8;
|
|
*write_data_b++ |= *read_data--;
|
|
} while (read_data < read_end);
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit unsigned */
|
|
static int convert_16u(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data = *read_data++;
|
|
*write_data++ |= ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data < read_end);
|
|
gus_sample->loop_start >>= 1;
|
|
gus_sample->loop_end >>= 1;
|
|
gus_sample->data_length >>= 1;
|
|
gus_sample->modes ^= SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit unsigned ping pong */
|
|
static int convert_16up(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->loop_start;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data = (*read_data++);
|
|
*write_data++ |= ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = (*read_data++);
|
|
*write_data |= ((*read_data++) ^ 0x80) << 8;
|
|
write_data_a = write_data + (dloop_length >> 1);
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + (dloop_length >> 1);
|
|
read_end = data + gus_sample->loop_end;
|
|
do {
|
|
*write_data = (*read_data++);
|
|
*write_data |= ((*read_data++) ^ 0x80) << 8;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = (*read_data++);
|
|
*write_data |= ((*read_data++) ^ 0x80) << 8;
|
|
*write_data_b++ = *write_data;
|
|
read_end = data + gus_sample->data_length;
|
|
if (read_data != read_end) {
|
|
do {
|
|
*write_data_b = (*read_data++);
|
|
*write_data_b++ |= ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data < read_end);
|
|
}
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG;
|
|
gus_sample->loop_start >>= 1;
|
|
gus_sample->loop_end >>= 1;
|
|
gus_sample->data_length >>= 1;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit unsigned reverse */
|
|
static int convert_16ur(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned char *read_data = data;
|
|
unsigned char *read_end = data + gus_sample->data_length;
|
|
signed short int *write_data = NULL;
|
|
unsigned long int tmp_loop = 0;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
|
|
do {
|
|
*write_data = *read_data++;
|
|
*write_data-- |= ((*read_data++) ^ 0x80) << 8;
|
|
} while (read_data < read_end);
|
|
tmp_loop = gus_sample->loop_end;
|
|
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
|
|
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
|
|
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
|
|
| ((gus_sample->loop_fraction & 0xf0) >> 4);
|
|
gus_sample->loop_start >>= 1;
|
|
gus_sample->loop_end >>= 1;
|
|
gus_sample->data_length >>= 1;
|
|
gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* 16bit unsigned reverse ping pong */
|
|
static int convert_16urp(unsigned char *data, struct _sample *gus_sample) {
|
|
unsigned long int loop_length = gus_sample->loop_end
|
|
- gus_sample->loop_start;
|
|
unsigned long int dloop_length = loop_length * 2;
|
|
unsigned long int new_length = gus_sample->data_length + dloop_length;
|
|
unsigned char *read_data = data + gus_sample->data_length - 1;
|
|
unsigned char *read_end = data + gus_sample->loop_end;
|
|
signed short int *write_data = NULL;
|
|
signed short int *write_data_a = NULL;
|
|
signed short int *write_data_b = NULL;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
|
|
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
|
|
sizeof(signed short int));
|
|
if (gus_sample->data != NULL) {
|
|
write_data = gus_sample->data;
|
|
do {
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data++ |= *read_data--;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data |= *read_data--;
|
|
write_data_a = write_data + (dloop_length >> 1);
|
|
*write_data_a-- = *write_data;
|
|
write_data++;
|
|
write_data_b = write_data + (dloop_length >> 1);
|
|
read_end = data + gus_sample->loop_start;
|
|
do {
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data |= *read_data--;
|
|
*write_data_a-- = *write_data;
|
|
*write_data_b++ = *write_data;
|
|
write_data++;
|
|
} while (read_data < read_end);
|
|
|
|
*write_data = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data |= *read_data--;
|
|
*write_data_b++ = *write_data;
|
|
read_end = data - 1;
|
|
do {
|
|
*write_data_b = ((*read_data--) ^ 0x80) << 8;
|
|
*write_data_b++ |= *read_data--;
|
|
} while (read_data < read_end);
|
|
gus_sample->loop_start += loop_length;
|
|
gus_sample->loop_end += dloop_length;
|
|
gus_sample->data_length = new_length;
|
|
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
|
|
return 0;
|
|
}
|
|
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
|
|
return -1;
|
|
}
|
|
|
|
/* sample loading */
|
|
|
|
struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) {
|
|
unsigned char *gus_patch;
|
|
unsigned long int gus_size;
|
|
unsigned long int gus_ptr;
|
|
unsigned char no_of_samples;
|
|
struct _sample *gus_sample = NULL;
|
|
struct _sample *first_gus_sample = NULL;
|
|
unsigned long int i = 0;
|
|
|
|
int (*do_convert[])(unsigned char *data, struct _sample *gus_sample) = {
|
|
convert_8s,
|
|
convert_16s,
|
|
convert_8u,
|
|
convert_16u,
|
|
convert_8sp,
|
|
convert_16sp,
|
|
convert_8up,
|
|
convert_16up,
|
|
convert_8sr,
|
|
convert_16sr,
|
|
convert_8ur,
|
|
convert_16ur,
|
|
convert_8srp,
|
|
convert_16srp,
|
|
convert_8urp,
|
|
convert_16urp
|
|
};
|
|
unsigned long int tmp_loop;
|
|
|
|
SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename);
|
|
|
|
if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) {
|
|
return NULL;
|
|
}
|
|
if (gus_size < 239) {
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
|
|
free(gus_patch);
|
|
return NULL;
|
|
}
|
|
if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22)
|
|
&& memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) {
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
|
|
0);
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
|
|
free(gus_patch);
|
|
return NULL;
|
|
}
|
|
if (gus_patch[82] > 1) {
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
|
|
0);
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
|
|
free(gus_patch);
|
|
return NULL;
|
|
}
|
|
if (gus_patch[151] > 1) {
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
|
|
0);
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
|
|
free(gus_patch);
|
|
return NULL;
|
|
}
|
|
|
|
GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]);
|
|
|
|
no_of_samples = gus_patch[198];
|
|
gus_ptr = 239;
|
|
while (no_of_samples) {
|
|
unsigned long int tmp_cnt;
|
|
if (first_gus_sample == NULL) {
|
|
first_gus_sample = (struct _sample*)malloc(sizeof(struct _sample));
|
|
gus_sample = first_gus_sample;
|
|
} else {
|
|
gus_sample->next = (struct _sample*)malloc(sizeof(struct _sample));
|
|
gus_sample = gus_sample->next;
|
|
}
|
|
if (gus_sample == NULL) {
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
|
|
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
|
|
free(gus_patch);
|
|
return NULL;
|
|
}
|
|
|
|
gus_sample->next = NULL;
|
|
gus_sample->loop_fraction = gus_patch[gus_ptr + 7];
|
|
gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24)
|
|
| (gus_patch[gus_ptr + 10] << 16)
|
|
| (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8];
|
|
gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24)
|
|
| (gus_patch[gus_ptr + 14] << 16)
|
|
| (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12];
|
|
gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24)
|
|
| (gus_patch[gus_ptr + 18] << 16)
|
|
| (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16];
|
|
gus_sample->rate = (gus_patch[gus_ptr + 21] << 8)
|
|
| gus_patch[gus_ptr + 20];
|
|
gus_sample->freq_low = ((gus_patch[gus_ptr + 25] << 24)
|
|
| (gus_patch[gus_ptr + 24] << 16)
|
|
| (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]);
|
|
gus_sample->freq_high = ((gus_patch[gus_ptr + 29] << 24)
|
|
| (gus_patch[gus_ptr + 28] << 16)
|
|
| (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]);
|
|
gus_sample->freq_root = ((gus_patch[gus_ptr + 33] << 24)
|
|
| (gus_patch[gus_ptr + 32] << 16)
|
|
| (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]);
|
|
|
|
/* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */
|
|
/* Result is 0.001% inacurate */
|
|
gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2;
|
|
|
|
#if 0
|
|
/* We dont use this info at this time, kept in here for info */
|
|
printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n",
|
|
gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]);
|
|
printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n",
|
|
gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]);
|
|
#endif
|
|
gus_sample->modes = gus_patch[gus_ptr + 55];
|
|
GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG();
|
|
|
|
if (gus_sample->loop_start > gus_sample->loop_end) {
|
|
tmp_loop = gus_sample->loop_end;
|
|
gus_sample->loop_end = gus_sample->loop_start;
|
|
gus_sample->loop_start = tmp_loop;
|
|
gus_sample->loop_fraction =
|
|
((gus_sample->loop_fraction & 0x0f) << 4)
|
|
| ((gus_sample->loop_fraction & 0xf0) >> 4);
|
|
}
|
|
|
|
/*
|
|
FIXME: Experimental Hacky Fix
|
|
*/
|
|
if (fix_release) {
|
|
if (env_time_table[gus_patch[gus_ptr + 40]]
|
|
< env_time_table[gus_patch[gus_ptr + 41]]) {
|
|
unsigned char tmp_hack_rate = gus_patch[gus_ptr + 41];
|
|
gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40];
|
|
gus_patch[gus_ptr + 40] = tmp_hack_rate;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
if (gus_sample->modes & SAMPLE_ENVELOPE) {
|
|
unsigned char env_rate = gus_patch[gus_ptr + 37 + i];
|
|
gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i];
|
|
GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]);
|
|
gus_sample->env_rate[i] = (signed long int) (4194303.0
|
|
/ ((float) _WM_SampleRate * env_time_table[env_rate]));
|
|
GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate);
|
|
if (gus_sample->env_rate[i] == 0) {
|
|
_WM_ERROR_NEW("%s: Warning: found invalid envelope(%lu) rate setting in %s. Using %f instead.",
|
|
__FUNCTION__, i, filename, env_time_table[63]);
|
|
gus_sample->env_rate[i] = (signed long int) (4194303.0
|
|
/ ((float) _WM_SampleRate * env_time_table[63]));
|
|
GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]);
|
|
}
|
|
} else {
|
|
gus_sample->env_target[i] = 4194303;
|
|
gus_sample->env_rate[i] = (signed long int) (4194303.0
|
|
/ ((float) _WM_SampleRate * env_time_table[63]));
|
|
GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]);
|
|
}
|
|
}
|
|
|
|
gus_sample->env_target[6] = 0;
|
|
gus_sample->env_rate[6] = (signed long int) (4194303.0
|
|
/ ((float) _WM_SampleRate * env_time_table[63]));
|
|
|
|
gus_ptr += 96;
|
|
tmp_cnt = gus_sample->data_length;
|
|
|
|
if (do_convert[(((gus_sample->modes & 0x18) >> 1)
|
|
| (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample)
|
|
== -1) {
|
|
free(gus_patch);
|
|
return NULL;
|
|
}
|
|
|
|
gus_ptr += tmp_cnt;
|
|
gus_sample->loop_start = (gus_sample->loop_start << 10)
|
|
| (((gus_sample->loop_fraction & 0x0f) << 10) / 16);
|
|
gus_sample->loop_end = (gus_sample->loop_end << 10)
|
|
| (((gus_sample->loop_fraction & 0xf0) << 6) / 16);
|
|
gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start;
|
|
gus_sample->data_length = gus_sample->data_length << 10;
|
|
no_of_samples--;
|
|
}
|
|
free(gus_patch);
|
|
return first_gus_sample;
|
|
}
|