- Timidity++ sources added. This compiles but isn't hooked into the engine yet.

This source has been heavily edited to remove the deep integration with the provided UI modules and to eliminate use of global variables and puts everything into a small number of C++ classes.
This commit is contained in:
Christoph Oelckers 2018-02-19 22:14:22 +01:00
parent a3236aa7ef
commit 576932c47f
50 changed files with 34860 additions and 0 deletions

View File

@ -802,6 +802,8 @@ set( FASTMATH_SOURCES
sound/oalsound.cpp
sound/sndfile_decoder.cpp
sound/mididevices/music_timiditypp_mididevice.cpp
sound/timidity++/fft4g.cpp
sound/timidity++/reverb.cpp
gl/utility/gl_clock.cpp
gl/renderer/gl_2ddrawer.cpp
gl/hqnx/init.cpp
@ -832,6 +834,10 @@ set( FASTMATH_SOURCES
gl/models/gl_models.cpp
r_data/models/models.cpp
r_data/matrix.cpp
# These will be removed later.
sound/timidity++/timidity.cpp
sound/timidity++/w32_a.cpp
)
set (PCH_SOURCES
@ -1166,6 +1172,28 @@ set (PCH_SOURCES
sound/timidity/playmidi.cpp
sound/timidity/resample.cpp
sound/timidity/timidity.cpp
sound/timidity++/aq.cpp
sound/timidity++/common.cpp
sound/timidity++/configfile.cpp
sound/timidity++/effect.cpp
sound/timidity++/filter.cpp
sound/timidity++/freq.cpp
sound/timidity++/instrum.cpp
sound/timidity++/mblock.cpp
sound/timidity++/mix.cpp
sound/timidity++/output.cpp
sound/timidity++/playmidi.cpp
sound/timidity++/quantity.cpp
sound/timidity++/readmidi.cpp
sound/timidity++/readmidic.cpp
sound/timidity++/recache.cpp
sound/timidity++/resample.cpp
sound/timidity++/sbkconv.cpp
sound/timidity++/sffile.cpp
sound/timidity++/sfitem.cpp
sound/timidity++/smplfile.cpp
sound/timidity++/sndfont.cpp
sound/timidity++/tables.cpp
sound/wildmidi/file_io.cpp
sound/wildmidi/gus_pat.cpp
sound/wildmidi/reverb.cpp

329
src/sound/timidity++/aq.cpp Normal file
View File

@ -0,0 +1,329 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
aq.c - Audio queue.
Written by Masanao Izumo <mo@goice.co.jp>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "timidity.h"
#include "common.h"
#include "aq.h"
#include "instrum.h"
#include "playmidi.h"
#include "effect.h"
namespace TimidityPlus
{
#define TEST_SPARE_RATE 0.9
#define MAX_BUCKET_TIME 0.2
#define MAX_FILLED_TIME 2.0
AudioQueue::AudioQueue(PlayMode *pm, int bufsize, Reverb *reverb)
{
playMode = pm;
buffer_size = bufsize;
effect = new Effect(reverb);
}
AudioQueue::~AudioQueue()
{
freeSoftQueue();
delete effect;
}
void AudioQueue::setup(void)
{
int ch = 2; // stereo only
/* Initialize Bps, bucket_size, device_qsize, and bucket_time */
if (playMode->encoding & PE_24BIT)
Bps = 3 * ch;
else
Bps = 2 * ch;
bucket_size = buffer_size * Bps;
bucket_time = (double)bucket_size / Bps / playMode->rate;
device_qsize = 0;
freeSoftQueue();
nbuckets = 0;
effect->init_effect();
aq_add_count = 0;
}
void AudioQueue::setSoftQueue(double soft_buff_time, double fill_start_time)
{
int nb;
/* for re-initialize */
if (soft_buff_time < 0)
soft_buff_time = last_soft_buff_time;
if (fill_start_time < 0)
fill_start_time = last_fill_start_time;
nb = (int)(soft_buff_time / bucket_time);
if (nb == 0)
aq_start_count = 0;
else
aq_start_count = (int32_t)(fill_start_time * playMode->rate);
aq_fill_buffer_flag = (aq_start_count > 0);
if (nbuckets != nb)
{
nbuckets = nb;
allocSoftQueue();
}
last_soft_buff_time = soft_buff_time;
last_fill_start_time = fill_start_time;
}
/* Send audio data to playMode->output_data() */
int AudioQueue::outputData(char *buff, int nbytes)
{
int i;
play_counter += nbytes / Bps;
while (nbytes > 0)
{
i = nbytes;
if (i > bucket_size)
i = bucket_size;
if (playMode->output_data(buff, i) == -1)
return -1;
nbytes -= i;
buff += i;
}
return 0;
}
int AudioQueue::add(int32_t *samples, int32_t count)
{
int32_t nbytes, i;
char *buff;
if (!count)
{
return 0;
}
aq_add_count += count;
effect->do_effect(samples, count);
nbytes = general_output_convert(samples, count);
buff = (char *)samples;
if (device_qsize == 0)
return playMode->output_data(buff, nbytes);
aq_fill_buffer_flag = (aq_add_count <= aq_start_count);
while ((i = addPlayBucket(buff, nbytes)) < nbytes)
{
buff += i;
nbytes -= i;
if (head && head->len == bucket_size)
{
if (fillOne() == -1)
return -1;
}
aq_fill_buffer_flag = 0;
}
return 0;
}
/* alloc_soft_queue() (re-)initializes audio buckets. */
void AudioQueue::allocSoftQueue(void)
{
int i;
char *base;
freeSoftQueue();
base_buckets = new AudioBucket[nbuckets];
base = new char[nbuckets * bucket_size];
for (i = 0; i < nbuckets; i++)
base_buckets[i].data = base + i * bucket_size;
flushBuckets();
}
void AudioQueue::freeSoftQueue(void)
{
if (base_buckets)
{
delete[] base_buckets[0].data;
delete[] base_buckets;
base_buckets = NULL;
}
}
/* aq_fill_one() transfers one audio bucket to device. */
int AudioQueue::fillOne(void)
{
AudioBucket *tmp;
if (head == NULL)
return 0;
if (outputData(head->data, bucket_size) == -1)
return -1;
tmp = head;
head = head->next;
reuseAudioBucket(tmp);
return 0;
}
int32_t AudioQueue::softFilled(void)
{
int32_t bytes;
AudioBucket *cur;
bytes = 0;
for (cur = head; cur != NULL; cur = cur->next)
bytes += cur->len;
return bytes / Bps;
}
int AudioQueue::softFlush(void)
{
while (head)
{
if (head->len < bucket_size)
{
/* Add silence code */
memset(head->data + head->len, 0, bucket_size - head->len);
head->len = bucket_size;
}
if (fillOne() == -1)
return RC_ERROR;
}
return RC_OK;
}
int AudioQueue::flush(int discard)
{
aq_add_count = 0;
effect->init_effect();
if (discard)
{
if (playMode->acntl(PM_REQ_DISCARD, NULL) != -1)
{
flushBuckets();
return RC_OK;
}
}
playMode->acntl(PM_REQ_FLUSH, NULL);
flushBuckets();
return RC_OK;
}
/* add_play_bucket() attempts to add buf to audio bucket.
* It returns actually added bytes.
*/
int AudioQueue::addPlayBucket(const char *buf, int n)
{
int total;
if (n == 0)
return 0;
if (!nbuckets) {
playMode->output_data((char *)buf, n);
return n;
}
if (head == NULL)
head = tail = nextAllocatedBucket();
total = 0;
while (n > 0)
{
int i;
if (tail->len == bucket_size)
{
AudioBucket *b;
if ((b = nextAllocatedBucket()) == NULL)
break;
if (head == NULL)
head = tail = b;
else
tail = tail->next = b;
}
i = bucket_size - tail->len;
if (i > n)
i = n;
memcpy(tail->data + tail->len, buf + total, i);
total += i;
n -= i;
tail->len += i;
}
return total;
}
/* Flush and clear audio bucket */
void AudioQueue::flushBuckets(void)
{
int i;
allocated_bucket_list = NULL;
for (i = 0; i < nbuckets; i++)
reuseAudioBucket(&base_buckets[i]);
head = tail = NULL;
aq_fill_buffer_flag = (aq_start_count > 0);
play_counter = play_offset_counter = 0;
}
/* next_allocated_bucket() gets free bucket. If all buckets is used, it
* returns NULL.
*/
AudioQueue::AudioBucket *AudioQueue::nextAllocatedBucket(void)
{
AudioBucket *b;
if (allocated_bucket_list == NULL)
return NULL;
b = allocated_bucket_list;
allocated_bucket_list = allocated_bucket_list->next;
b->len = 0;
b->next = NULL;
return b;
}
/* Reuse specified bucket */
void AudioQueue::reuseAudioBucket(AudioBucket *bucket)
{
bucket->next = allocated_bucket_list;
allocated_bucket_list = bucket;
}
}

97
src/sound/timidity++/aq.h Normal file
View File

@ -0,0 +1,97 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
aq.h - Audio queue.
Written by Masanao Izumo <mo@goice.co.jp>
*/
#ifndef ___AQ_H_
#define ___AQ_H_
#include <stdint.h>
namespace TimidityPlus
{
/* interfaces */
class Effect;
class Reverb;
struct PlayMode;
class AudioQueue
{
struct AudioBucket
{
char *data;
int len;
AudioBucket *next;
};
Effect *effect;
PlayMode *playMode;
int buffer_size = 0;
int32_t device_qsize = 0;
int Bps = 0; /* Bytes per sample frame */
int bucket_size = 0;
int nbuckets = 0;
double bucket_time = 0;
int aq_fill_buffer_flag = 0;
int32_t aq_start_count = 0;
int32_t aq_add_count = 0;
int32_t play_counter = 0, play_offset_counter = 0;
double play_start_time = 0;
AudioBucket *base_buckets = NULL;
AudioBucket *allocated_bucket_list = NULL;
AudioBucket *head = NULL;
AudioBucket *tail = NULL;
void allocSoftQueue(void);
int addPlayBucket(const char *buf, int n);
void reuseAudioBucket(AudioBucket *bucket);
AudioBucket *nextAllocatedBucket(void);
void flushBuckets(void);
int fillOne(void);
int outputData(char *buff, int nbytes);
double last_soft_buff_time, last_fill_start_time;
public:
AudioQueue(PlayMode *pm, int buffersize, Reverb *reverb); // play_mode, audio_buffer_size
~AudioQueue();
void setup(); // allocates the buffer for software queue, and estimate maxmum queue size of audio device.
void setSoftQueue(double soft_buff_time, double fill_start_time); // makes software audio queue. If fill_start_time is positive, TiMidity doesn't start playing immidiately until the autio buffer is filled.
int add(int32_t *samples, int32_t count); // adds new samples to software queue. If samples is NULL, only updates internal software queue buffer.
int32_t softFilled(void); // returns filled queue length of software buffer.
int flush(int discard); // If discard is true, discards all audio queue and returns immediately, otherwise waits until play all out.
int softFlush(void); // transfers all buffer to device
void freeSoftQueue(void); // free soft_que memory
int fillBufferFlag() // non-zero if aq->add() is in filling mode
{
return aq_fill_buffer_flag;
}
};
}
#endif /* ___AQ_H_ */

View File

@ -0,0 +1,275 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
common.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include "m_random.h"
#include "common.h"
namespace TimidityPlus
{
/* This'll allocate memory or die. */
void *safe_malloc(size_t count)
{
auto p = malloc(count);
if (p == nullptr)
{
// I_FatalError("Out of memory");
}
return p;
}
void *safe_large_malloc(size_t count)
{
return safe_malloc(count);
}
void *safe_realloc(void *ptr, size_t count)
{
auto p = realloc(ptr, count);
if (p == nullptr)
{
// I_FatalError("Out of memory");
}
return p;
}
char *safe_strdup(const char *s)
{
if (s == nullptr) s = "";
auto p = strdup(s);
if (p == nullptr)
{
// I_FatalError("Out of memory");
}
return p;
}
/* free ((void **)ptr_list)[0..count-1] and ptr_list itself */
void free_ptr_list(void *ptr_list, int count)
{
int i;
for (i = 0; i < count; i++)
free(((void **)ptr_list)[i]);
free(ptr_list);
}
static int atoi_limited(const char *string, int v_min, int v_max)
{
int value = atoi(string);
if (value <= v_min)
value = v_min;
else if (value > v_max)
value = v_max;
return value;
}
int string_to_7bit_range(const char *string_, int *start, int *end)
{
const char *string = string_;
if (isdigit(*string))
{
*start = atoi_limited(string, 0, 127);
while (isdigit(*++string));
}
else
*start = 0;
if (*string == '-')
{
string++;
*end = isdigit(*string) ? atoi_limited(string, 0, 127) : 127;
if (*start > *end)
*end = *start;
}
else
*end = *start;
return string != string_;
}
static FRandom pr_rnd;
int int_rand(int n)
{
return (int)pr_rnd.GenRand_Real1() * n;
}
double flt_rand()
{
return (int)pr_rnd.GenRand_Real1();
}
PathList::PathList()
{
paths.push_back("./");
}
/* This adds a directory to the path list */
void PathList::addPath(const char *str)
{
if (*str == 0) return;
for (size_t i = 0; i < paths.size(); i++)
{
if (pathcmp(paths[i].c_str(), str, 0) == 0)
{
// move string to the back.
std::string ss = paths[i];
paths.erase(paths.begin() + i);
paths.push_back(ss);
return;
}
}
paths.push_back(str);
}
int PathList::pathcmp(const char *p1, const char *p2, int ignore_case)
{
int c1, c2;
#ifdef _WIN32
ignore_case = 1; /* Always ignore the case */
#endif
do {
c1 = *p1++ & 0xff;
c2 = *p2++ & 0xff;
if (ignore_case)
{
c1 = tolower(c1);
c2 = tolower(c2);
}
if (c1 == '/') c1 = *p1 ? 0x100 : 0;
if (c1 == '/') c2 = *p2 ? 0x100 : 0;
} while (c1 == c2 && c1 /* && c2 */);
return c1 - c2;
}
std::pair<FileReader *, std::string> PathList::openFile(const char *name)
{
if (name && *name)
{
/* First try the given name */
FileReader *fr = new FileReader;
if (fr->Open(name))
{
return std::make_pair(fr, std::string(name));
}
if (!isAbsPath(name))
{
for (int i = (int)paths.size() - 1; i >= 0; i--)
{
std::string s = paths[i];
auto c = s.at(s.length() - 1);
if (c != '/' && c != '#' && name[0] != '#')
{
s += '/';
}
s += name;
if (fr->Open(s.c_str())) return std::make_pair(fr, s);
}
}
delete fr;
}
return std::make_pair(nullptr, std::string());
}
int PathList::isAbsPath(const char *name)
{
if (name[0] == '/')
return 1;
#ifdef _WIN32
/* [A-Za-z]: (for Windows) */
if (isalpha(name[0]) && name[1] == ':')
return 1;
#endif /* _WIN32 */
return 0;
}
struct timidity_file *open_file(const char *name, int decompress, int noise_mode, PathList &pathList)
{
auto file = pathList.openFile(name);
if (!file.first) return nullptr;
auto tf = new timidity_file;
tf->url = file.first;
tf->filename = file.second;
return tf;
}
/* This closes files opened with open_file */
void close_file(struct timidity_file *tf)
{
if (tf->url != NULL)
{
tf->url->Close();
}
delete tf;
}
/* This is meant for skipping a few bytes. */
void skip(struct timidity_file *tf, size_t len)
{
tf->url->Seek((long)len, SEEK_CUR);
}
char *tf_gets(char *buff, int n, struct timidity_file *tf)
{
return tf->url->Gets(buff, n);
}
int tf_getc(struct timidity_file *tf)
{
unsigned char c;
auto read = tf->url->Read(&c, 1);
return read == 0 ? EOF : c;
}
long tf_read(void *buff, int32_t size, int32_t nitems, struct timidity_file *tf)
{
return tf->url->Read(buff, size * nitems) / size;
}
long tf_seek(struct timidity_file *tf, long offset, int whence)
{
return tf->url->Seek(offset, whence);
}
long tf_tell(struct timidity_file *tf)
{
return tf->url->Tell();
}
}

View File

@ -0,0 +1,90 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
common.h
*/
#ifndef ___COMMON_H_
#define ___COMMON_H_
#include <string>
#include <vector>
#include <stdint.h>
#include "files.h"
namespace TimidityPlus
{
class PathList
{
std::vector<std::string> paths;
int isAbsPath(const char *name);
public:
PathList();
void addPath(const char *str);
void clear()
{
paths.resize(1);
}
static int pathcmp(const char *p1, const char *p2, int ignore_case);
std::pair<FileReader *, std::string> openFile(const char *name);
};
struct timidity_file
{
FileReader *url;
std::string filename;
};
/* Noise modes for open_file */
enum
{
OF_SILENT = 0,
OF_NORMAL = 1,
OF_VERBOSE = 2,
};
extern struct timidity_file *open_file(const char *name, int decompress, int noise_mode, PathList &);
extern void close_file(struct timidity_file *tf);
extern void skip(struct timidity_file *tf, size_t len);
extern char *tf_gets(char *buff, int n, struct timidity_file *tf);
int tf_getc(struct timidity_file *tf);
extern long tf_read(void *buff, int32_t size, int32_t nitems, struct timidity_file *tf);
extern long tf_seek(struct timidity_file *tf, long offset, int whence);
extern long tf_tell(struct timidity_file *tf);
extern int int_rand(int n); /* random [0..n-1] */
double flt_rand();
extern int check_file_extension(char *filename, char *ext, int decompress);
extern void *safe_malloc(size_t count);
extern void *safe_realloc(void *old_ptr, size_t new_size);
extern void *safe_large_malloc(size_t count);
extern char *safe_strdup(const char *s);
extern void free_ptr_list(void *ptr_list, int count);
extern int string_to_7bit_range(const char *s, int *start, int *end);
extern int load_table(char *file);
}
#endif /* ___COMMON_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
controls.h
*/
#ifndef ___CONTROLS_H_
#define ___CONTROLS_H_
namespace TimidityPlus
{
enum
{
/* Return values for ControlMode.read */
RC_ERROR = -1,
RC_OK = 0,
RC_QUIT = 1,
RC_TUNE_END = 3,
RC_STOP = 4, /* Stop to play */
CMSG_INFO = 0,
CMSG_WARNING = 1,
CMSG_ERROR = 2,
VERB_NORMAL = 0,
VERB_VERBOSE = 1,
VERB_NOISY = 2,
VERB_DEBUG = 3,
};
inline bool RC_IS_SKIP_FILE(int rc)
{
return ((rc) == RC_QUIT || (rc) == RC_ERROR || (rc) == RC_STOP || (rc) == RC_TUNE_END);
}
inline void ctl_cmsg(int type, int verbosity_level, const char *fmt, ...)
{
/* todo:
CMSG_ERROR: I_Error(...)
CMSG_WARNING, VERB_NORMAL: Printf(TEXTCOLOR_YELLOW
CMSG_WARNING, VERB_VERBOSE: DPrintf(DMSG_SPAMMY
CMSG_INFO, VERB_DEBUG/VERB_NOISY: ignore
/*
#ifdef _WIN32
char buf[1024];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
I_DebugPrint(buf);
#endif
*/
}
}
#endif /* ___CONTROLS_H_ */

View File

@ -0,0 +1,225 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
effect.c - To apply sound effects.
Mainly written by Masanao Izumo <iz@onicos.co.jp>
Interfaces:
void init_effect(void);
do_effect(int32_t* buf, int32_t count);
*/
#include <string.h>
#include <stdlib.h>
#include "effect.h"
#include "instrum.h"
#include "playmidi.h"
#include "reverb.h"
namespace TimidityPlus
{
#define SIDE_CONTI_SEC 10
#define CHANGE_SEC 2.0
void Effect::init_effect()
{
effect_left_right_delay(NULL, 0);
reverb->init_for_effect();
}
/*
* Left & Right Delay Effect
*/
void Effect::effect_left_right_delay(int32_t *buff, int32_t count)
{
int32_t save[AUDIO_BUFFER_SIZE * 2];
int32_t pi, i, j, k, v, backoff;
int b;
int32_t *p;
if (buff == NULL)
{
memset(prev, 0, sizeof(prev));
return;
}
if (effect_lr_mode == 0 || effect_lr_mode == 1 || effect_lr_mode == 2)
b = effect_lr_mode;
else
return;
count *= 2;
backoff = 2 * (int)(playback_rate * effect_lr_delay_msec / 1000.0);
if (backoff == 0)
return;
if (backoff > count)
backoff = count;
if (count < audio_buffer_size * 2)
{
memset(buff + count, 0, 4 * (audio_buffer_size * 2 - count));
count = audio_buffer_size * 2;
}
memcpy(save, buff, 4 * count);
pi = count - backoff;
if (b == 2)
{
if (turn_counter == 0)
{
turn_counter = SIDE_CONTI_SEC * playback_rate;
/* status: 0 -> 2 -> 3 -> 1 -> 4 -> 5 -> 0 -> ...
* status left right
* 0 - + (right)
* 1 + - (left)
* 2 -> + + (right -> center)
* 3 + -> - (center -> left)
* 4 -> - - (left -> center)
* 5 - -> + (center -> right)
*/
status = 0;
tc = 0;
}
p = prev;
for (i = 0; i < count; i += 2, pi += 2)
{
if (i < backoff)
p = prev;
else if (p == prev)
{
pi = 0;
p = save;
}
if (status < 2)
buff[i + status] = p[pi + status];
else if (status < 4)
{
j = (status & 1);
v = (int32_t)(rate0 * buff[i + j] + rate1 * p[pi + j]);
buff[i + j] = v;
rate0 += dr, rate1 -= dr;
}
else
{
j = (status & 1);
k = !j;
v = (int32_t)(rate0 * buff[i + j] + rate1 * p[pi + j]);
buff[i + j] = v;
buff[i + k] = p[pi + k];
rate0 += dr, rate1 -= dr;
}
tc++;
if (tc == turn_counter)
{
tc = 0;
switch (status)
{
case 0:
status = 2;
turn_counter = (CHANGE_SEC / 2.0) * playback_rate;
rate0 = 0.0;
rate1 = 1.0;
dr = 1.0 / turn_counter;
break;
case 2:
status = 3;
rate0 = 1.0;
rate1 = 0.0;
dr = -1.0 / turn_counter;
break;
case 3:
status = 1;
turn_counter = SIDE_CONTI_SEC * playback_rate;
break;
case 1:
status = 4;
turn_counter = (CHANGE_SEC / 2.0) * playback_rate;
rate0 = 1.0;
rate1 = 0.0;
dr = -1.0 / turn_counter;
break;
case 4:
status = 5;
turn_counter = (CHANGE_SEC / 2.0) * playback_rate;
rate0 = 0.0;
rate1 = 1.0;
dr = 1.0 / turn_counter;
break;
case 5:
status = 0;
turn_counter = SIDE_CONTI_SEC * playback_rate;
break;
}
}
}
}
else
{
for (i = 0; i < backoff; i += 2, pi += 2)
buff[b + i] = prev[b + pi];
for (pi = 0; i < count; i += 2, pi += 2)
buff[b + i] = save[b + pi];
}
memcpy(prev + count - backoff, save + count - backoff, 4 * backoff);
}
void Effect::do_effect(int32_t *buf, int32_t count)
{
int32_t nsamples = count * 2;
int reverb_level = (opt_reverb_control < 0)
? -opt_reverb_control & 0x7f : DEFAULT_REVERB_SEND_LEVEL;
/* for static reverb / chorus level */
if (opt_reverb_control == 2 || opt_reverb_control == 4
|| (opt_reverb_control < 0 && !(opt_reverb_control & 0x80))
|| opt_chorus_control < 0)
{
reverb->set_dry_signal(buf, nsamples);
/* chorus sounds horrible
* if applied globally on top of channel chorus
*/
if (opt_reverb_control == 2 || opt_reverb_control == 4
|| (opt_reverb_control < 0 && !(opt_reverb_control & 0x80)))
reverb->set_ch_reverb(buf, nsamples, reverb_level);
reverb->mix_dry_signal(buf, nsamples);
/* chorus sounds horrible
* if applied globally on top of channel chorus
*/
if (opt_reverb_control == 2 || opt_reverb_control == 4
|| (opt_reverb_control < 0 && !(opt_reverb_control & 0x80)))
reverb->do_ch_reverb(buf, nsamples);
}
/* L/R Delay */
effect_left_right_delay(buf, count);
}
uint32_t Effect::frand(void)
{
return rng.GenRand32();
}
int32_t Effect::my_mod(int32_t x, int32_t n)
{
if (x >= n)
x -= n;
return x;
}
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
#include "m_random.h"
#include "timidity.h"
namespace TimidityPlus
{
class Reverb;
class Effect
{
void effect_left_right_delay(int32_t *, int32_t);
void init_mtrand(void);
uint32_t frand(void);
int32_t my_mod(int32_t, int32_t);
int turn_counter = 0, tc = 0;
int status = 0;
double rate0 = 0, rate1 = 0, dr = 0;
int32_t prev[AUDIO_BUFFER_SIZE * 2] = { 0 };
FRandom rng;
Reverb *reverb;
public:
Effect(Reverb *_reverb)
{
reverb = _reverb;
}
void init_effect();
void do_effect(int32_t *buf, int32_t count);
};
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
/*
Copyright(C) 1996-1999 Takuya OOURA
email: ooura@mmm.t.u-tokyo.ac.jp
download: http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html
You may use, copy, modify this code for any purpose and
without fee. You may distribute this ORIGINAL package.
*/
namespace TimidityPlus
{
extern void cdft(int, int, float *, int *, float *);
extern void rdft(int, int, float *, int *, float *);
extern void ddct(int, int, float *, int *, float *);
extern void ddst(int, int, float *, int *, float *);
extern void dfct(int, float *, float *, int *, float *);
extern void dfst(int, float *, float *, int *, float *);
}

View File

@ -0,0 +1,200 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
filter.c: written by Vincent Pagel ( pagel@loria.fr )
implements fir antialiasing filter : should help when setting sample
rates as low as 8Khz.
April 95
- first draft
22/5/95
- modify "filter" so that it simulate leading and trailing 0 in the buffer
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "filter.h"
namespace TimidityPlus
{
/* bessel function */
static double ino(double x)
{
double y, de, e, sde;
int i;
y = x / 2;
e = 1.0;
de = 1.0;
i = 1;
do {
de = de * y / (double)i;
sde = de * de;
e += sde;
} while (!((e * 1.0e-08 - sde > 0) || (i++ > 25)));
return(e);
}
/* Kaiser Window (symetric) */
static void kaiser(double *w, int n, double beta)
{
double xind, xi;
int i;
xind = (2 * n - 1) * (2 * n - 1);
for (i = 0; i < n; i++)
{
xi = i + 0.5;
w[i] = ino((double)(beta * sqrt((double)(1. - 4 * xi * xi / xind))))
/ ino((double)beta);
}
}
/*
* fir coef in g, cuttoff frequency in fc
*/
static void designfir(double *g, double fc)
{
int i;
double xi, omega, att, beta;
double w[ORDER2];
for (i = 0; i < ORDER2; i++)
{
xi = (double)i + 0.5;
omega = M_PI * xi;
g[i] = sin((double)omega * fc) / omega;
}
att = 40.; /* attenuation in db */
beta = (double)exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886
* (att - 20.96);
kaiser(w, ORDER2, beta);
/* Matrix product */
for (i = 0; i < ORDER2; i++)
g[i] = g[i] * w[i];
}
/*
* FIR filtering -> apply the filter given by coef[] to the data buffer
* Note that we simulate leading and trailing 0 at the border of the
* data buffer
*/
static void filter(int16_t *result, int16_t *data, int32_t length, double coef[])
{
int32_t sample, i, sample_window;
int16_t peak = 0;
double sum;
/* Simulate leading 0 at the begining of the buffer */
for (sample = 0; sample < ORDER2; sample++)
{
sum = 0.0;
sample_window = sample - ORDER2;
for (i = 0; i < ORDER; i++)
sum += coef[i] *
((sample_window < 0) ? 0.0 : data[sample_window++]);
/* Saturation ??? */
if (sum > 32767.) { sum = 32767.; peak++; }
if (sum < -32768.) { sum = -32768; peak++; }
result[sample] = (int16_t)sum;
}
/* The core of the buffer */
for (sample = ORDER2; sample < length - ORDER + ORDER2; sample++)
{
sum = 0.0;
sample_window = sample - ORDER2;
for (i = 0; i < ORDER; i++)
sum += data[sample_window++] * coef[i];
/* Saturation ??? */
if (sum > 32767.) { sum = 32767.; peak++; }
if (sum < -32768.) { sum = -32768; peak++; }
result[sample] = (int16_t)sum;
}
/* Simulate 0 at the end of the buffer */
for (sample = length - ORDER + ORDER2; sample < length; sample++)
{
sum = 0.0;
sample_window = sample - ORDER2;
for (i = 0; i < ORDER; i++)
sum += coef[i] *
((sample_window >= length) ? 0.0 : data[sample_window++]);
/* Saturation ??? */
if (sum > 32767.) { sum = 32767.; peak++; }
if (sum < -32768.) { sum = -32768; peak++; }
result[sample] = (int16_t)sum;
}
}
/***********************************************************************/
/* Prevent aliasing by filtering any freq above the output_rate */
/* */
/* I don't worry about looping point -> they will remain soft if they */
/* were already */
/***********************************************************************/
void antialiasing(int16_t *data, int32_t data_length,
int32_t sample_rate, int32_t output_rate)
{
int16_t *temp;
int i;
double fir_symetric[ORDER];
double fir_coef[ORDER2];
double freq_cut; /* cutoff frequency [0..1.0] FREQ_CUT/SAMP_FREQ*/
/* No oversampling */
if (output_rate >= sample_rate)
return;
freq_cut = (double)output_rate / (double)sample_rate;
designfir(fir_coef, freq_cut);
/* Make the filter symetric */
for (i = 0; i < ORDER2; i++)
fir_symetric[ORDER - 1 - i] = fir_symetric[i] = fir_coef[ORDER2 - 1 - i];
/* We apply the filter we have designed on a copy of the patch */
temp = (int16_t *)safe_malloc(2 * data_length);
memcpy(temp, data, 2 * data_length);
filter(data, temp, data_length, fir_symetric);
free(temp);
}
}

View File

@ -0,0 +1,46 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
filter.h : written by Vincent Pagel ( pagel@loria.fr )
implements fir antialiasing filter : should help when setting sample
rates as low as 8Khz.
*/
#ifndef ___FILTER_H_
#define ___FILTER_H_
#include <stdint.h>
namespace TimidityPlus
{
/* Order of the FIR filter = 20 should be enough ! */
enum
{
ORDER = 20,
ORDER2 = ORDER / 2
};
void antialiasing(int16_t *data, int32_t data_length, int32_t sample_rate, int32_t output_rate);
}
#endif /* ___FILTER_H_ */

View File

@ -0,0 +1,709 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "freq.h"
#include "fft4g.h"
namespace TimidityPlus
{
/* middle C = pitch 60 = 261.6 Hz
freq = 13.75 * exp((pitch - 9) / 12 * log(2))
pitch = 9 - log(13.75 / freq) * 12 / log(2)
= -36.37631656 + 17.31234049 * log(freq)
*/
const float pitch_freq_table[129] = {
8.17579892f, 8.66195722f, 9.17702400f, 9.72271824f, 10.3008612f, 10.9133822f,
11.5623257f, 12.2498574f, 12.9782718f, 13.7500000f, 14.5676175f, 15.4338532f,
16.3515978f, 17.3239144f, 18.3540480f, 19.4454365f, 20.6017223f, 21.8267645f,
23.1246514f, 24.4997147f, 25.9565436f, 27.5000000f, 29.1352351f, 30.8677063f,
32.7031957f, 34.6478289f, 36.7080960f, 38.8908730f, 41.2034446f, 43.6535289f,
46.2493028f, 48.9994295f, 51.9130872f, 55.0000000f, 58.2704702f, 61.7354127f,
65.4063913f, 69.2956577f, 73.4161920f, 77.7817459f, 82.4068892f, 87.3070579f,
92.4986057f, 97.9988590f, 103.826174f, 110.000000f, 116.540940f, 123.470825f,
130.812783f, 138.591315f, 146.832384f, 155.563492f, 164.813778f, 174.614116f,
184.997211f, 195.997718f, 207.652349f, 220.000000f, 233.081881f, 246.941651f,
261.625565f, 277.182631f, 293.664768f, 311.126984f, 329.627557f, 349.228231f,
369.994423f, 391.995436f, 415.304698f, 440.000000f, 466.163762f, 493.883301f,
523.251131f, 554.365262f, 587.329536f, 622.253967f, 659.255114f, 698.456463f,
739.988845f, 783.990872f, 830.609395f, 880.000000f, 932.327523f, 987.766603f,
1046.50226f, 1108.73052f, 1174.65907f, 1244.50793f, 1318.51023f, 1396.91293f,
1479.97769f, 1567.98174f, 1661.21879f, 1760.00000f, 1864.65505f, 1975.53321f,
2093.00452f, 2217.46105f, 2349.31814f, 2489.01587f, 2637.02046f, 2793.82585f,
2959.95538f, 3135.96349f, 3322.43758f, 3520.00000f, 3729.31009f, 3951.06641f,
4186.00904f, 4434.92210f, 4698.63629f, 4978.03174f, 5274.04091f, 5587.65170f,
5919.91076f, 6271.92698f, 6644.87516f, 7040.00000f, 7458.62018f, 7902.13282f,
8372.01809f, 8869.84419f, 9397.27257f, 9956.06348f, 10548.0818f, 11175.3034f,
11839.8215f, 12543.8540f, 13289.7503f
};
/* center_pitch + 0.49999 */
const float pitch_freq_ub_table[129] = {
8.41536325f, 8.91576679f, 9.44592587f, 10.0076099f, 10.6026933f, 11.2331623f,
11.9011208f, 12.6087983f, 13.3585565f, 14.1528976f, 14.9944727f, 15.8860904f,
16.8307265f, 17.8315336f, 18.8918517f, 20.0152197f, 21.2053866f, 22.4663245f,
23.8022417f, 25.2175966f, 26.7171129f, 28.3057952f, 29.9889453f, 31.7721808f,
33.6614530f, 35.6630672f, 37.7837035f, 40.0304394f, 42.4107732f, 44.9326490f,
47.6044834f, 50.4351932f, 53.4342259f, 56.6115903f, 59.9778907f, 63.5443616f,
67.3229060f, 71.3261343f, 75.5674070f, 80.0608788f, 84.8215464f, 89.8652980f,
95.2089667f, 100.870386f, 106.868452f, 113.223181f, 119.955781f, 127.088723f,
134.645812f, 142.652269f, 151.134814f, 160.121758f, 169.643093f, 179.730596f,
190.417933f, 201.740773f, 213.736904f, 226.446361f, 239.911563f, 254.177446f,
269.291624f, 285.304537f, 302.269628f, 320.243515f, 339.286186f, 359.461192f,
380.835867f, 403.481546f, 427.473807f, 452.892723f, 479.823125f, 508.354893f,
538.583248f, 570.609074f, 604.539256f, 640.487030f, 678.572371f, 718.922384f,
761.671734f, 806.963092f, 854.947614f, 905.785445f, 959.646250f, 1016.70979f,
1077.16650f, 1141.21815f, 1209.07851f, 1280.97406f, 1357.14474f, 1437.84477f,
1523.34347f, 1613.92618f, 1709.89523f, 1811.57089f, 1919.29250f, 2033.41957f,
2154.33299f, 2282.43630f, 2418.15702f, 2561.94812f, 2714.28948f, 2875.68954f,
3046.68693f, 3227.85237f, 3419.79046f, 3623.14178f, 3838.58500f, 4066.83914f,
4308.66598f, 4564.87260f, 4836.31405f, 5123.89624f, 5428.57897f, 5751.37907f,
6093.37387f, 6455.70474f, 6839.58092f, 7246.28356f, 7677.17000f, 8133.67829f,
8617.33197f, 9129.74519f, 9672.62809f, 10247.7925f, 10857.1579f, 11502.7581f,
12186.7477f, 12911.4095f, 13679.1618f
};
/* center_pitch - 0.49999 */
const float pitch_freq_lb_table[129] = {
7.94305438f, 8.41537297f, 8.91577709f, 9.44593678f, 10.0076214f, 10.6027055f,
11.2331752f, 11.9011346f, 12.6088129f, 13.3585719f, 14.1529139f, 14.9944900f,
15.8861088f, 16.8307459f, 17.8315542f, 18.8918736f, 20.0152428f, 21.2054111f,
22.4663505f, 23.8022692f, 25.2176258f, 26.7171438f, 28.3058279f, 29.9889800f,
31.7722175f, 33.6614919f, 35.6631084f, 37.7837471f, 40.0304857f, 42.4108222f,
44.9327009f, 47.6045384f, 50.4352515f, 53.4342876f, 56.6116557f, 59.9779599f,
63.5444350f, 67.3229838f, 71.3262167f, 75.5674943f, 80.0609713f, 84.8216444f,
89.8654018f, 95.2090767f, 100.870503f, 106.868575f, 113.223311f, 119.955920f,
127.088870f, 134.645968f, 142.652433f, 151.134989f, 160.121943f, 169.643289f,
179.730804f, 190.418153f, 201.741006f, 213.737151f, 226.446623f, 239.911840f,
254.177740f, 269.291935f, 285.304867f, 302.269977f, 320.243885f, 339.286578f,
359.461607f, 380.836307f, 403.482012f, 427.474301f, 452.893246f, 479.823680f,
508.355480f, 538.583870f, 570.609734f, 604.539954f, 640.487770f, 678.573155f,
718.923215f, 761.672614f, 806.964024f, 854.948602f, 905.786491f, 959.647359f,
1016.71096f, 1077.16774f, 1141.21947f, 1209.07991f, 1280.97554f, 1357.14631f,
1437.84643f, 1523.34523f, 1613.92805f, 1709.89720f, 1811.57298f, 1919.29472f,
2033.42192f, 2154.33548f, 2282.43893f, 2418.15982f, 2561.95108f, 2714.29262f,
2875.69286f, 3046.69045f, 3227.85610f, 3419.79441f, 3623.14597f, 3838.58944f,
4066.84384f, 4308.67096f, 4564.87787f, 4836.31963f, 5123.90216f, 5428.58524f,
5751.38572f, 6093.38091f, 6455.71219f, 6839.58882f, 7246.29193f, 7677.17887f,
8133.68768f, 8617.34192f, 9129.75574f, 9672.63927f, 10247.8043f, 10857.1705f,
11502.7714f, 12186.7618f, 12911.4244f
};
/* (M)ajor, rotate back 1, rotate back 2
(m)inor, rotate back 1, rotate back 2
(d)iminished minor, rotate back 1, rotate back 2
(f)ifth, rotate back 1, rotate back 2
*/
const int chord_table[4][3][3] = {
{ { 0, 4, 7, }, { -5, 0, 4, }, { -8, -5, 0, }, },
{ { 0, 3, 7, }, { -5, 0, 3, }, { -9, -5, 0, }, },
{ { 0, 3, 6, }, { -6, 0, 3, }, { -9, -6, 0, }, },
{ { 0, 5, 7, }, { -5, 0, 5, }, { -7, -5, 0, }, },
};
/* write the chord type to *chord, returns the root note of the chord */
int Freq::assign_chord(double *pitchbins, int *chord,
int min_guesspitch, int max_guesspitch, int root_pitch)
{
int type, subtype;
int pitches[19] = { 0 };
int prune_pitches[10] = { 0 };
int i, j, k, n, n2;
double val, cutoff, max;
int root_flag;
*chord = -1;
if (root_pitch - 9 > min_guesspitch)
min_guesspitch = root_pitch - 9;
if (min_guesspitch <= LOWEST_PITCH)
min_guesspitch = LOWEST_PITCH + 1;
if (root_pitch + 9 < max_guesspitch)
max_guesspitch = root_pitch + 9;
if (max_guesspitch >= HIGHEST_PITCH)
max_guesspitch = HIGHEST_PITCH - 1;
/* keep only local maxima */
for (i = min_guesspitch, n = 0; i <= max_guesspitch; i++)
{
val = pitchbins[i];
if (val)
{
if (pitchbins[i - 1] < val && pitchbins[i + 1] < val)
pitches[n++] = i;
}
}
if (n < 3)
return -1;
/* find largest peak */
max = -1;
for (i = 0; i < n; i++)
{
val = pitchbins[pitches[i]];
if (val > max)
max = val;
}
/* discard any peaks below cutoff */
cutoff = 0.2 * max;
for (i = 0, n2 = 0, root_flag = 0; i < n; i++)
{
val = pitchbins[pitches[i]];
if (val >= cutoff)
{
prune_pitches[n2++] = pitches[i];
if (pitches[i] == root_pitch)
root_flag = 1;
}
}
if (!root_flag || n2 < 3)
return -1;
/* search for a chord, must contain root pitch */
for (i = 0; i < n2; i++)
{
for (subtype = 0; subtype < 3; subtype++)
{
if (i + subtype >= n2)
continue;
for (type = 0; type < 4; type++)
{
for (j = 0, n = 0, root_flag = 0; j < 3; j++)
{
k = i + j;
if (k >= n2)
continue;
if (prune_pitches[k] == root_pitch)
root_flag = 1;
if (prune_pitches[k] - prune_pitches[i + subtype] ==
chord_table[type][subtype][j])
n++;
}
if (root_flag && n == 3)
{
*chord = 3 * type + subtype;
return prune_pitches[i + subtype];
}
}
}
}
return -1;
}
/* initialize FFT arrays for the frequency analysis */
int Freq::freq_initialize_fft_arrays(Sample *sp)
{
uint32_t i;
uint32_t length, newlength;
unsigned int rate;
sample_t *origdata;
rate = sp->sample_rate;
length = sp->data_length >> FRACTION_BITS;
origdata = sp->data;
/* copy the sample to a new float array */
floatData.resize(length);
for (i = 0; i < length; i++)
floatData[i] = origdata[i];
/* length must be a power of 2 */
/* set it to smallest power of 2 >= 1.4*rate */
/* at least 1.4*rate is required for decent resolution of low notes */
newlength = pow(2, ceil(log(1.4*rate) / log(2)));
if (length < newlength)
{
floatData.resize(newlength);
memset(&floatData[0] + length, 0, (newlength - length) * sizeof(float));
}
length = newlength;
/* allocate FFT arrays */
/* calculate sin/cos and fft1_bin_to_pitch tables */
if (length != oldfftsize)
{
float f0;
magData.resize(length);
pruneMagData.resize(length);
ipa.resize(int(2 + sqrt(length)) * sizeof(int));
ipa[0] = 0;
wa.resize(length >> 1);
fft1BinToPitch.resize(length >> 1);
for (i = 1, f0 = (float)rate / length; i < (length >> 1); i++) {
fft1BinToPitch[i] = assign_pitch_to_freq(i * f0);
}
}
oldfftsize = length;
/* zero out arrays that need it */
memset(pitchmags, 0, 129 * sizeof(float));
memset(pitchbins, 0, 129 * sizeof(double));
memset(new_pitchbins, 0, 129 * sizeof(double));
memset(&pruneMagData[0], 0, length * sizeof(float));
return(length);
}
/* return the frequency of the sample */
/* max of 1.4 - 2.0 seconds of audio is analyzed, depending on sample rate */
/* samples < 1.4 seconds are padded to max length for higher fft accuracy */
float Freq::freq_fourier(Sample *sp, int *chord)
{
uint32_t length, length0;
int32_t maxoffset, minoffset, minoffset1, minoffset2;
int32_t minbin, maxbin;
int32_t bin;
uint32_t i;
int32_t j, n, total;
unsigned int rate;
int pitch, bestpitch, minpitch, maxpitch, maxpitch2;
sample_t *origdata;
float f0, mag, maxmag;
int16_t amp, oldamp, maxamp;
int32_t maxpos = 0;
double sum, weightsum, maxsum;
double f0_inv;
float freq, newfreq, bestfreq, freq_inc;
float minfreq, maxfreq, minfreq2, maxfreq2;
float min_guessfreq, max_guessfreq;
rate = sp->sample_rate;
length = length0 = sp->data_length >> FRACTION_BITS;
origdata = sp->data;
length = freq_initialize_fft_arrays(sp);
/* base frequency of the FFT */
f0 = (float)rate / length;
f0_inv = 1.0 / f0;
/* get maximum amplitude */
maxamp = -1;
for (uint32_t i = 0; i < length0; i++)
{
amp = abs(origdata[i]);
if (amp >= maxamp)
{
maxamp = amp;
maxpos = i;
}
}
/* go out 2 zero crossings in both directions, starting at maxpos */
/* find the peaks after the 2nd crossing */
minoffset1 = 0;
for (n = 0, oldamp = origdata[maxpos], i = maxpos - 1; i >= 0 && n < 2; i--)
{
amp = origdata[i];
if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) ||
(oldamp < 0 && amp > 0))
n++;
oldamp = amp;
}
minoffset1 = i;
maxamp = labs(origdata[i]);
while (i >= 0)
{
amp = origdata[i];
if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) ||
(oldamp < 0 && amp > 0))
{
break;
}
oldamp = amp;
amp = labs(amp);
if (amp > maxamp)
{
maxamp = amp;
minoffset1 = i;
}
i--;
}
minoffset2 = 0;
for (n = 0, oldamp = origdata[maxpos], i = maxpos + 1; i < length0 && n < 2; i++)
{
amp = origdata[i];
if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) ||
(oldamp < 0 && amp > 0))
n++;
oldamp = amp;
}
minoffset2 = i;
maxamp = labs(origdata[i]);
while (i < length0)
{
amp = origdata[i];
if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) ||
(oldamp < 0 && amp > 0))
{
break;
}
oldamp = amp;
amp = labs(amp);
if (amp > maxamp)
{
maxamp = amp;
minoffset2 = i;
}
i++;
}
/* upper bound on the detected frequency */
/* distance between the two peaks is at most 2 periods */
minoffset = (minoffset2 - minoffset1);
if (minoffset < 4)
minoffset = 4;
max_guessfreq = (float)rate / (minoffset * 0.5);
if (max_guessfreq >= (rate >> 1)) max_guessfreq = (rate >> 1) - 1;
/* lower bound on the detected frequency */
maxoffset = rate / pitch_freq_lb_table[LOWEST_PITCH] + 0.5;
if ((uint32_t)maxoffset > (length >> 1))
maxoffset = (length >> 1);
min_guessfreq = (float)rate / maxoffset;
/* perform the in place FFT */
rdft(length, 1, &floatData[0], &ipa[0], &wa[0]);
/* calc the magnitudes */
for (i = 2; i < length; i++)
{
mag = floatData[i++];
mag *= mag;
mag += floatData[i] * floatData[i];
magData[i >> 1] = sqrt(mag);
}
/* find max mag */
maxmag = 0;
for (i = 1; i < (length >> 1); i++)
{
mag = magData[i];
pitch = fft1BinToPitch[i];
if (pitch && mag > maxmag)
maxmag = mag;
}
/* Apply non-linear scaling to the magnitudes
* I don't know why this improves the pitch detection, but it does
* The best choice of power seems to be between 1.64 - 1.68
*/
for (i = 1; i < (length >> 1); i++)
magData[i] = maxmag * pow(magData[i] / maxmag, 1.66);
/* bin the pitches */
for (i = 1; i < (length >> 1); i++)
{
mag = magData[i];
pitch = fft1BinToPitch[i];
pitchbins[pitch] += mag;
if (mag > pitchmags[pitch])
pitchmags[pitch] = mag;
}
/* zero out lowest pitch, since it contains all lower frequencies too */
pitchbins[LOWEST_PITCH] = 0;
/* find the largest peak */
for (i = LOWEST_PITCH + 1, maxsum = -42; i <= HIGHEST_PITCH; i++)
{
sum = pitchbins[i];
if (sum > maxsum)
{
maxsum = sum;
}
}
minpitch = assign_pitch_to_freq(min_guessfreq);
if (minpitch > HIGHEST_PITCH) minpitch = HIGHEST_PITCH;
/* zero out any peak below minpitch */
for (int i = LOWEST_PITCH + 1; i < minpitch; i++)
pitchbins[i] = 0;
/* remove all pitches below threshold */
for (int i = minpitch; i <= HIGHEST_PITCH; i++)
{
if (pitchbins[i] / maxsum < 0.01 && pitchmags[i] / maxmag < 0.01)
pitchbins[i] = 0;
}
/* keep local maxima */
for (int i = LOWEST_PITCH + 1; i < HIGHEST_PITCH; i++)
{
double temp;
temp = pitchbins[i];
/* also keep significant bands to either side */
if (temp && pitchbins[i - 1] < temp && pitchbins[i + 1] < temp)
{
new_pitchbins[i] = temp;
temp *= 0.5;
if (pitchbins[i - 1] >= temp)
new_pitchbins[i - 1] = pitchbins[i - 1];
if (pitchbins[i + 1] >= temp)
new_pitchbins[i + 1] = pitchbins[i - 1];
}
}
memcpy(pitchbins, new_pitchbins, 129 * sizeof(double));
/* find lowest and highest pitches */
minpitch = LOWEST_PITCH;
while (minpitch < HIGHEST_PITCH && !pitchbins[minpitch])
minpitch++;
maxpitch = HIGHEST_PITCH;
while (maxpitch > LOWEST_PITCH && !pitchbins[maxpitch])
maxpitch--;
/* uh oh, no pitches left...
* best guess is middle C
* return 260 Hz, since exactly 260 Hz is never returned except on error
* this should only occur on blank/silent samples
*/
if (maxpitch < minpitch)
{
return 260.0;
}
/* pitch assignment bounds based on zero crossings and pitches kept */
if (pitch_freq_lb_table[minpitch] > min_guessfreq)
min_guessfreq = pitch_freq_lb_table[minpitch];
if (pitch_freq_ub_table[maxpitch] < max_guessfreq)
max_guessfreq = pitch_freq_ub_table[maxpitch];
minfreq = pitch_freq_lb_table[minpitch];
if (minfreq >= (rate >> 1)) minfreq = (rate >> 1) - 1;
maxfreq = pitch_freq_ub_table[maxpitch];
if (maxfreq >= (rate >> 1)) maxfreq = (rate >> 1) - 1;
minbin = minfreq / f0;
if (!minbin)
minbin = 1;
maxbin = ceil(maxfreq / f0);
if ((uint32_t)maxbin >= (length >> 1))
maxbin = (length >> 1) - 1;
/* filter out all "noise" from magnitude array */
for (int i = minbin, n = 0; i <= maxbin; i++)
{
pitch = fft1BinToPitch[i];
if (pitchbins[pitch])
{
pruneMagData[i] = magData[i];
n++;
}
}
/* whoa!, there aren't any strong peaks at all !!! bomb early
* best guess is middle C
* return 260 Hz, since exactly 260 Hz is never returned except on error
* this should only occur on blank/silent samples
*/
if (!n)
{
return 260.0;
}
memset(new_pitchbins, 0, 129 * sizeof(double));
maxsum = -1;
minpitch = assign_pitch_to_freq(min_guessfreq);
maxpitch = assign_pitch_to_freq(max_guessfreq);
maxpitch2 = assign_pitch_to_freq(max_guessfreq) + 9;
if (maxpitch2 > HIGHEST_PITCH) maxpitch2 = HIGHEST_PITCH;
/* initial guess is first local maximum */
bestfreq = pitch_freq_table[minpitch];
if (minpitch < HIGHEST_PITCH &&
pitchbins[minpitch + 1] > pitchbins[minpitch])
bestfreq = pitch_freq_table[minpitch + 1];
/* find best fundamental */
for (int i = minpitch; i <= maxpitch2; i++)
{
if (!pitchbins[i])
continue;
minfreq2 = pitch_freq_lb_table[i];
maxfreq2 = pitch_freq_ub_table[i];
freq_inc = (maxfreq2 - minfreq2) * 0.1;
if (minfreq2 >= (rate >> 1)) minfreq2 = (rate >> 1) - 1;
if (maxfreq2 >= (rate >> 1)) maxfreq2 = (rate >> 1) - 1;
/* look for harmonics */
for (freq = minfreq2; freq <= maxfreq2; freq += freq_inc)
{
n = total = 0;
sum = weightsum = 0;
for (j = 1; j <= 32 && (newfreq = j * freq) <= maxfreq; j++)
{
pitch = assign_pitch_to_freq(newfreq);
if (pitchbins[pitch])
{
sum += pitchbins[pitch];
n++;
total = j;
}
}
/* only pitches with good harmonics are assignment candidates */
if (n > 1)
{
double ratio;
ratio = (double)n / total;
if (ratio >= 0.333333)
{
weightsum = ratio * sum;
pitch = assign_pitch_to_freq(freq);
/* use only these pitches for chord detection */
if (pitch <= HIGHEST_PITCH && pitchbins[pitch])
new_pitchbins[pitch] = weightsum;
if (pitch > maxpitch)
continue;
if (n < 2 || weightsum > maxsum)
{
maxsum = weightsum;
bestfreq = freq;
}
}
}
}
}
bestpitch = assign_pitch_to_freq(bestfreq);
/* assign chords */
if ((pitch = assign_chord(new_pitchbins, chord,
bestpitch - 9, maxpitch2, bestpitch)) >= 0)
bestpitch = pitch;
bestfreq = pitch_freq_table[bestpitch];
/* tune based on the fundamental and harmonics up to +5 octaves */
sum = weightsum = 0;
for (i = 1; i <= 32 && (freq = i * bestfreq) <= maxfreq; i++)
{
double tune;
minfreq2 = pitch_freq_lb_table[bestpitch];
maxfreq2 = pitch_freq_ub_table[bestpitch];
minbin = minfreq2 * f0_inv;
if (!minbin) minbin = 1;
maxbin = ceil(maxfreq2 * f0_inv);
if ((uint32_t)maxbin >= (length >> 1))
maxbin = (length >> 1) - 1;
for (bin = minbin; bin <= maxbin; bin++)
{
tune = -36.37631656 + 17.31234049 * log(bin*f0) - bestpitch;
sum += magData[bin];
weightsum += magData[bin] * tune;
}
}
bestfreq = 13.75 * exp(((bestpitch + weightsum / sum) - 9) /
12 * log(2));
/* Since we are using exactly 260 Hz as an error code, fudge the freq
* on the extremely unlikely chance that the detected pitch is exactly
* 260 Hz.
*/
if (bestfreq == 260.0f)
bestfreq += 1E-5f;
return bestfreq;
}
int assign_pitch_to_freq(float freq)
{
/* round to nearest integer using: ceil(fraction - 0.5) */
/* -0.5 is already added into the first constant below */
int pitch = ceil(-36.87631656f + 17.31234049f * log(freq));
/* min and max pitches */
if (pitch < LOWEST_PITCH) pitch = LOWEST_PITCH;
else if (pitch > HIGHEST_PITCH) pitch = HIGHEST_PITCH;
return pitch;
}
}

View File

@ -0,0 +1,67 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <vector>
namespace TimidityPlus
{
extern const float pitch_freq_table[129];
extern const float pitch_freq_ub_table[129];
extern const float pitch_freq_lb_table[129];
extern const int chord_table[4][3][3];
extern int assign_pitch_to_freq(float freq);
enum
{
CHORD_MAJOR = 0,
CHORD_MINOR = 3,
CHORD_DIM = 6,
CHORD_FIFTH = 9,
LOWEST_PITCH = 0,
HIGHEST_PITCH = 127
};
struct Sample;
class Freq
{
std::vector<float> floatData;
std::vector<float> magData;
std::vector<float> pruneMagData;
std::vector<int> ipa;
std::vector<float> wa;
std::vector<int> fft1BinToPitch;
uint32_t oldfftsize = 0;
float pitchmags[129] = { 0 };
double pitchbins[129] = { 0 };
double new_pitchbins[129] = { 0 };
int assign_chord(double *pitchbins, int *chord, int min_guesspitch, int max_guesspitch, int root_pitch);
int freq_initialize_fft_arrays(Sample *sp);
public:
float freq_fourier(Sample *sp, int *chord);
};
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,560 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
instrum.h
*/
#ifndef ___INSTRUM_H_
#define ___INSTRUM_H_
#include "common.h"
#include "sysdep.h"
#include "sffile.h"
#include "sflayer.h"
#include "sfitem.h"
namespace TimidityPlus
{
enum
{
READ_CONFIG_SUCCESS = 0,
READ_CONFIG_ERROR = 1,
READ_CONFIG_RECURSION = 2, /* Too much recursion */
READ_CONFIG_FILE_NOT_FOUND = 3, /* Returned only w. allow_missing_file */
};
struct Sample
{
splen_t
loop_start, loop_end, data_length;
int32_t
sample_rate, low_freq, high_freq, root_freq;
int8_t panning, note_to_use;
int32_t
envelope_rate[6], envelope_offset[6],
modenv_rate[6], modenv_offset[6];
double
volume;
sample_t
*data;
int32_t
tremolo_sweep_increment, tremolo_phase_increment,
vibrato_sweep_increment, vibrato_control_ratio;
int16_t
tremolo_depth;
int16_t vibrato_depth;
uint8_t
modes, data_alloced,
low_vel, high_vel;
int32_t cutoff_freq; /* in Hz, [1, 20000] */
int16_t resonance; /* in centibels, [0, 960] */
/* in cents, [-12000, 12000] */
int16_t tremolo_to_pitch, tremolo_to_fc, modenv_to_pitch, modenv_to_fc,
envelope_keyf[6], envelope_velf[6], modenv_keyf[6], modenv_velf[6],
vel_to_fc, key_to_fc;
int16_t vel_to_resonance; /* in centibels, [-960, 960] */
int8_t envelope_velf_bpo, modenv_velf_bpo,
key_to_fc_bpo, vel_to_fc_threshold; /* in notes */
int32_t vibrato_delay, tremolo_delay, envelope_delay, modenv_delay; /* in samples */
int16_t scale_freq; /* in notes */
int16_t scale_factor; /* in 1024divs/key */
int8_t inst_type;
int32_t sf_sample_index, sf_sample_link; /* for stereo SoundFont */
uint16_t sample_type; /* 1 = Mono, 2 = Right, 4 = Left, 8 = Linked, $8000 = ROM */
double root_freq_detected; /* root freq from pitch detection */
int transpose_detected; /* note offset from detected root */
int chord; /* type of chord for detected pitch */
};
/* Bits in modes: */
enum
{
MODES_16BIT = (1 << 0),
MODES_UNSIGNED = (1 << 1),
MODES_LOOPING = (1 << 2),
MODES_PINGPONG = (1 << 3),
MODES_REVERSE = (1 << 4),
MODES_SUSTAIN = (1 << 5),
MODES_ENVELOPE = (1 << 6),
MODES_CLAMPED = (1 << 7), /* ?? (for last envelope??) */
INST_GUS = 0,
INST_SF2 = 1,
INST_MOD = 2,
INST_PCM = 3, /* %sample */
/* sfSampleType */
SF_SAMPLETYPE_MONO = 1,
SF_SAMPLETYPE_RIGHT = 2,
SF_SAMPLETYPE_LEFT = 4,
SF_SAMPLETYPE_LINKED = 8,
SF_SAMPLETYPE_ROM = 0x8000,
};
struct Instrument
{
int type;
int samples;
Sample *sample;
char *instname;
};
struct ToneBankElement
{
char *name;
char *comment;
Instrument *instrument;
int8_t note, pan, strip_loop, strip_envelope, strip_tail, loop_timeout,
font_preset, font_keynote, legato, tva_level, play_note, damper_mode;
uint8_t font_bank;
uint8_t instype; /* 0: Normal
1: %font
2: %sample
3-255: reserved
*/
int16_t amp;
int16_t rnddelay;
int tunenum;
float *tune;
int sclnotenum;
int16_t *sclnote;
int scltunenum;
int16_t *scltune;
int fcnum;
int16_t *fc;
int resonum;
int16_t *reso;
int trempitchnum, tremfcnum, modpitchnum, modfcnum;
int16_t *trempitch, *tremfc, *modpitch, *modfc;
int envratenum, envofsnum;
int **envrate, **envofs;
int modenvratenum, modenvofsnum;
int **modenvrate, **modenvofs;
int envvelfnum, envkeyfnum;
int **envvelf, **envkeyf;
int modenvvelfnum, modenvkeyfnum;
int **modenvvelf, **modenvkeyf;
int tremnum, vibnum;
struct Quantity_ **trem, **vib;
int16_t vel_to_fc, key_to_fc, vel_to_resonance;
int8_t reverb_send, chorus_send, delay_send;
};
/* A hack to delay instrument loading until after reading the
entire MIDI file. */
#define MAGIC_LOAD_INSTRUMENT ((Instrument *)(-1))
#define MAGIC_ERROR_INSTRUMENT ((Instrument *)(-2))
#define IS_MAGIC_INSTRUMENT(ip) ((ip) == MAGIC_LOAD_INSTRUMENT || (ip) == MAGIC_ERROR_INSTRUMENT)
#define DYNAMIC_INSTRUMENT_NAME ""
struct AlternateAssign
{
/* 128 bit vector:
* bits[(note >> 5) & 0x3] & (1 << (note & 0x1F))
*/
uint32_t bits[4];
AlternateAssign* next;
};
struct ToneBank
{
ToneBankElement tone[128];
AlternateAssign *alt;
};
struct SpecialPatch /* To be used MIDI Module play mode */
{
int type;
int samples;
Sample *sample;
char *name;
int32_t sample_offset;
};
enum instrument_mapID
{
INST_NO_MAP = 0,
SC_55_TONE_MAP,
SC_55_DRUM_MAP,
SC_88_TONE_MAP,
SC_88_DRUM_MAP,
SC_88PRO_TONE_MAP,
SC_88PRO_DRUM_MAP,
SC_8850_TONE_MAP,
SC_8850_DRUM_MAP,
XG_NORMAL_MAP,
XG_SFX64_MAP,
XG_SFX126_MAP,
XG_DRUM_MAP,
GM2_TONE_MAP,
GM2_DRUM_MAP,
NUM_INST_MAP
};
enum
{
MAP_BANK_COUNT = 256,
NSPECIAL_PATCH = 256,
SPECIAL_PROGRAM = -1,
MAX_MREL = 5000,
DEFAULT_MREL = 800,
};
struct SFInsts;
struct InstList;
struct SampleList;
struct AIFFCommonChunk;
struct AIFFSoundDataChunk;
struct SampleImporter;
class Instruments
{
PathList pathlist;
ToneBank standard_tonebank, standard_drumset;
enum
{
INSTRUMENT_HASH_SIZE = 128,
};
struct InstrumentCache
{
char *name;
int panning, amp, note_to_use, strip_loop, strip_envelope, strip_tail;
Instrument *ip;
InstrumentCache *next;
};
InstrumentCache *instrument_cache[INSTRUMENT_HASH_SIZE] = { nullptr };
/* bank mapping (mapped bank) */
struct bank_map_elem
{
int16_t used = 0, mapid = 0;
int bankno = 0;
};
bank_map_elem map_bank[MAP_BANK_COUNT], map_drumset[MAP_BANK_COUNT];
int map_bank_counter = 0;
struct inst_map_elem
{
int set, elem, mapped;
};
inst_map_elem *inst_map_table[NUM_INST_MAP][128] = { { nullptr} };
struct UserInstrument
{
int8_t bank;
int8_t prog;
int8_t source_map;
int8_t source_bank;
int8_t source_prog;
int8_t vibrato_rate;
int8_t vibrato_depth;
int8_t cutoff_freq;
int8_t resonance;
int8_t env_attack;
int8_t env_decay;
int8_t env_release;
int8_t vibrato_delay;
UserInstrument *next;
};
UserInstrument *userinst_first = (UserInstrument *)NULL;
UserInstrument *userinst_last = (UserInstrument *)NULL;
struct UserDrumset {
int8_t bank;
int8_t prog;
int8_t play_note;
int8_t level;
int8_t assign_group;
int8_t pan;
int8_t reverb_send_level;
int8_t chorus_send_level;
int8_t rx_note_off;
int8_t rx_note_on;
int8_t delay_send_level;
int8_t source_map;
int8_t source_prog;
int8_t source_note;
UserDrumset *next;
};
struct SFBags
{
int nbags;
uint16_t *bag;
int ngens;
SFGenRec *gen;
};
SFBags prbags, inbags;
UserDrumset *userdrum_first = (UserDrumset *)NULL;
UserDrumset *userdrum_last = (UserDrumset *)NULL;
/* Some functions get aggravated if not even the standard banks are available. */
ToneBank
*tonebank[128 + MAP_BANK_COUNT] = { &standard_tonebank },
*drumset[128 + MAP_BANK_COUNT] = { &standard_drumset };
Instrument *default_instrument = 0;
SpecialPatch *special_patch[NSPECIAL_PATCH] = { nullptr };
int default_program[MAX_CHANNELS] = { 0 }; /* This is only used for tracks that don't specify a program */
char *default_instrument_name = nullptr;
int progbase = 0;
int32_t modify_release = 0;
bool opt_sf_close_each_file = true;
char def_instr_name[256] = "";
SFInsts *sfrecs = nullptr;
SFInsts *current_sfrec = nullptr;
int last_sample_type = 0;
int last_sample_instrument = 0;
int last_sample_keyrange = 0;
SampleList *last_sample_list = nullptr;
LayerItem layer_items[SF_EOF];
/* convert from 8bit value to fractional offset (15.15) */
int32_t to_offset_22(int offset)
{
return (int32_t)offset << (7 + 15);
}
int32_t calc_rate_i(int diff, double msec);
int32_t convert_envelope_rate(uint8_t rate);
int32_t convert_envelope_offset(uint8_t offset);
int32_t convert_tremolo_sweep(uint8_t sweep);
int32_t convert_vibrato_sweep(uint8_t sweep, int32_t vib_control_ratio);
int32_t convert_tremolo_rate(uint8_t rate);
int32_t convert_vibrato_rate(uint8_t rate);
void reverse_data(int16_t *sp, int32_t ls, int32_t le);
int name_hash(char *name);
Instrument *search_instrument_cache(char *name, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail);
void store_instrument_cache(Instrument *ip, char *name, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail);
int32_t to_rate(int rate);
void apply_bank_parameter(Instrument *ip, ToneBankElement *tone);
Instrument *load_gus_instrument(char *name, ToneBank *bank, int dr, int prog);
int fill_bank(int dr, int b, int *rc);
void free_tone_bank_list(ToneBank *tb[]);
void free_tone_bank(void);
void free_instrument_map(void);
int set_default_instrument(char *name);
void *safe_memdup(void *s, size_t size);
void MarkInstrument(int banknum, int percussion, int instr);
//smplfile.c
Instrument *extract_sample_file(char *);
int32_t convert_envelope_rate_s(uint8_t rate);
void initialize_sample(Instrument *inst, int frames, int sample_bits, int sample_rate);
int get_importers(const char *sample_file, int limit, SampleImporter **importers);
int get_next_importer(char *sample_file, int start, int count, SampleImporter **importers);
int import_wave_discriminant(char *sample_file);
int import_wave_load(char *sample_file, Instrument *inst);
int import_aiff_discriminant(char *sample_file);
int import_aiff_load(char *sample_file, Instrument *inst);
int read_AIFFCommonChunk(struct timidity_file *tf, AIFFCommonChunk *comm, int csize, int compressed);
int read_AIFFSoundData(struct timidity_file *tf, Instrument *inst, AIFFCommonChunk *common);
int read_AIFFSoundDataChunk(struct timidity_file *tf, AIFFSoundDataChunk *sound, int csize, int mode);
// sndfont.cpp
SFInsts *find_soundfont(char *sf_file);
SFInsts *new_soundfont(char *sf_file);
void init_sf(SFInsts *rec);
void end_soundfont(SFInsts *rec);
Instrument *try_load_soundfont(SFInsts *rec, int order, int bank, int preset, int keynote);
Instrument *load_from_file(SFInsts *rec, InstList *ip);
int is_excluded(SFInsts *rec, int bank, int preset, int keynote);
int is_ordered(SFInsts *rec, int bank, int preset, int keynote);
int load_font(SFInfo *sf, int pridx);
int parse_layer(SFInfo *sf, int pridx, LayerTable *tbl, int level);
int is_global(SFGenLayer *layer);
void clear_table(LayerTable *tbl);
void set_to_table(SFInfo *sf, LayerTable *tbl, SFGenLayer *lay, int level);
void add_item_to_table(LayerTable *tbl, int oper, int amount, int level);
void merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src);
void init_and_merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src);
int sanity_range(LayerTable *tbl);
int make_patch(SFInfo *sf, int pridx, LayerTable *tbl);
void make_info(SFInfo *sf, SampleList *vp, LayerTable *tbl);
double calc_volume(LayerTable *tbl);
void set_sample_info(SFInfo *sf, SampleList *vp, LayerTable *tbl);
void set_init_info(SFInfo *sf, SampleList *vp, LayerTable *tbl);
void reset_last_sample_info(void);
int abscent_to_Hz(int abscents);
void set_rootkey(SFInfo *sf, SampleList *vp, LayerTable *tbl);
void set_rootfreq(SampleList *vp);
int32_t to_offset(int32_t offset);
int32_t to_rate(int32_t diff, int timecent);
int32_t calc_rate(int32_t diff, double msec);
double to_msec(int timecent);
int32_t calc_sustain(int sust_cB);
void convert_volume_envelope(SampleList *vp, LayerTable *tbl);
void convert_tremolo(SampleList *vp, LayerTable *tbl);
void convert_vibrato(SampleList *vp, LayerTable *tbl);
void set_envelope_parameters(SampleList *vp);
// configfile
int set_patchconf(const char *name, int line, ToneBank *bank, char *w[], int dr, int mapid, int bankmapfrom, int bankno);
int strip_trailing_comment(char *string, int next_token_index);
char *expand_variables(char *string, MBlockList *varbuf, const char *basedir);
int set_gus_patchconf(const char *name, int line, ToneBankElement *tone, char *pat, char **opts);
void reinit_tone_bank_element(ToneBankElement *tone);
int set_gus_patchconf_opts(const char *name, int line, char *opts, ToneBankElement *tone);
int copymap(int mapto, int mapfrom, int isdrum);
void copybank(ToneBank *to, ToneBank *from, int mapid, int bankmapfrom, int bankno);
// sffile.cpp
int chunkid(char *id);
int process_list(int size, SFInfo *sf, struct timidity_file *fd);
int process_info(int size, SFInfo *sf, struct timidity_file *fd);
int process_sdta(int size, SFInfo *sf, struct timidity_file *fd);
int process_pdta(int size, SFInfo *sf, struct timidity_file *fd);
void load_sample_names(int size, SFInfo *sf, struct timidity_file *fd);
void load_preset_header(int size, SFInfo *sf, struct timidity_file *fd);
void load_inst_header(int size, SFInfo *sf, struct timidity_file *fd);
void load_bag(int size, SFBags *bagp, struct timidity_file *fd);
void load_gen(int size, SFBags *bagp, struct timidity_file *fd);
void load_sample_info(int size, SFInfo *sf, struct timidity_file *fd);
void convert_layers(SFInfo *sf);
void generate_layers(SFHeader *hdr, SFHeader *next, SFBags *bags);
void free_layer(SFHeader *hdr);
int load_soundfont(SFInfo *sf, struct timidity_file *fd);
void free_soundfont(SFInfo *sf);
void correct_samples(SFInfo *sf);
public:
Instruments();
bool load(const char *config);
~Instruments();
const ToneBank *toneBank(int i) const
{
return tonebank[i];
}
int defaultProgram(int i) const
{
return default_program[i];
}
const ToneBank *drumSet(int i) const
{
return drumset[i];
}
const SpecialPatch *specialPatch(int i) const
{
return special_patch[i];
}
void setSpecialPatchOffset(int i, int32_t ofs)
{
special_patch[i]->sample_offset = ofs;
}
Instrument *defaultInstrument() const
{
return default_instrument;
}
/* instrum.c */
int load_missing_instruments(int *rc);
void free_instruments(int reload_default_inst);
void free_special_patch(int id);
void clear_magic_instruments(void);
Instrument *load_instrument(int dr, int b, int prog);
int find_instrument_map_bank(int dr, int map, int bk);
int alloc_instrument_map_bank(int dr, int map, int bk);
void alloc_instrument_bank(int dr, int bankset);
int instrument_map(int mapID, int *set_in_out, int *elem_in_out) const;
void set_instrument_map(int mapID, int set_from, int elem_from, int set_to, int elem_to);
AlternateAssign *add_altassign_string(AlternateAssign *old, char **params, int n);
AlternateAssign *find_altassign(AlternateAssign *altassign, int note);
void copy_tone_bank_element(ToneBankElement *elm, const ToneBankElement *src);
void free_tone_bank_element(ToneBankElement *elm);
void free_instrument(Instrument *ip);
void squash_sample_16to8(Sample *sp);
Instrument *play_midi_load_instrument(int dr, int bk, int prog, bool *pLoad_success);
void recompute_userinst(int bank, int prog);
Instrument *recompute_userdrum(int bank, int prog);
UserInstrument *get_userinst(int bank, int prog);
UserDrumset *get_userdrum(int bank, int prog);
void recompute_userdrum_altassign(int bank, int group);
/*! initialize GS user drumset. */
void init_userdrum();
void free_userdrum();
void init_userinst() { free_userinst(); }
void free_userinst();
void mark_instrument(int newbank, int newprog)
{
if (!(tonebank[newbank]->tone[newprog].instrument))
tonebank[newbank]->tone[newprog].instrument =
MAGIC_LOAD_INSTRUMENT;
}
void mark_drumset(int newbank, int newprog)
{
if (!(drumset[newbank]->tone[newprog].instrument))
drumset[newbank]->tone[newprog].instrument =
MAGIC_LOAD_INSTRUMENT;
}
/* sndfont.c */
void add_soundfont(char *sf_file, int sf_order, int cutoff_allowed, int resonance_allowed, int amp);
void remove_soundfont(char *sf_file);
void init_load_soundfont(void);
Instrument *load_soundfont_inst(int order, int bank, int preset, int keynote);
Instrument *extract_soundfont(char *sf_file, int bank, int preset, int keynote);
int exclude_soundfont(int bank, int preset, int keynote);
int order_soundfont(int bank, int preset, int keynote, int order);
char *soundfont_preset_name(int bank, int preset, int keynote, char **sndfile);
void free_soundfonts(void);
void PrecacheInstruments(const uint16_t *instruments, int count);
int read_config_file(const char *name, int self, int allow_missing_file);
void set_default_instrument()
{
if (def_instr_name) set_default_instrument(def_instr_name);
}
};
}
#endif /* ___INSTRUM_H_ */

View File

@ -0,0 +1,169 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "timidity.h"
#include "common.h"
namespace TimidityPlus
{
static MBlockNode *free_mblock_list = NULL;
#define ADDRALIGN 8
/* #define DEBUG */
void init_mblock(MBlockList *mblock)
{
mblock->first = NULL;
mblock->allocated = 0;
}
static MBlockNode *new_mblock_node(size_t n)
{
MBlockNode *p;
if (n > MIN_MBLOCK_SIZE)
{
if ((p = (MBlockNode *)safe_malloc(n + sizeof(MBlockNode))) == NULL)
return NULL;
p->block_size = n;
}
else if (free_mblock_list == NULL)
{
if ((p = (MBlockNode *)safe_malloc(sizeof(MBlockNode) + MIN_MBLOCK_SIZE)) == NULL)
return NULL;
p->block_size = MIN_MBLOCK_SIZE;
}
else
{
p = free_mblock_list;
free_mblock_list = free_mblock_list->next;
}
p->offset = 0;
p->next = NULL;
return p;
}
static int enough_block_memory(MBlockList *mblock, size_t n)
{
size_t newoffset;
if(mblock->first == NULL)
return 0;
newoffset = mblock->first->offset + n;
if(newoffset < mblock->first->offset) /* exceed representable in size_t */
return 0;
if(newoffset > mblock->first->block_size)
return 0;
return 1;
}
void *new_segment(MBlockList *mblock, size_t nbytes)
{
MBlockNode *p;
void *addr;
/* round up to ADDRALIGN */
nbytes = ((nbytes + ADDRALIGN - 1) & ~(ADDRALIGN - 1));
if (!enough_block_memory(mblock, nbytes))
{
p = new_mblock_node(nbytes);
p->next = mblock->first;
mblock->first = p;
mblock->allocated += p->block_size;
}
else
p = mblock->first;
addr = (void *)(p->buffer + p->offset);
p->offset += nbytes;
return addr;
}
static void reuse_mblock1(MBlockNode *p)
{
if (p->block_size > MIN_MBLOCK_SIZE)
free(p);
else /* p->block_size <= MIN_MBLOCK_SIZE */
{
p->next = free_mblock_list;
free_mblock_list = p;
}
}
void reuse_mblock(MBlockList *mblock)
{
MBlockNode *p;
if ((p = mblock->first) == NULL)
return; /* There is nothing to collect memory */
while (p)
{
MBlockNode *tmp;
tmp = p;
p = p->next;
reuse_mblock1(tmp);
}
init_mblock(mblock);
}
char *strdup_mblock(MBlockList *mblock, const char *str)
{
int len;
char *p;
len = (int)strlen(str);
p = (char *)new_segment(mblock, len + 1); /* for '\0' */
memcpy(p, str, len + 1);
return p;
}
int free_global_mblock(void)
{
int cnt;
cnt = 0;
while (free_mblock_list)
{
MBlockNode *tmp;
tmp = free_mblock_list;
free_mblock_list = free_mblock_list->next;
free(tmp);
cnt++;
}
return cnt;
}
}

View File

@ -0,0 +1,78 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ___MBLOCK_H_
#define ___MBLOCK_H_
namespace TimidityPlus
{
struct MBlockNode;
/* Memory block for decreasing malloc
*
* +------+ +------+ +-------+
* |BLOCK1|--->|BLOCK2|---> ... --->|BLOCK N|---> NULL
* +------+ +------+ +-------+
*
*
* BLOCK:
* +-----------------------+
* | memory 1 |
* | |
* +-----------------------+
* | memory 2 |
* +-----------------------+
* | memory 3 |
* | |
* | |
* +-----------------------+
* | unused ... |
* +-----------------------+
*/
#define MIN_MBLOCK_SIZE 8192
struct MBlockNode
{
size_t block_size;
size_t offset;
MBlockNode *next;
#ifndef MBLOCK_NOPAD
void *pad;
#endif /* MBLOCK_NOPAD */
char buffer[1];
};
struct MBlockList
{
MBlockNode *first;
size_t allocated;
};
extern void init_mblock(MBlockList *mblock);
extern void *new_segment(MBlockList *mblock, size_t nbytes);
extern void reuse_mblock(MBlockList *mblock);
extern char *strdup_mblock(MBlockList *mblock, const char *str);
extern int free_global_mblock(void);
}
#endif /* ___MBLOCK_H_ */

1632
src/sound/timidity++/mix.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,76 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
In case you haven't heard, this program is free software;
you can redistribute it and/or modify it under the terms of the
GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
mix.h
*/
#ifndef ___MIX_H_
#define ___MIX_H_
#include "resample.h"
namespace TimidityPlus
{
typedef int32_t mix_t;
class Player;
class Mixer
{
Player *player;
int32_t filter_buffer[AUDIO_BUFFER_SIZE];
int do_voice_filter(int, resample_t*, mix_t*, int32_t);
void recalc_voice_resonance(int);
void recalc_voice_fc(int);
void ramp_out(mix_t *, int32_t *, int, int32_t);
void mix_mono_signal(mix_t *, int32_t *, int, int);
void mix_mystery_signal(mix_t *, int32_t *, int, int);
void mix_mystery(mix_t *, int32_t *, int, int);
void mix_center_signal(mix_t *, int32_t *, int, int);
void mix_center(mix_t *, int32_t *, int, int);
void mix_single_signal(mix_t *, int32_t *, int, int);
void mix_single(mix_t *, int32_t *, int, int);
int update_signal(int);
int update_envelope(int);
int update_modulation_envelope(int);
void voice_ran_out(int);
int next_stage(int);
int modenv_next_stage(int);
void update_tremolo(int);
void compute_mix_smoothing(Voice *);
int get_eg_stage(int v, int stage);
public:
Mixer(Player *p)
{
player = p;
}
void mix_voice(int32_t *, int, int32_t);
int recompute_envelope(int);
int apply_envelope_to_amp(int);
int recompute_modulation_envelope(int);
int apply_modulation_envelope(int);
};
}
#endif /* ___MIX_H_ */

View File

@ -0,0 +1,65 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef OPTCODE_H_INCLUDED
#define OPTCODE_H_INCLUDED 1
#include <stdint.h>
namespace TimidityPlus
{
/*****************************************************************************/
/*****************************************************************************/
/* Generic version of imuldiv. */
inline int32_t imuldiv8(int32_t a, int32_t b)
{
return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 8);
}
inline int32_t imuldiv16(int32_t a, int32_t b)
{
return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 16);
}
inline int32_t imuldiv24(int32_t a, int32_t b)
{
return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 24);
}
inline int32_t imuldiv28(int32_t a, int32_t b)
{
return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 28);
}
static inline int32_t signlong(int32_t a)
{
return ((a | 0x7fffffff) >> 30);
}
}
/*****************************************************************************/
#endif /* OPTCODE_H_INCLUDED */

View File

@ -0,0 +1,92 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
output.c
Audio output (to file / device) functions.
*/
#include "timidity.h"
#include "common.h"
#include "sysdep.h"
#include "tables.h"
namespace TimidityPlus
{
int audio_buffer_bits = DEFAULT_AUDIO_BUFFER_BITS;
extern PlayMode w32_play_mode;
#define DEV_PLAY_MODE &w32_play_mode
extern PlayMode raw_play_mode;
PlayMode *play_mode = DEV_PLAY_MODE;
/*****************************************************************/
/* Some functions to convert signed 32-bit data to other formats */
void s32tos16(int32_t *lp, int32_t c)
{
int16_t *sp=(int16_t *)(lp);
int32_t l, i;
for(i = 0; i < c; i++)
{
l=(lp[i])>>(32-16-GUARD_BITS);
if (l > 32767) l=32767;
else if (l<-32768) l=-32768;
sp[i] = (int16_t)(l);
}
}
// This only gets used as intermediate so we do not care about byte order
#define STORE_S24(cp, l) *cp++ = l & 0xFF, *cp++ = l >> 8 & 0xFF, *cp++ = l >> 16
#define MAX_24BIT_SIGNED (8388607)
#define MIN_24BIT_SIGNED (-8388608)
void s32tos24(int32_t *lp, int32_t c)
{
uint8_t *cp = (uint8_t *)(lp);
int32_t l, i;
for(i = 0; i < c; i++)
{
l = (lp[i]) >> (32 - 24 - GUARD_BITS);
l = (l > MAX_24BIT_SIGNED) ? MAX_24BIT_SIGNED
: (l < MIN_24BIT_SIGNED) ? MIN_24BIT_SIGNED : l;
STORE_S24(cp, l);
}
}
/* return: number of bytes */
int32_t general_output_convert(int32_t *buf, int32_t count)
{
int32_t bytes;
count *= 2; /* Stereo samples */
bytes = count;
bytes *= 2;
s32tos16(buf, count);
return bytes;
}
}

View File

@ -0,0 +1,94 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
output.h
*/
#ifndef ___OUTPUT_H_
#define ___OUTPUT_H_
namespace TimidityPlus
{
/* Data format encoding bits */
#define PE_16BIT (1u<<2) /* versus 8-bit */
#define PE_24BIT (1u<<6) /* versus 8-bit, 16-bit */
/* for play_mode->acntl() */
enum {
PM_REQ_DISCARD, /* ARG: not-used
* Discard the audio device buffer and returns
* immediatly.
*/
PM_REQ_FLUSH, /* ARG: not-used
* Wait until all audio data is out.
*/
};
/* Flag bits */
#define PF_PCM_STREAM (1u<<0) /* Enable output PCM data */
#define PF_BUFF_FRAGM_OPT (1u<<3) /* Enable set extra_param[0] to specify
the number of audio buffer fragments */
#define PF_AUTO_SPLIT_FILE (1u<<4) /* Split PCM files automatically */
#define PF_FILE_OUTPUT (1u<<5) /* Output is to file rather than device */
struct PlayMode {
int32_t rate, encoding, flag;
int fd; /* file descriptor for the audio device
-1 means closed otherwise opened. It must be -1 by default. */
int32_t extra_param[5]; /* System depended parameters
e.g. buffer fragments, ... */
const char *id_name;
char id_character;
const char *name; /* default device or file name */
int (* open_output)(void); /* 0=success, 1=warning, -1=fatal error */
void (* close_output)(void);
int (* output_data)(char *buf, int32_t bytes);
/* return: -1=error, otherwise success */
int (* acntl)(int request, void *arg); /* see PM_REQ_* above
* return: 0=success, -1=fail
*/
int (* detect)(void); /* 0=not available, 1=available */
};
extern PlayMode *play_mode_list[], *play_mode;
extern int audio_buffer_bits;
#define audio_buffer_size (1<<audio_buffer_bits)
/* 16-bit */
extern void s32tos16(int32_t *lp, int32_t c);
/* 24-bit */
extern void s32tos24(int32_t *lp, int32_t c);
extern int32_t general_output_convert(int32_t *buf, int32_t count);
}
#endif /* ___OUTPUT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,759 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
playmidi.h
*/
#ifndef ___PLAYMIDI_H_
#define ___PLAYMIDI_H_
#include <stdint.h>
namespace TimidityPlus
{
struct AlternateAssign;
struct MidiEvent
{
int32_t time;
uint8_t type, channel, a, b;
};
#define REDUCE_CHANNELS 16
#define REVERB_MAX_DELAY_OUT (4 * playback_rate)
#define SYSEX_TAG 0xFF
/* Midi events */
enum midi_event_t
{
ME_NONE,
/* MIDI events */
ME_NOTEOFF,
ME_NOTEON,
ME_KEYPRESSURE,
ME_PROGRAM,
ME_CHANNEL_PRESSURE,
ME_PITCHWHEEL,
/* Controls */
ME_TONE_BANK_MSB,
ME_TONE_BANK_LSB,
ME_MODULATION_WHEEL,
ME_BREATH,
ME_FOOT,
ME_MAINVOLUME,
ME_BALANCE,
ME_PAN,
ME_EXPRESSION,
ME_SUSTAIN,
ME_PORTAMENTO_TIME_MSB,
ME_PORTAMENTO_TIME_LSB,
ME_PORTAMENTO,
ME_PORTAMENTO_CONTROL,
ME_DATA_ENTRY_MSB,
ME_DATA_ENTRY_LSB,
ME_SOSTENUTO,
ME_SOFT_PEDAL,
ME_LEGATO_FOOTSWITCH,
ME_HOLD2,
ME_HARMONIC_CONTENT,
ME_RELEASE_TIME,
ME_ATTACK_TIME,
ME_BRIGHTNESS,
ME_REVERB_EFFECT,
ME_TREMOLO_EFFECT,
ME_CHORUS_EFFECT,
ME_CELESTE_EFFECT,
ME_PHASER_EFFECT,
ME_RPN_INC,
ME_RPN_DEC,
ME_NRPN_LSB,
ME_NRPN_MSB,
ME_RPN_LSB,
ME_RPN_MSB,
ME_ALL_SOUNDS_OFF,
ME_RESET_CONTROLLERS,
ME_ALL_NOTES_OFF,
ME_MONO,
ME_POLY,
/* TiMidity Extensionals */
ME_MASTER_TUNING, /* Master tuning */
ME_SCALE_TUNING, /* Scale tuning */
ME_BULK_TUNING_DUMP, /* Bulk tuning dump */
ME_SINGLE_NOTE_TUNING, /* Single-note tuning */
ME_RANDOM_PAN,
ME_SET_PATCH, /* Install special instrument */
ME_DRUMPART,
ME_KEYSHIFT,
ME_PATCH_OFFS, /* Change special instrument sample position
* Channel, LSB, MSB
*/
/* Global channel events */
ME_TEMPO,
ME_CHORUS_TEXT,
ME_LYRIC,
ME_GSLCD, /* GS L.C.D. Exclusive message event */
ME_MARKER,
ME_INSERT_TEXT, /* for SC */
ME_TEXT,
ME_KARAOKE_LYRIC, /* for KAR format */
ME_MASTER_VOLUME,
ME_RESET, /* Reset and change system mode */
ME_NOTE_STEP,
ME_TIMESIG, /* Time signature */
ME_KEYSIG, /* Key signature */
ME_TEMPER_KEYSIG, /* Temperament key signature */
ME_TEMPER_TYPE, /* Temperament type */
ME_MASTER_TEMPER_TYPE, /* Master temperament type */
ME_USER_TEMPER_ENTRY, /* User-defined temperament entry */
ME_SYSEX_LSB, /* Universal system exclusive message (LSB) */
ME_SYSEX_MSB, /* Universal system exclusive message (MSB) */
ME_SYSEX_GS_LSB, /* GS system exclusive message (LSB) */
ME_SYSEX_GS_MSB, /* GS system exclusive message (MSB) */
ME_SYSEX_XG_LSB, /* XG system exclusive message (LSB) */
ME_SYSEX_XG_MSB, /* XG system exclusive message (MSB) */
ME_WRD, /* for MIMPI WRD tracer */
ME_SHERRY, /* for Sherry WRD tracer */
ME_BARMARKER,
ME_STEP, /* for Metronome */
ME_LAST = 254, /* Last sequence of MIDI list.
* This event is reserved for realtime player.
*/
ME_EOT = 255 /* End of MIDI. Finish to play */
};
#define GLOBAL_CHANNEL_EVENT_TYPE(type) \
((type) == ME_NONE || (type) >= ME_TEMPO)
enum rpn_data_address_t /* NRPN/RPN */
{
NRPN_ADDR_0108,
NRPN_ADDR_0109,
NRPN_ADDR_010A,
NRPN_ADDR_0120,
NRPN_ADDR_0121,
NRPN_ADDR_0130,
NRPN_ADDR_0131,
NRPN_ADDR_0134,
NRPN_ADDR_0135,
NRPN_ADDR_0163,
NRPN_ADDR_0164,
NRPN_ADDR_0166,
NRPN_ADDR_1400,
NRPN_ADDR_1500,
NRPN_ADDR_1600,
NRPN_ADDR_1700,
NRPN_ADDR_1800,
NRPN_ADDR_1900,
NRPN_ADDR_1A00,
NRPN_ADDR_1C00,
NRPN_ADDR_1D00,
NRPN_ADDR_1E00,
NRPN_ADDR_1F00,
NRPN_ADDR_3000,
NRPN_ADDR_3100,
NRPN_ADDR_3400,
NRPN_ADDR_3500,
RPN_ADDR_0000,
RPN_ADDR_0001,
RPN_ADDR_0002,
RPN_ADDR_0003,
RPN_ADDR_0004,
RPN_ADDR_0005,
RPN_ADDR_7F7F,
RPN_ADDR_FFFF,
RPN_MAX_DATA_ADDR
};
#define RX_PITCH_BEND (1<<0)
#define RX_CH_PRESSURE (1<<1)
#define RX_PROGRAM_CHANGE (1<<2)
#define RX_CONTROL_CHANGE (1<<3)
#define RX_POLY_PRESSURE (1<<4)
#define RX_NOTE_MESSAGE (1<<5)
#define RX_RPN (1<<6)
#define RX_NRPN (1<<7)
#define RX_MODULATION (1<<8)
#define RX_VOLUME (1<<9)
#define RX_PANPOT (1<<10)
#define RX_EXPRESSION (1<<11)
#define RX_HOLD1 (1<<12)
#define RX_PORTAMENTO (1<<13)
#define RX_SOSTENUTO (1<<14)
#define RX_SOFT (1<<15)
#define RX_NOTE_ON (1<<16)
#define RX_NOTE_OFF (1<<17)
#define RX_BANK_SELECT (1<<18)
#define RX_BANK_SELECT_LSB (1<<19)
enum {
EG_ATTACK = 0,
EG_DECAY = 2,
EG_DECAY1 = 1,
EG_DECAY2 = 2,
EG_RELEASE = 3,
EG_NULL = 5,
EG_GUS_ATTACK = 0,
EG_GUS_DECAY = 1,
EG_GUS_SUSTAIN = 2,
EG_GUS_RELEASE1 = 3,
EG_GUS_RELEASE2 = 4,
EG_GUS_RELEASE3 = 5,
EG_SF_ATTACK = 0,
EG_SF_HOLD = 1,
EG_SF_DECAY = 2,
EG_SF_RELEASE = 3,
};
#ifndef PART_EQ_XG
#define PART_EQ_XG
/*! shelving filter */
struct filter_shelving
{
double freq, gain, q;
int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r;
int32_t a1, a2, b0, b1, b2;
};
/*! Part EQ (XG) */
struct part_eq_xg {
int8_t bass, treble, bass_freq, treble_freq;
filter_shelving basss, trebles;
int8_t valid;
};
#endif /* PART_EQ_XG */
struct midi_controller
{
int16_t val;
int8_t pitch; /* in +-semitones [-24, 24] */
int16_t cutoff; /* in +-cents [-9600, 9600] */
float amp; /* [-1.0, 1.0] */
/* in GS, LFO1 means LFO for voice 1, LFO2 means LFO for voice2.
LFO2 is not supported. */
float lfo1_rate, lfo2_rate; /* in +-Hz [-10.0, 10.0] */
int16_t lfo1_pitch_depth, lfo2_pitch_depth; /* in cents [0, 600] */
int16_t lfo1_tvf_depth, lfo2_tvf_depth; /* in cents [0, 2400] */
float lfo1_tva_depth, lfo2_tva_depth; /* [0, 1.0] */
int8_t variation_control_depth, insertion_control_depth;
};
struct DrumPartEffect
{
int32_t *buf;
int8_t note, reverb_send, chorus_send, delay_send;
};
struct DrumParts
{
int8_t drum_panning;
int32_t drum_envelope_rate[6]; /* drum instrument envelope */
int8_t pan_random; /* flag for drum random pan */
float drum_level;
int8_t chorus_level, reverb_level, delay_level, coarse, fine,
play_note, drum_cutoff_freq, drum_resonance;
int32_t rx;
};
struct Channel
{
int8_t bank_msb, bank_lsb, bank, program, volume,
expression, sustain, panning, mono, portamento,
key_shift, loop_timeout;
/* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar
processor near you */
int8_t chorus_level, /* Chorus level */
reverb_level; /* Reverb level. */
int reverb_id; /* Reverb ID used for reverb optimize implementation
>=0 reverb_level
-1: DEFAULT_REVERB_SEND_LEVEL
*/
int8_t delay_level; /* Delay Send Level */
int8_t eq_gs; /* EQ ON/OFF (GS) */
int8_t insertion_effect;
/* Special sample ID. (0 means Normal sample) */
uint8_t special_sample;
int pitchbend;
double
pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
/* For portamento */
uint8_t portamento_time_msb, portamento_time_lsb;
int porta_control_ratio, porta_dpb;
int32_t last_note_fine;
/* For Drum part */
struct DrumParts *drums[128];
/* For NRPN Vibrato */
int32_t vibrato_depth, vibrato_delay;
float vibrato_ratio;
/* For RPN */
uint8_t rpnmap[RPN_MAX_DATA_ADDR]; /* pseudo RPN address map */
uint8_t rpnmap_lsb[RPN_MAX_DATA_ADDR];
uint8_t lastlrpn, lastmrpn;
int8_t nrpn; /* 0:RPN, 1:NRPN, -1:Undefined */
int rpn_7f7f_flag; /* Boolean flag used for RPN 7F/7F */
/* For channel envelope */
int32_t envelope_rate[6]; /* for Envelope Generator in mix.c
* 0: value for attack rate
* 2: value for decay rate
* 3: value for release rate
*/
int mapID; /* Program map ID */
AlternateAssign *altassign; /* Alternate assign patch table */
int32_t lasttime; /* Last sample time of computed voice on this channel */
/* flag for random pan */
int pan_random;
/* for Voice LPF / Resonance */
int8_t param_resonance, param_cutoff_freq; /* -64 ~ 63 */
float cutoff_freq_coef, resonance_dB;
int8_t velocity_sense_depth, velocity_sense_offset;
int8_t scale_tuning[12], prev_scale_tuning;
int8_t temper_type;
int8_t soft_pedal;
int8_t sostenuto;
int8_t damper_mode;
int8_t tone_map0_number;
double pitch_offset_fine; /* in Hz */
int8_t assign_mode;
int8_t legato; /* legato footswitch */
int8_t legato_flag; /* note-on flag for legato */
midi_controller mod, bend, caf, paf, cc1, cc2;
ChannelBitMask channel_layer;
int port_select;
struct part_eq_xg eq_xg;
int8_t dry_level;
int8_t note_limit_high, note_limit_low; /* Note Limit (Keyboard Range) */
int8_t vel_limit_high, vel_limit_low; /* Velocity Limit */
int32_t rx; /* Rx. ~ (Rcv ~) */
int drum_effect_num;
int8_t drum_effect_flag;
struct DrumPartEffect *drum_effect;
int8_t sysex_gs_msb_addr, sysex_gs_msb_val,
sysex_xg_msb_addr, sysex_xg_msb_val, sysex_msb_addr, sysex_msb_val;
};
/* Causes the instrument's default panning to be used. */
#define NO_PANNING -1
typedef struct {
int16_t freq, last_freq, orig_freq;
double reso_dB, last_reso_dB, orig_reso_dB, reso_lin;
int8_t type; /* filter type. 0: Off, 1: 12dB/oct, 2: 24dB/oct */
int32_t f, q, p; /* coefficients in fixed-point */
int32_t b0, b1, b2, b3, b4;
float gain;
int8_t start_flag;
} FilterCoefficients;
#define ENABLE_PAN_DELAY
#define PAN_DELAY_BUF_MAX 48 /* 0.5ms in 96kHz */
typedef struct {
uint8_t
status, channel, note, velocity;
int vid, temper_instant;
Sample *sample;
int64_t sample_offset; /* sample_offset must be signed */
int32_t
orig_frequency, frequency, sample_increment,
envelope_volume, envelope_target, envelope_increment,
tremolo_sweep, tremolo_sweep_position,
tremolo_phase, tremolo_phase_increment,
vibrato_sweep, vibrato_sweep_position;
final_volume_t left_mix, right_mix;
int32_t old_left_mix, old_right_mix,
left_mix_offset, right_mix_offset,
left_mix_inc, right_mix_inc;
double
left_amp, right_amp, tremolo_volume;
int32_t
vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS], vibrato_delay;
int
vibrato_phase, orig_vibrato_control_ratio, vibrato_control_ratio,
vibrato_depth, vibrato_control_counter,
envelope_stage, control_counter, panning, panned;
int16_t tremolo_depth;
/* for portamento */
int porta_control_ratio, porta_control_counter, porta_dpb;
int32_t porta_pb;
int delay; /* Note ON delay samples */
int32_t timeout;
struct cache_hash *cache;
uint8_t chorus_link; /* Chorus link */
int8_t proximate_flag;
FilterCoefficients fc;
double envelope_scale, last_envelope_volume;
int32_t inv_envelope_scale;
int modenv_stage;
int32_t
modenv_volume, modenv_target, modenv_increment;
double last_modenv_volume;
int32_t tremolo_delay, modenv_delay;
int32_t delay_counter;
#ifdef ENABLE_PAN_DELAY
int32_t *pan_delay_buf, pan_delay_rpt, pan_delay_wpt, pan_delay_spt;
#endif /* ENABLE_PAN_DELAY */
} Voice;
/* Voice status options: */
#define VOICE_FREE (1<<0)
#define VOICE_ON (1<<1)
#define VOICE_SUSTAINED (1<<2)
#define VOICE_OFF (1<<3)
#define VOICE_DIE (1<<4)
/* Voice panned options: */
#define PANNED_MYSTERY 0
#define PANNED_LEFT 1
#define PANNED_RIGHT 2
#define PANNED_CENTER 3
/* Anything but PANNED_MYSTERY only uses the left volume */
enum {
MODULE_TIMIDITY_DEFAULT = 0x0,
/* GS modules */
MODULE_SC55 = 0x1,
MODULE_SC88 = 0x2,
MODULE_SC88PRO = 0x3,
MODULE_SC8850 = 0x4,
/* XG modules */
MODULE_MU50 = 0x10,
MODULE_MU80 = 0x11,
MODULE_MU90 = 0x12,
MODULE_MU100 = 0x13,
/* GM modules */
MODULE_SBLIVE = 0x20,
MODULE_SBAUDIGY = 0x21,
/* Special modules */
MODULE_TIMIDITY_SPECIAL1 = 0x70,
MODULE_TIMIDITY_DEBUG = 0x7f,
};
struct midi_file_info
{
int readflag;
char *seq_name;
char *karaoke_title;
char *first_text;
int16_t hdrsiz;
int16_t format;
int16_t tracks;
int32_t divisions;
int time_sig_n, time_sig_d, time_sig_c, time_sig_b; /* Time signature */
int drumchannels_isset;
ChannelBitMask drumchannels;
ChannelBitMask drumchannel_mask;
int32_t samples;
int max_channel;
int compressed; /* True if midi_data is compressed */
};
class Recache;
class Mixer;
class Reverb;
class AudioQueue;
class Player
{
public:
Channel channel[MAX_CHANNELS];
Voice voice[max_voices];
ChannelBitMask default_drumchannel_mask;
ChannelBitMask default_drumchannels;
ChannelBitMask drumchannel_mask;
ChannelBitMask drumchannels;
double *vol_table;
private:
Recache *recache;
Mixer *mixer;
Reverb *reverb;
AudioQueue *aq;
MidiEvent *current_event;
int32_t sample_count; /* Length of event_list */
int32_t current_sample; /* Number of calclated samples */
double midi_time_ratio; /* For speed up/down */
int note_key_offset = 0; /* For key up/down */
ChannelBitMask channel_mute; /* For channel mute */
double master_volume;
int32_t master_volume_ratio;
int play_system_mode;
int midi_streaming;
int volatile stream_max_compute; /* compute time limit (in msec) when streaming */
int8_t current_keysig;
int8_t current_temper_keysig;
int temper_adj;
int32_t current_play_tempo;
int opt_realtime_playing;
int check_eot_flag;
int playmidi_seek_flag;
int opt_pure_intonation;
int current_freq_table;
int current_temper_freq_table;
int master_tuning;
int make_rvid_flag; /* For reverb optimization */
int32_t amplification;
int voices, upper_voices;
struct midi_file_info midifileinfo, *current_file_info;
MBlockList playmidi_pool;
int32_t freq_table_user[4][48][128];
char *reverb_buffer; /* MAX_CHANNELS*AUDIO_BUFFER_SIZE*8 */
int32_t lost_notes, cut_notes;
int32_t common_buffer[AUDIO_BUFFER_SIZE * 2], *buffer_pointer; /* stereo samples */
int16_t wav_buffer[AUDIO_BUFFER_SIZE * 2];
int32_t buffered_count;
int32_t insertion_effect_buffer[AUDIO_BUFFER_SIZE * 2];
/* Ring voice id for each notes. This ID enables duplicated note. */
uint8_t vidq_head[128 * MAX_CHANNELS], vidq_tail[128 * MAX_CHANNELS];
int MIDI_EVENT_NOTE(MidiEvent *ep)
{
return (ISDRUMCHANNEL((ep)->channel) ? (ep)->a : (((int)(ep)->a + note_key_offset + channel[ep->channel].key_shift) & 0x7f));
}
int32_t MIDI_EVENT_TIME(MidiEvent *ep)
{
return ((int32_t)((ep)->time * midi_time_ratio + 0.5));
}
int16_t conv_lfo_pitch_depth(float val)
{
return (int16_t)(0.0318f * val * val + 0.6858f * val + 0.5f);
}
int16_t conv_lfo_filter_depth(float val)
{
return (int16_t)((0.0318f * val * val + 0.6858f * val) * 4.0f + 0.5f);
}
bool IS_SYSEX_EVENT_TYPE(MidiEvent *event);
double cnv_Hz_to_vib_ratio(double freq);
int new_vidq(int ch, int note);
int last_vidq(int ch, int note);
void reset_voices(void);
void kill_note(int i);
void kill_all_voices(void);
void reset_drum_controllers(struct DrumParts *d[], int note);
void reset_nrpn_controllers(int c);
void reset_controllers(int c);
int32_t calc_velocity(int32_t ch, int32_t vel);
void recompute_voice_tremolo(int v);
void recompute_amp(int v);
void reset_midi(int playing);
void recompute_channel_filter(int ch, int note);
void init_voice_filter(int i);
int reduce_voice(void);
int find_free_voice(void);
int get_panning(int ch, int note, int v);
void init_voice_vibrato(int v);
void init_voice_pan_delay(int v);
void init_voice_portamento(int v);
void init_voice_tremolo(int v);
void start_note(MidiEvent *e, int i, int vid, int cnt);
void set_envelope_time(int ch, int val, int stage);
void new_chorus_voice_alternate(int v1, int level);
void note_on(MidiEvent *e);
void update_sostenuto_controls(int ch);
void update_redamper_controls(int ch);
void note_off(MidiEvent *e);
void all_notes_off(int c);
void all_sounds_off(int c);
void adjust_pressure(MidiEvent *e);
void adjust_channel_pressure(MidiEvent *e);
void adjust_panning(int c);
void adjust_drum_panning(int ch, int note);
void drop_sustain(int c);
void adjust_all_pitch(void);
void adjust_pitch(int c);
void adjust_volume(int c);
void set_reverb_level(int ch, int level);
void make_drum_effect(int ch);
void adjust_master_volume(void);
void add_channel_layer(int to_ch, int from_ch);
void remove_channel_layer(int ch);
void process_sysex_event(int ev, int ch, int val, int b);
double gs_cnv_vib_rate(int rate);
int32_t gs_cnv_vib_depth(int depth);
int32_t gs_cnv_vib_delay(int delay);
int last_rpn_addr(int ch);
void voice_increment(int n);
void voice_decrement(int n);
void voice_decrement_conservative(int n);
void mix_signal(int32_t *dest, int32_t *src, int32_t count);
int is_insertion_effect_xg(int ch);
void do_compute_data(int32_t count);
int check_midi_play_end(MidiEvent *e, int len);
int midi_play_end(void);
int compute_data(int32_t count);
void update_modulation_wheel(int ch);
void drop_portamento(int ch);
void update_portamento_time(int ch);
void update_legato_controls(int ch);
void set_master_tuning(int tune);
struct midi_file_info *new_midi_file_info();
void adjust_amplification(void);
void init_freq_table_user(void);
int find_samples(MidiEvent *, int *);
int select_play_sample(Sample *, int, int *, int *, MidiEvent *);
double get_play_note_ratio(int, int);
int find_voice(MidiEvent *);
void finish_note(int i);
void update_portamento_controls(int ch);
void update_rpn_map(int ch, int addr, int update_now);
void set_single_note_tuning(int, int, int, int);
void set_user_temper_entry(int, int, int);
void recompute_bank_parameter(int, int);
float calc_drum_tva_level(int ch, int note, int level);
int32_t calc_random_delay(int ch, int note);
/* XG Part EQ */
void init_part_eq_xg(struct part_eq_xg *);
void recompute_part_eq_xg(struct part_eq_xg *);
/* MIDI controllers (MW, Bend, CAf, PAf,...) */
void init_midi_controller(midi_controller *);
float get_midi_controller_amp(midi_controller *);
float get_midi_controller_filter_cutoff(midi_controller *);
float get_midi_controller_filter_depth(midi_controller *);
int32_t get_midi_controller_pitch(midi_controller *);
int16_t get_midi_controller_pitch_depth(midi_controller *);
int16_t get_midi_controller_amp_depth(midi_controller *);
/* Rx. ~ (Rcv ~) */
void init_rx(int);
void set_rx(int, int32_t, int);
void init_rx_drum(struct DrumParts *);
void set_rx_drum(struct DrumParts *, int32_t, int);
int32_t get_rx_drum(struct DrumParts *, int32_t);
public:
Player();
~Player();
bool ISDRUMCHANNEL(int c)
{
return !!IS_SET_CHANNELMASK(drumchannels, c);
}
int midi_drumpart_change(int ch, int isdrum);
int get_reverb_level(int ch);
int get_chorus_level(int ch);
Instrument *play_midi_load_instrument(int dr, int bk, int prog);
void midi_program_change(int ch, int prog);
void free_voice(int v);
void play_midi_setup_drums(int ch, int note);
/* For stream player */
void playmidi_stream_init(void);
void playmidi_tmr_reset(void);
int play_event(MidiEvent *ev);
void recompute_voice_filter(int);
void free_drum_effect(int);
void change_system_mode(int mode);
struct midi_file_info *get_midi_file_info(const char *filename, int newp);
void recompute_freq(int v);
int get_default_mapID(int ch);
void init_channel_layer(int ch);
// Only until streaming works.
void skip_to(int32_t until_time, MidiEvent *evt_start);
int play_midi(MidiEvent *eventlist, int32_t samples);
friend MidiEvent *groom_list(int32_t divisions, int32_t *eventsp, int32_t *samplesp);
};
class SysexConvert
{
const int midi_port_number = 0;
uint8_t rhythm_part[2] = { 0,0 }; /* for GS */
uint8_t drum_setup_xg[16] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; /* for XG */
public:
int parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments);
int parse_sysex_event(uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments);
};
// really extern!
int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret);
}
#endif /* ___PLAYMIDI_H_ */

View File

@ -0,0 +1,340 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
quantity.c
string -> quantity -> native value convertion
by Kentaro Sato <kentaro@ranvis.com>
*/
#include <stdlib.h>
#include <math.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "tables.h"
#include "quantity.h"
namespace TimidityPlus
{
typedef int32_t(*QuantityToIntProc)(int32_t value, int32_t param);
typedef double(*QuantityToFloatProc)(double value, int32_t param);
typedef union {
QuantityToIntProc i;
QuantityToFloatProc f;
} QuantityConvertProc;
typedef struct {
const char *suffix;
uint16_t type, id;
int float_type; /* is floating-point type */
QuantityConvertProc convert;
} QuantityHint;
/*
Guide To Add New Unit Types/Units
append QUANTITY_UNIT_TYPE(<TYPE>)
QUANTITY_UNIT_NAME(<UNIT>)
... to enum quantity_units (in quantity.h)
append QUANTITY_TYPE_INT/FLOAT(<TYPE>)
REGISTER_TYPE_INT/FLOAT("<SUFFIX>", <UNIT>);
...
END_QUANTITY_TYPE; to GetQuantityHints()
write convert_<TYPE>_NUM(int32_t/double value, int32_t param)
convert_<UNIT>(int32_t/double value, int32_t param)
... functions.
*/
/*************** conversion functions ***************/
static int32_t convert_DIRECT_INT_NUM(int32_t value, int32_t param)
{
return value;
}
static double convert_DIRECT_FLOAT_NUM(double value, int32_t param)
{
return value;
}
/* from instrum.c, convert_tremolo_sweep() */
static int32_t convert_TREMOLO_SWEEP_NUM(int32_t value, int32_t param)
{
uint8_t sweep = value;
if (!sweep)
return 0;
return
((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
(playback_rate * sweep);
}
static int32_t convert_TREMOLO_SWEEP_MS(int32_t value, int32_t param)
{
if (value <= 0)
return 0;
#if SWEEP_SHIFT <= 16
return ((uint32_t)(control_ratio * (1000 >> 2)) << SWEEP_SHIFT) / ((playback_rate * value) >> 2);
#else
#error "overflow"
#endif
}
/* from instrum.c, convert_tremolo_rate() */
static int32_t convert_TREMOLO_RATE_NUM(int32_t value, int32_t param)
{
uint8_t rate = value;
return
((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) /
(TREMOLO_RATE_TUNING * playback_rate);
}
static int32_t convert_TREMOLO_RATE_MS(int32_t value, int32_t param)
{
#if RATE_SHIFT <= 5
return ((SINE_CYCLE_LENGTH * control_ratio * (1000 >> 1)) << RATE_SHIFT) /
((playback_rate * (uint32_t)value) >> 1);
#else
#error "overflow"
#endif
}
static double convert_TREMOLO_RATE_HZ(double value, int32_t param)
{
if (value <= 0)
return 0;
return ((SINE_CYCLE_LENGTH * control_ratio) << RATE_SHIFT) * value / playback_rate;
}
/* from instrum.c, convert_vibrato_sweep() */
static int32_t convert_VIBRATO_SWEEP_NUM(int32_t value, int32_t vib_control_ratio)
{
uint8_t sweep = value;
if (!sweep)
return 0;
return (int32_t)(TIM_FSCALE((double) (vib_control_ratio)
* SWEEP_TUNING, SWEEP_SHIFT)
/ (double)(playback_rate * sweep));
/* this was overflowing with seashore.pat
((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
(playback_rate * sweep); */
}
static int32_t convert_VIBRATO_SWEEP_MS(int32_t value, int32_t vib_control_ratio)
{
if (value <= 0)
return 0;
return (TIM_FSCALE((double)vib_control_ratio * 1000, SWEEP_SHIFT)
/ (double)(playback_rate * value));
}
/* from instrum.c, to_control() */
static int32_t convert_VIBRATO_RATE_NUM(int32_t control, int32_t param)
{
return (int32_t) (0x2000 / pow(2.0, control / 31.0));
}
static int32_t convert_VIBRATO_RATE_MS(int32_t value, int32_t param)
{
return 1000 * playback_rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value);
}
static double convert_VIBRATO_RATE_HZ(double value, int32_t param)
{
return playback_rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value);
}
/*************** core functions ***************/
#define MAX_QUANTITY_UNITS_PER_UNIT_TYPES 8
static int GetQuantityHints(uint16_t type, QuantityHint *units)
{
QuantityHint *unit;
unit = units;
#define QUANTITY_TYPE_INT(type) \
case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_INT("", type##_NUM)
#define QUANTITY_TYPE_FLOAT(type) \
case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_FLOAT("", type##_NUM)
#define REGISTER_TYPE_INT(ustr, utype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##utype)
#define REGISTER_TYPE_FLOAT(ustr, utype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##utype)
#define REGISTER_TYPE_ALIAS_INT(ustr, utype, atype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##atype)
#define REGISTER_TYPE_ALIAS_FLOAT(ustr, utype, atype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##atype)
#define REGISTER_TYPE_ENTITY_INT(ustr, utype, ucvt) \
unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 0, unit->convert.i = ucvt, unit++
#define REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, ucvt) \
unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 1, unit->convert.f = ucvt, unit++
#define END_QUANTITY_TYPE unit->suffix = NULL; break
switch (type)
{
QUANTITY_TYPE_INT(DIRECT_INT);
END_QUANTITY_TYPE;
QUANTITY_TYPE_FLOAT(DIRECT_FLOAT);
END_QUANTITY_TYPE;
QUANTITY_TYPE_INT(TREMOLO_SWEEP);
REGISTER_TYPE_INT("ms", TREMOLO_SWEEP_MS);
END_QUANTITY_TYPE;
QUANTITY_TYPE_INT(TREMOLO_RATE);
REGISTER_TYPE_INT("ms", TREMOLO_RATE_MS);
REGISTER_TYPE_FLOAT("Hz", TREMOLO_RATE_HZ);
END_QUANTITY_TYPE;
QUANTITY_TYPE_INT(VIBRATO_RATE);
REGISTER_TYPE_INT("ms", VIBRATO_RATE_MS);
REGISTER_TYPE_FLOAT("Hz", VIBRATO_RATE_HZ);
END_QUANTITY_TYPE;
QUANTITY_TYPE_INT(VIBRATO_SWEEP);
REGISTER_TYPE_INT("ms", VIBRATO_SWEEP_MS);
END_QUANTITY_TYPE;
default:
ctl_cmsg(CMSG_ERROR, VERB_NORMAL, "Internal parameter error (%d)", type);
return 0;
}
return 1;
}
/* quantity is unchanged if an error occurred */
static const char *number_to_quantity(int32_t number_i, const char *suffix_i, double number_f, const char *suffix_f, Quantity *quantity, uint16_t type)
{
QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit;
if (!GetQuantityHints(type, units))
return "Parameter error";
unit = units;
while(unit->suffix != NULL)
{
if (suffix_i != NULL && strcmp(suffix_i, unit->suffix) == 0) /* number_i, suffix_i was valid */
{
quantity->type = unit->type;
quantity->unit = unit->id;
if (unit->float_type)
quantity->value.f = number_i;
else
quantity->value.i = number_i;
return NULL;
}
else if (suffix_f != NULL && strcmp(suffix_f, unit->suffix) == 0) /* number_f, suffix_f was valid */
{
if (unit->float_type)
{
quantity->type = unit->type;
quantity->unit = unit->id;
quantity->value.f = number_f;
return NULL;
}
else
return "integer expected";
}
unit++;
}
return "invalid parameter";
}
const char *string_to_quantity(const char *string, Quantity *quantity, uint16_t type)
{
int32_t number_i;
double number_f;
char *suffix_i, *suffix_f;
number_i = strtol(string, &suffix_i, 10); /* base == 10 for compatibility with atoi() */
if (string == suffix_i) /* doesn't start with valid character */
return "Number expected";
number_f = strtod(string, &suffix_f);
return number_to_quantity(number_i, suffix_i, number_f, suffix_f, quantity, type);
}
void int_to_quantity(int32_t number, Quantity *quantity, uint16_t type)
{
/* pass suffix_f NULL to warn if unit type is float type */
if (number_to_quantity(number, "", number, NULL, quantity, type) != NULL) /* error */
{
quantity->type = QUANTITY_UNIT_TYPE(DIRECT_INT);
quantity->unit = QUANTITY_UNIT_NAME(DIRECT_INT_NUM);
quantity->value.i = 0;
}
}
void float_to_quantity(double number, Quantity *quantity, uint16_t type)
{
/* pass suffix_i NULL to warn if unit type is integer type */
if (number_to_quantity(number, NULL, number, "", quantity, type) != NULL) /* error */
{
quantity->type = QUANTITY_UNIT_TYPE(DIRECT_FLOAT);
quantity->unit = QUANTITY_UNIT_NAME(DIRECT_FLOAT_NUM);
quantity->value.f = 0;
}
}
static int GetQuantityConvertProc(const Quantity *quantity, QuantityConvertProc *proc)
{
QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit;
if (!GetQuantityHints(quantity->type, units))
return -1; /* already warned */
unit = units;
while(unit->suffix != NULL)
{
if (quantity->unit == unit->id)
{
*proc = unit->convert;
return unit->float_type;
}
unit++;
}
ctl_cmsg(CMSG_ERROR, VERB_NORMAL, "Internal parameter error");
return -1;
}
int32_t quantity_to_int(const Quantity *quantity, int32_t param)
{
QuantityConvertProc proc;
switch (GetQuantityConvertProc(quantity, &proc))
{
case 0:
return (*proc.i)(quantity->value.i, param);
case 1:
return (*proc.f)(quantity->value.f, param);
}
return 0;
}
double quantity_to_float(const Quantity *quantity, int32_t param)
{
QuantityConvertProc proc;
switch (GetQuantityConvertProc(quantity, &proc))
{
case 0:
return (*proc.i)(quantity->value.i, param);
case 1:
return (*proc.f)(quantity->value.f, param);
}
return 0;
}
}

View File

@ -0,0 +1,72 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
quantity.h
by Kentaro Sato <kentaro@ranvis.com>
*/
#ifndef ___QUANTITY_H_
#define ___QUANTITY_H_
#include <stdint.h>
namespace TimidityPlus
{
#define QUANTITY_UNIT_TYPE(u) QUANTITY_OF_##u, QUANTITY_UNIT_NAME(u##_NUM)
#define QUANTITY_UNIT_NAME(name) QUANTITY_UNIT_##name
enum quantity_units {
QUANTITY_UNIT_TYPE(UNDEFINED), /* type only */
QUANTITY_UNIT_TYPE(DIRECT_INT), /* internal use */
QUANTITY_UNIT_TYPE(DIRECT_FLOAT), /* internal use */
QUANTITY_UNIT_TYPE(TREMOLO_SWEEP), /* int */
QUANTITY_UNIT_NAME(TREMOLO_SWEEP_MS), /* int */
QUANTITY_UNIT_TYPE(TREMOLO_RATE), /* int */
QUANTITY_UNIT_NAME(TREMOLO_RATE_MS), /* int */
QUANTITY_UNIT_NAME(TREMOLO_RATE_HZ), /* float */
QUANTITY_UNIT_TYPE(VIBRATO_SWEEP), /* int */
QUANTITY_UNIT_NAME(VIBRATO_SWEEP_MS), /* int */
QUANTITY_UNIT_TYPE(VIBRATO_RATE), /* int */
QUANTITY_UNIT_NAME(VIBRATO_RATE_MS), /* int */
QUANTITY_UNIT_NAME(VIBRATO_RATE_HZ), /* float */
};
#undef QUANTITY_UNIT_TYPE
#define QUANTITY_UNIT_TYPE(u) QUANTITY_OF_##u
#define INIT_QUANTITY(q) (q).type = QUANTITY_UNIT_TYPE(UNDEFINED)
#define IS_QUANTITY_DEFINED(q) ((q).type != QUANTITY_UNIT_TYPE(UNDEFINED))
typedef struct Quantity_ {
uint16_t type, unit;
union {
int32_t i;
double f;
} value;
} Quantity;
extern const char *string_to_quantity(const char *string, Quantity *quantity, uint16_t type);
extern void int_to_quantity(int32_t number, Quantity *quantity, uint16_t type);
extern void float_to_quantity(double number, Quantity *quantity, uint16_t type);
extern int32_t quantity_to_int(const Quantity *quantity, int32_t param);
extern double quantity_to_float(const Quantity *quantity, int32_t param);
}
#endif /* ___QUANTITY_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,440 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
recache.c
Code related to resample cache.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "tables.h"
#include "mblock.h"
#include "recache.h"
#include "resample.h"
namespace TimidityPlus
{
#define CACHE_DATA_LEN (allocate_cache_size / sizeof(sample_t))
inline uint32_t sp_hash(Sample *sp, int note)
{
return ((uint32_t)(intptr_t)(sp)+(uint32_t)(note));
}
#define RESAMPLATION_CACHE _x = do_resamplation(src, ofs, &resrc); \
dest[i] = (int16_t) ((_x > 32767) ? 32767 \
: ((_x < -32768) ? -32768 : _x))
void Recache::free_cache_data(void) {
free(cache_data);
reuse_mblock(&hash_entry_pool);
}
void Recache::resamp_cache_reset(void)
{
if (cache_data == NULL) {
cache_data = (sample_t *)
safe_large_malloc((CACHE_DATA_LEN + 1) * sizeof(sample_t));
memset(cache_data, 0, (CACHE_DATA_LEN + 1) * sizeof(sample_t));
init_mblock(&hash_entry_pool);
}
cache_data_len = 0;
memset(cache_hash_table, 0, sizeof(cache_hash_table));
memset(channel_note_table, 0, sizeof(channel_note_table));
reuse_mblock(&hash_entry_pool);
}
struct cache_hash *Recache::resamp_cache_fetch(Sample *sp, int note)
{
unsigned int addr;
struct cache_hash *p;
if (sp->vibrato_control_ratio || (sp->modes & MODES_PINGPONG)
|| (sp->sample_rate == playback_rate
&& sp->root_freq == get_note_freq(sp, sp->note_to_use)))
return NULL;
addr = sp_hash(sp, note) % HASH_TABLE_SIZE;
p = cache_hash_table[addr];
while (p && (p->note != note || p->sp != sp))
p = p->next;
if (p && p->resampled != NULL)
return p;
return NULL;
}
void Recache::resamp_cache_refer_on(Voice *vp, int32_t sample_start)
{
unsigned int addr;
struct cache_hash *p;
int note, ch;
ch = vp->channel;
if (vp->vibrato_control_ratio || player->channel[ch].portamento
|| (vp->sample->modes & MODES_PINGPONG)
|| vp->orig_frequency != vp->frequency
|| (vp->sample->sample_rate == playback_rate
&& vp->sample->root_freq
== get_note_freq(vp->sample, vp->sample->note_to_use)))
return;
note = vp->note;
if (channel_note_table[ch].cache[note])
resamp_cache_refer_off(ch, note, sample_start);
addr = sp_hash(vp->sample, note) % HASH_TABLE_SIZE;
p = cache_hash_table[addr];
while (p && (p->note != note || p->sp != vp->sample))
p = p->next;
if (! p) {
p = (struct cache_hash *)
new_segment(&hash_entry_pool, sizeof(struct cache_hash));
p->cnt = 0;
p->note = vp->note;
p->sp = vp->sample;
p->resampled = NULL;
p->next = cache_hash_table[addr];
cache_hash_table[addr] = p;
}
channel_note_table[ch].cache[note] = p;
channel_note_table[ch].on[note] = sample_start;
}
void Recache::resamp_cache_refer_off(int ch, int note, int32_t sample_end)
{
int32_t sample_start, len;
struct cache_hash *p;
Sample *sp;
p = channel_note_table[ch].cache[note];
if (p == NULL)
return;
sp = p->sp;
if (sp->sample_rate == playback_rate
&& sp->root_freq == get_note_freq(sp, sp->note_to_use))
return;
sample_start = channel_note_table[ch].on[note];
len = sample_end - sample_start;
if (len < 0) {
channel_note_table[ch].cache[note] = NULL;
return;
}
if (! (sp->modes & MODES_LOOPING)) {
double a;
int32_t slen;
a = ((double) sp->root_freq * playback_rate)
/ ((double) sp->sample_rate * get_note_freq(sp, note));
slen = (int32_t) ((sp->data_length >> FRACTION_BITS) * a);
if (len > slen)
len = slen;
}
p->cnt += len;
channel_note_table[ch].cache[note] = NULL;
}
void Recache::resamp_cache_refer_alloff(int ch, int32_t sample_end)
{
int i;
for (i = 0; i < 128; i++)
resamp_cache_refer_off(ch, i, sample_end);
}
void Recache::resamp_cache_create(void)
{
int i, skip;
int32_t n, t1, t2, total;
struct cache_hash **array;
/* It is NP completion that solve the best cache hit rate.
* So I thought better algorism O(n log n), but not a best solution.
* Follows implementation takes good hit rate, and it is fast.
*/
n = t1 = t2 = 0;
total = 0;
/* set size per count */
for (i = 0; i < HASH_TABLE_SIZE; i++) {
struct cache_hash *p, *q;
p = cache_hash_table[i], q = NULL;
while (p) {
struct cache_hash *tmp;
t1 += p->cnt;
tmp = p, p = p->next;
if (tmp->cnt > 0) {
Sample *sp;
splen_t newlen;
sp = tmp->sp;
sample_resamp_info(sp, tmp->note, NULL, NULL, &newlen);
if (newlen > 0) {
total += tmp->cnt;
tmp->r = (double) newlen / tmp->cnt;
tmp->next = q, q = tmp;
n++;
}
}
}
cache_hash_table[i] = q;
}
if (n == 0) {
ctl_cmsg(CMSG_INFO, VERB_VERBOSE, "No pre-resampling cache hit");
return;
}
array = (struct cache_hash **) new_segment(&hash_entry_pool,
n * sizeof(struct cache_hash *));
n = 0;
for (i = 0; i < HASH_TABLE_SIZE; i++) {
struct cache_hash *p;
for (p = cache_hash_table[i]; p; p = p->next)
array[n++] = p;
}
if ((uint32_t)total > CACHE_DATA_LEN)
qsort_cache_array(array, 0, n - 1);
skip = 0;
for (i = 0; i < n; i++) {
if (array[i]->r != 0
&& cache_resampling(array[i]) == CACHE_RESAMPLING_OK)
t2 += array[i]->cnt;
else
skip++;
}
/* update cache_hash_table */
if (skip)
for (i = 0; i < HASH_TABLE_SIZE; i++) {
struct cache_hash *p, *q;
p = cache_hash_table[i], q = NULL;
while (p) {
struct cache_hash *tmp;
tmp = p, p = p->next;
if (tmp->resampled)
tmp->next = q, q = tmp;
}
cache_hash_table[i] = q;
}
}
double Recache::sample_resamp_info(Sample *sp, int note,
splen_t *loop_start, splen_t *loop_end, splen_t *data_length)
{
splen_t xls, xle, ls, le, ll, newlen;
double a, xxls, xxle, xn;
a = ((double) sp->sample_rate * get_note_freq(sp, note))
/ ((double) sp->root_freq * playback_rate);
a = TIM_FSCALENEG((double) (int32_t) TIM_FSCALE(a, FRACTION_BITS),
FRACTION_BITS);
xn = sp->data_length / a;
if (xn >= SPLEN_T_MAX) {
/* Ignore this sample */
*data_length = 0;
return 0.0;
}
newlen = (splen_t) (TIM_FSCALENEG(xn, FRACTION_BITS) + 0.5);
ls = sp->loop_start;
le = sp->loop_end;
ll = le - ls;
xxls = ls / a + 0.5;
if (xxls >= SPLEN_T_MAX) {
/* Ignore this sample */
*data_length = 0;
return 0.0;
}
xls = (splen_t) xxls;
xxle = le / a + 0.5;
if (xxle >= SPLEN_T_MAX) {
/* Ignore this sample */
*data_length = 0;
return 0.0;
}
xle = (splen_t) xxle;
if ((sp->modes & MODES_LOOPING)
&& ((xle - xls) >> FRACTION_BITS) < MIN_LOOPLEN) {
splen_t n;
splen_t newxle;
double xl; /* Resampled new loop length */
double xnewxle;
xl = ll / a;
if (xl >= SPLEN_T_MAX) {
/* Ignore this sample */
*data_length = 0;
return 0.0;
}
n = (splen_t) (0.0001 + MIN_LOOPLEN
/ TIM_FSCALENEG(xl, FRACTION_BITS)) + 1;
xnewxle = le / a + n * xl + 0.5;
if (xnewxle >= SPLEN_T_MAX) {
/* Ignore this sample */
*data_length = 0;
return 0.0;
}
newxle = (splen_t) xnewxle;
newlen += (newxle - xle) >> FRACTION_BITS;
xle = newxle;
}
if (loop_start)
*loop_start = (splen_t) (xls & ~FRACTION_MASK);
if (loop_end)
*loop_end = (splen_t) (xle & ~FRACTION_MASK);
*data_length = newlen << FRACTION_BITS;
return a;
}
void Recache::qsort_cache_array(struct cache_hash **a, int32_t first, int32_t last)
{
int32_t i = first, j = last;
struct cache_hash *x, *t;
if (j - i < SORT_THRESHOLD) {
insort_cache_array(a + i, j - i + 1);
return;
}
x = a[(first + last) / 2];
for (;;) {
while (a[i]->r < x->r)
i++;
while (x->r < a[j]->r)
j--;
if (i >= j)
break;
t = a[i], a[i] = a[j], a[j] = t;
i++, j--;
}
if (first < i - 1)
qsort_cache_array(a, first, i - 1);
if (j + 1 < last)
qsort_cache_array(a, j + 1, last);
}
void Recache::insort_cache_array(struct cache_hash **data, int32_t n)
{
int32_t i, j;
struct cache_hash *x;
for (i = 1; i < n; i++) {
x = data[i];
for (j = i - 1; j >= 0 && x->r < data[j]->r; j--)
data[j + 1] = data[j];
data[j + 1] = x;
}
}
int Recache::cache_resampling(struct cache_hash *p)
{
Sample *sp, *newsp;
sample_t *src, *dest;
splen_t newlen, ofs, le, ls, ll, xls, xle;
int32_t incr, _x;
resample_rec_t resrc;
double a;
int8_t note;
sp = p->sp;
if (sp->note_to_use)
note = sp->note_to_use;
else
note = p->note;
a = sample_resamp_info(sp, note, &xls, &xle, &newlen);
if (newlen == 0)
return CACHE_RESAMPLING_NOTOK;
newlen >>= FRACTION_BITS;
if (cache_data_len + newlen + 1 > CACHE_DATA_LEN)
return CACHE_RESAMPLING_NOTOK;
resrc.loop_start = ls = sp->loop_start;
resrc.loop_end = le = sp->loop_end;
resrc.data_length = sp->data_length;
ll = sp->loop_end - sp->loop_start;
dest = cache_data + cache_data_len;
src = sp->data;
newsp = (Sample *) new_segment(&hash_entry_pool, sizeof(Sample));
memcpy(newsp, sp, sizeof(Sample));
newsp->data = dest;
ofs = 0;
incr = (splen_t) (TIM_FSCALE(a, FRACTION_BITS) + 0.5);
if (sp->modes & MODES_LOOPING)
for (splen_t i = 0; i < newlen; i++) {
if (ofs >= le)
ofs -= ll;
RESAMPLATION_CACHE;
ofs += incr;
}
else
for (splen_t i = 0; i < newlen; i++) {
RESAMPLATION_CACHE;
ofs += incr;
}
newsp->loop_start = xls;
newsp->loop_end = xle;
newsp->data_length = newlen << FRACTION_BITS;
if (sp->modes & MODES_LOOPING)
loop_connect(dest, (int32_t) (xls >> FRACTION_BITS),
(int32_t) (xle >> FRACTION_BITS));
dest[xle >> FRACTION_BITS] = dest[xls >> FRACTION_BITS];
newsp->root_freq = get_note_freq(newsp, note);
newsp->sample_rate = playback_rate;
p->resampled = newsp;
cache_data_len += newlen + 1;
return CACHE_RESAMPLING_OK;
}
void Recache::loop_connect(sample_t *data, int32_t start, int32_t end)
{
int i, mixlen;
int32_t t0, t1;
mixlen = MIXLEN;
if (start < mixlen)
mixlen = start;
if (end - start < mixlen)
mixlen = end - start;
if (mixlen <= 0)
return;
t0 = start - mixlen;
t1 = end - mixlen;
for (i = 0; i < mixlen; i++) {
double x, b;
b = i / (double) mixlen; /* 0 <= b < 1 */
x = b * data[t0 + i] + (1.0 - b) * data[t1 + i];
if (x < -32768)
data[t1 + i] = -32768;
else if (x > 32767)
data[t1 + i] = 32767;
else
data[t1 + i] = (sample_t) x;
}
}
}

View File

@ -0,0 +1,106 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ___RECACHE_H_
#define ___RECACHE_H_
#include <stdint.h>
namespace TimidityPlus
{
struct cache_hash
{
/* cache key */
int note;
Sample *sp;
int32_t cnt; /* counter */
double r; /* size/refcnt */
Sample *resampled;
struct cache_hash *next;
};
class Player;
class Recache
{
Player *player;
enum
{
HASH_TABLE_SIZE = 251,
MIXLEN = 256,
MIN_LOOPSTART = MIXLEN,
MIN_LOOPLEN = 1024,
MAX_EXPANDLEN = (1024 * 32),
CACHE_RESAMPLING_OK = 0,
CACHE_RESAMPLING_NOTOK = 1,
SORT_THRESHOLD = 20
};
struct CNote
{
int32_t on[128];
struct cache_hash *cache[128];
};
CNote channel_note_table[MAX_CHANNELS] = { 0 };
sample_t *cache_data = NULL;
splen_t cache_data_len = 0;
struct cache_hash *cache_hash_table[HASH_TABLE_SIZE] = { 0 };
MBlockList hash_entry_pool = { nullptr, 0 };
void free_cache_data(void);
double sample_resamp_info(Sample *, int, splen_t *, splen_t *, splen_t *);
void qsort_cache_array(struct cache_hash **, int32_t, int32_t);
void insort_cache_array(struct cache_hash **, int32_t);
int cache_resampling(struct cache_hash *);
void loop_connect(sample_t *, int32_t, int32_t);
public:
Recache(Player *p)
{
player = p;
resamp_cache_reset();
}
~Recache()
{
free_cache_data();
}
void resamp_cache_reset(void);
void resamp_cache_refer_on(Voice *vp, int32_t sample_start);
void resamp_cache_refer_off(int ch, int note, int32_t sample_end);
void resamp_cache_refer_alloff(int ch, int32_t sample_end);
void resamp_cache_create(void);
struct cache_hash *resamp_cache_fetch(Sample *sp, int note);
};
const int32_t allocate_cache_size = DEFAULT_CACHE_DATA_SIZE;
}
#endif /* ___RECACHE_H_ */

View File

@ -0,0 +1,979 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
resample.c
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "tables.h"
#include "resample.h"
#include "recache.h"
namespace TimidityPlus
{
/* for start/end of samples */
static float newt_coeffs[58][58];
static int sample_bounds_min, sample_bounds_max; /* min/max bounds for sample data */
#define DEFAULT_GAUSS_ORDER 25
static float *gauss_table[(1 << FRACTION_BITS)] = { 0 }; /* don't need doubles */
static int gauss_n = DEFAULT_GAUSS_ORDER;
static void initialize_newton_coeffs()
{
int i, j, n = 57;
int sign;
newt_coeffs[0][0] = 1;
for (i = 0; i <= n; i++)
{
newt_coeffs[i][0] = 1;
newt_coeffs[i][i] = 1;
if (i > 1)
{
newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i;
newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i;
}
for (j = 1; j < i; j++)
{
newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1] + newt_coeffs[i - 1][j];
if (i > 1)
newt_coeffs[i][j] /= i;
}
}
for (i = 0; i <= n; i++)
for (j = 0, sign = pow(-1, i); j <= i; j++, sign *= -1)
newt_coeffs[i][j] *= sign;
}
/* Very fast and accurate table based interpolation. Better speed and higher
accuracy than Newton. This isn't *quite* true Gauss interpolation; it's
more a slightly modified Gauss interpolation that I accidently stumbled
upon. Rather than normalize all x values in the window to be in the range
[0 to 2*PI], it simply divides them all by 2*PI instead. I don't know why
this works, but it does. Gauss should only work on periodic data with the
window spanning exactly one period, so it is no surprise that regular Gauss
interpolation doesn't work too well on general audio data. But dividing
the x values by 2*PI magically does. Any other scaling produces degraded
results or total garbage. If anyone can work out the theory behind why
this works so well (at first glance, it shouldn't ??), please contact me
(Eric A. Welsh, ewelsh@ccb.wustl.edu), as I would really like to have some
mathematical justification for doing this. Despite the lack of any sound
theoretical basis, this method DOES result in highly accurate interpolation
(or possibly approximaton, not sure yet if it truly interpolates, but it
looks like it does). -N 34 is as high as it can go before errors start
appearing. But even at -N 34, it is more accurate than Newton at -N 57.
-N 34 has no problem running in realtime on my system, but -N 25 is the
default, since that is the optimal compromise between speed and accuracy.
I strongly recommend using Gauss interpolation. It is the highest
quality interpolation option available, and is much faster than using
Newton polynomials. */
static resample_t resample_gauss(sample_t *src, splen_t ofs, resample_rec_t *rec)
{
sample_t *sptr;
int32_t left, right, temp_n;
left = (ofs >> FRACTION_BITS);
right = (rec->data_length >> FRACTION_BITS) - left - 1;
temp_n = (right << 1) - 1;
if (temp_n > (left << 1) + 1)
temp_n = (left << 1) + 1;
if (temp_n < gauss_n) {
int ii, jj;
float xd, y;
if (temp_n <= 0)
temp_n = 1;
xd = ofs & FRACTION_MASK;
xd /= (1L << FRACTION_BITS);
xd += temp_n >> 1;
y = 0;
sptr = src + (ofs >> FRACTION_BITS) - (temp_n >> 1);
for (ii = temp_n; ii;) {
for (jj = 0; jj <= ii; jj++)
y += sptr[jj] * newt_coeffs[ii][jj];
y *= xd - --ii;
}
y += *sptr;
return ((y > sample_bounds_max) ? sample_bounds_max :
((y < sample_bounds_min) ? sample_bounds_min : y));
}
else {
float *gptr, *gend;
float y;
y = 0;
sptr = src + left - (gauss_n >> 1);
gptr = gauss_table[ofs&FRACTION_MASK];
if (gauss_n == DEFAULT_GAUSS_ORDER) {
/* expanding the loop for the default case.
* this will allow intensive optimization when compiled
* with SSE2 capability.
*/
#define do_gauss y += *(sptr++) * *(gptr++);
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
do_gauss;
y += *sptr * *gptr;
#undef do_gauss
}
else {
gend = gptr + gauss_n;
do {
y += *(sptr++) * *(gptr++);
} while (gptr <= gend);
}
return ((y > sample_bounds_max) ? sample_bounds_max :
((y < sample_bounds_min) ? sample_bounds_min : y));
}
}
#define RESAMPLATION *dest++ = resample_gauss(src, ofs, &resrc);
/* exported for recache.c */
resample_t do_resamplation(sample_t *src, splen_t ofs, resample_rec_t *rec)
{
return resample_gauss(src, ofs, rec);
}
#define PRECALC_LOOP_COUNT(start, end, incr) (int32_t)(((int64_t)((end) - (start) + (incr) - 1)) / (incr))
void initialize_gauss_table(int n)
{
int m, i, k, n_half = (n >> 1);
double ck;
double x, x_inc, xz;
double z[35], zsin_[34 + 35], *zsin, xzsin[35];
float *gptr;
for (i = 0; i <= n; i++)
z[i] = i / (4 * M_PI);
zsin = &zsin_[34];
for (i = -n; i <= n; i++)
zsin[i] = sin(i / (4 * M_PI));
x_inc = 1.0 / (1 << FRACTION_BITS);
gptr = (float*)safe_realloc(gauss_table[0], (n + 1) * sizeof(float)*(1 << FRACTION_BITS));
for (m = 0, x = 0.0; m < (1 << FRACTION_BITS); m++, x += x_inc)
{
xz = (x + n_half) / (4 * M_PI);
for (i = 0; i <= n; i++)
xzsin[i] = sin(xz - z[i]);
gauss_table[m] = gptr;
for (k = 0; k <= n; k++)
{
ck = 1.0;
for (i = 0; i <= n; i++)
{
if (i == k)
continue;
ck *= xzsin[i] / zsin[k - i];
}
*gptr++ = ck;
}
}
}
void free_gauss_table(void)
{
if (gauss_table[0] != 0)
free(gauss_table[0]);
gauss_table[0] = NULL;
}
/* initialize the coefficients of the current resampling algorithm */
void initialize_resampler_coeffs(void)
{
// Only needs to be done once.
static bool done = false;
if (done) return;
done = true;
// atterm(free_gauss_table);
initialize_newton_coeffs();
initialize_gauss_table(gauss_n);
/* we don't have to initialize newton table any more */
/* bounds checking values for the appropriate sample types */
/* this is as good a place as any to initialize them */
if (play_mode->encoding & PE_24BIT)
{
sample_bounds_min = -8388608;
sample_bounds_max = 8388607;
}
else /* 16-bit */
{
sample_bounds_min = -32768;
sample_bounds_max = 32767;
}
}
/*************** resampling with fixed increment *****************/
resample_t *Resampler::rs_plain_c(int v, int32_t *countptr)
{
Voice *vp = &player->voice[v];
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
int32_t ofs, count = *countptr, i, le;
le = (int32_t)(vp->sample->loop_end >> FRACTION_BITS);
ofs = (int32_t)(vp->sample_offset >> FRACTION_BITS);
i = ofs + count;
if (i > le)
i = le;
count = i - ofs;
for (i = 0; i < count; i++) {
dest[i] = src[i + ofs];
}
ofs += count;
if (ofs == le)
{
vp->timeout = 1;
*countptr = count;
}
vp->sample_offset = ((splen_t)ofs << FRACTION_BITS);
return resample_buffer + resample_buffer_offset;
}
resample_t *Resampler::rs_plain(int v, int32_t *countptr)
{
/* Play sample until end, then free the voice. */
Voice *vp = &player->voice[v];
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
splen_t
ofs = vp->sample_offset,
ls = 0,
le = vp->sample->data_length;
resample_rec_t resrc;
int32_t count = *countptr, incr = vp->sample_increment;
int32_t i, j;
if (vp->cache && incr == (1 << FRACTION_BITS))
return rs_plain_c(v, countptr);
resrc.loop_start = ls;
resrc.loop_end = le;
resrc.data_length = vp->sample->data_length;
if (incr < 0) incr = -incr; /* In case we're coming out of a bidir loop */
/* Precalc how many times we should go through the loop.
NOTE: Assumes that incr > 0 and that ofs <= le */
i = PRECALC_LOOP_COUNT(ofs, le, incr);
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
for (j = 0; j < i; j++)
{
RESAMPLATION;
ofs += incr;
}
if (ofs >= le)
{
vp->timeout = 1;
*countptr -= count;
}
vp->sample_offset = ofs; /* Update offset */
return resample_buffer + resample_buffer_offset;
}
resample_t *Resampler::rs_loop_c(Voice *vp, int32_t count)
{
int32_t
ofs = (int32_t)(vp->sample_offset >> FRACTION_BITS),
le = (int32_t)(vp->sample->loop_end >> FRACTION_BITS),
ll = le - (int32_t)(vp->sample->loop_start >> FRACTION_BITS);
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
int32_t i, j;
while (count)
{
while (ofs >= le)
ofs -= ll;
/* Precalc how many times we should go through the loop */
i = le - ofs;
if (i > count)
i = count;
count -= i;
for (j = 0; j < i; j++) {
dest[j] = src[j + ofs];
}
dest += i;
ofs += i;
}
vp->sample_offset = ((splen_t)ofs << FRACTION_BITS);
return resample_buffer + resample_buffer_offset;
}
resample_t *Resampler::rs_loop(Voice *vp, int32_t count)
{
/* Play sample until end-of-loop, skip back and continue. */
splen_t
ofs = vp->sample_offset,
ls, le, ll;
resample_rec_t resrc;
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
int32_t i, j;
int32_t incr = vp->sample_increment;
if (vp->cache && incr == (1 << FRACTION_BITS))
return rs_loop_c(vp, count);
resrc.loop_start = ls = vp->sample->loop_start;
resrc.loop_end = le = vp->sample->loop_end;
ll = le - ls;
resrc.data_length = vp->sample->data_length;
while (count)
{
while (ofs >= le) { ofs -= ll; }
/* Precalc how many times we should go through the loop */
i = PRECALC_LOOP_COUNT(ofs, le, incr);
if (i > count) {
i = count;
count = 0;
}
else { count -= i; }
for (j = 0; j < i; j++) {
RESAMPLATION;
ofs += incr;
}
}
vp->sample_offset = ofs; /* Update offset */
return resample_buffer + resample_buffer_offset;
}
resample_t *Resampler::rs_bidir(Voice *vp, int32_t count)
{
int32_t
ofs = vp->sample_offset,
le = vp->sample->loop_end,
ls = vp->sample->loop_start;
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
int32_t incr = vp->sample_increment;
resample_rec_t resrc;
int32_t
le2 = le << 1,
ls2 = ls << 1;
int32_t i, j;
/* Play normally until inside the loop region */
resrc.loop_start = ls;
resrc.loop_end = le;
resrc.data_length = vp->sample->data_length;
if (incr > 0 && ofs < ls)
{
/* NOTE: Assumes that incr > 0, which is NOT always the case
when doing bidirectional looping. I have yet to see a case
where both ofs <= ls AND incr < 0, however. */
i = PRECALC_LOOP_COUNT(ofs, ls, incr);
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
for (j = 0; j < i; j++)
{
RESAMPLATION;
ofs += incr;
}
}
/* Then do the bidirectional looping */
while (count)
{
/* Precalc how many times we should go through the loop */
i = PRECALC_LOOP_COUNT(ofs, incr > 0 ? le : ls, incr);
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
for (j = 0; j < i; j++)
{
RESAMPLATION;
ofs += incr;
}
if (ofs >= 0 && ofs >= le)
{
/* fold the overshoot back in */
ofs = le2 - ofs;
incr *= -1;
}
else if (ofs <= 0 || ofs <= ls)
{
ofs = ls2 - ofs;
incr *= -1;
}
}
vp->sample_increment = incr;
vp->sample_offset = ofs; /* Update offset */
return resample_buffer + resample_buffer_offset;
}
/*********************** vibrato versions ***************************/
/* We only need to compute one half of the vibrato sine cycle */
static int vib_phase_to_inc_ptr(int phase)
{
if (phase < VIBRATO_SAMPLE_INCREMENTS / 2)
return VIBRATO_SAMPLE_INCREMENTS / 2 - 1 - phase;
else if (phase >= 3 * VIBRATO_SAMPLE_INCREMENTS / 2)
return 5 * VIBRATO_SAMPLE_INCREMENTS / 2 - 1 - phase;
else
return phase - VIBRATO_SAMPLE_INCREMENTS / 2;
}
int32_t Resampler::update_vibrato(Voice *vp, int sign)
{
int32_t depth;
int phase, pb;
double a;
int ch = vp->channel;
if (vp->vibrato_delay > 0)
{
vp->vibrato_delay -= vp->vibrato_control_ratio;
if (vp->vibrato_delay > 0)
return vp->sample_increment;
}
if (vp->vibrato_phase++ >= 2 * VIBRATO_SAMPLE_INCREMENTS - 1)
vp->vibrato_phase = 0;
phase = vib_phase_to_inc_ptr(vp->vibrato_phase);
if (vp->vibrato_sample_increment[phase])
{
if (sign)
return -vp->vibrato_sample_increment[phase];
else
return vp->vibrato_sample_increment[phase];
}
/* Need to compute this sample increment. */
depth = vp->vibrato_depth;
depth <<= 7;
if (vp->vibrato_sweep && !player->channel[ch].mod.val)
{
/* Need to update sweep */
vp->vibrato_sweep_position += vp->vibrato_sweep;
if (vp->vibrato_sweep_position >= (1 << SWEEP_SHIFT))
vp->vibrato_sweep = 0;
else
{
/* Adjust depth */
depth *= vp->vibrato_sweep_position;
depth >>= SWEEP_SHIFT;
}
}
if (vp->sample->inst_type == INST_SF2) {
pb = (int)((lookup_triangular(vp->vibrato_phase *
(SINE_CYCLE_LENGTH / (2 * VIBRATO_SAMPLE_INCREMENTS)))
* (double)(depth)* VIBRATO_AMPLITUDE_TUNING));
}
else {
pb = (int)((lookup_sine(vp->vibrato_phase *
(SINE_CYCLE_LENGTH / (2 * VIBRATO_SAMPLE_INCREMENTS)))
* (double)(depth)* VIBRATO_AMPLITUDE_TUNING));
}
a = TIM_FSCALE(((double)(vp->sample->sample_rate) *
(double)(vp->frequency)) /
((double)(vp->sample->root_freq) *
(double)(playback_rate)),
FRACTION_BITS);
if (pb < 0) {
pb = -pb;
a /= bend_fine[(pb >> 5) & 0xFF] * bend_coarse[pb >> 13];
pb = -pb;
}
else {
a *= bend_fine[(pb >> 5) & 0xFF] * bend_coarse[pb >> 13];
}
a += 0.5;
/* If the sweep's over, we can store the newly computed sample_increment */
if (!vp->vibrato_sweep || player->channel[ch].mod.val)
vp->vibrato_sample_increment[phase] = (int32_t)a;
if (sign)
a = -a; /* need to preserve the loop direction */
return (int32_t)a;
}
resample_t *Resampler::rs_vib_plain(int v, int32_t *countptr)
{
/* Play sample until end, then free the voice. */
Voice *vp = &player->voice[v];
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
splen_t
ls = 0,
le = vp->sample->data_length,
ofs = vp->sample_offset;
resample_rec_t resrc;
int32_t count = *countptr, incr = vp->sample_increment;
int cc = vp->vibrato_control_counter;
resrc.loop_start = ls;
resrc.loop_end = le;
resrc.data_length = vp->sample->data_length;
/* This has never been tested */
if (incr < 0) incr = -incr; /* In case we're coming out of a bidir loop */
while (count--)
{
if (!cc--)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, 0);
}
RESAMPLATION;
ofs += incr;
if (ofs >= le)
{
vp->timeout = 1;
*countptr -= count;
break;
}
}
vp->vibrato_control_counter = cc;
vp->sample_increment = incr;
vp->sample_offset = ofs; /* Update offset */
return resample_buffer + resample_buffer_offset;
}
resample_t *Resampler::rs_vib_loop(Voice *vp, int32_t count)
{
/* Play sample until end-of-loop, skip back and continue. */
splen_t
ofs = vp->sample_offset,
ls = vp->sample->loop_start,
le = vp->sample->loop_end,
ll = le - vp->sample->loop_start;
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
int cc = vp->vibrato_control_counter;
int32_t incr = vp->sample_increment;
resample_rec_t resrc;
int32_t i, j;
int vibflag = 0;
resrc.loop_start = ls;
resrc.loop_end = le;
resrc.data_length = vp->sample->data_length;
while (count)
{
/* Hopefully the loop is longer than an increment */
while (ofs >= le) { ofs -= ll; }
/* Precalc how many times to go through the loop, taking
the vibrato control ratio into account this time. */
i = PRECALC_LOOP_COUNT(ofs, le, incr);
if (i > count) {
i = count;
}
if (i > cc) {
i = cc;
vibflag = 1;
}
else { cc -= i; }
count -= i;
if (vibflag) {
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, 0);
vibflag = 0;
}
for (j = 0; j < i; j++) {
RESAMPLATION;
ofs += incr;
}
}
vp->vibrato_control_counter = cc;
vp->sample_increment = incr;
vp->sample_offset = ofs; /* Update offset */
return resample_buffer + resample_buffer_offset;
}
resample_t *Resampler::rs_vib_bidir(Voice *vp, int32_t count)
{
int32_t
ofs = vp->sample_offset,
le = vp->sample->loop_end,
ls = vp->sample->loop_start;
resample_t *dest = resample_buffer + resample_buffer_offset;
sample_t *src = vp->sample->data;
int cc = vp->vibrato_control_counter;
int32_t incr = vp->sample_increment;
resample_rec_t resrc;
resrc.loop_start = ls;
resrc.loop_end = le;
resrc.data_length = vp->sample->data_length;
/* Play normally until inside the loop region */
if (ofs < ls)
{
while (count--)
{
if (!cc--)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, 0);
}
RESAMPLATION;
ofs += incr;
if (ofs >= ls)
break;
}
}
/* Then do the bidirectional looping */
if (count > 0)
while (count--)
{
if (!cc--)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, (incr < 0));
}
RESAMPLATION;
ofs += incr;
if (ofs >= le)
{
/* fold the overshoot back in */
ofs = le - (ofs - le);
incr = -incr;
}
else if (ofs <= ls)
{
ofs = ls + (ls - ofs);
incr = -incr;
}
}
/* Update changed values */
vp->vibrato_control_counter = cc;
vp->sample_increment = incr;
vp->sample_offset = ofs;
return resample_buffer + resample_buffer_offset;
}
/*********************** portamento versions ***************************/
int Resampler::rs_update_porta(int v)
{
Voice *vp = &player->voice[v];
int32_t d;
d = vp->porta_dpb;
if (vp->porta_pb < 0)
{
if (d > -vp->porta_pb)
d = -vp->porta_pb;
}
else
{
if (d > vp->porta_pb)
d = -vp->porta_pb;
else
d = -d;
}
vp->porta_pb += d;
if (vp->porta_pb == 0)
{
vp->porta_control_ratio = 0;
vp->porta_pb = 0;
}
player->recompute_freq(v);
return vp->porta_control_ratio;
}
resample_t *Resampler::porta_resample_voice(int v, int32_t *countptr, int mode)
{
Voice *vp = &player->voice[v];
int32_t n = *countptr, i;
resample_t *(Resampler::*resampler)(int, int32_t *, int);
int cc = vp->porta_control_counter;
int loop;
if (vp->vibrato_control_ratio)
resampler = &Resampler::vib_resample_voice;
else
resampler = &Resampler::normal_resample_voice;
if (mode != 1)
loop = 1;
else
loop = 0;
vp->cache = NULL;
resample_buffer_offset = 0;
while (resample_buffer_offset < n)
{
if (cc == 0)
{
if ((cc = rs_update_porta(v)) == 0)
{
i = n - resample_buffer_offset;
(this->*resampler)(v, &i, mode);
resample_buffer_offset += i;
break;
}
}
i = n - resample_buffer_offset;
if (i > cc)
i = cc;
(this->*resampler)(v, &i, mode);
resample_buffer_offset += i;
if (!loop && (i == 0 || vp->status == VOICE_FREE))
break;
cc -= i;
}
*countptr = resample_buffer_offset;
resample_buffer_offset = 0;
vp->porta_control_counter = cc;
return resample_buffer;
}
/* interface function */
resample_t *Resampler::vib_resample_voice(int v, int32_t *countptr, int mode)
{
Voice *vp = &player->voice[v];
vp->cache = NULL;
if (mode == 0)
return rs_vib_loop(vp, *countptr);
if (mode == 1)
return rs_vib_plain(v, countptr);
return rs_vib_bidir(vp, *countptr);
}
/* interface function */
resample_t *Resampler::normal_resample_voice(int v, int32_t *countptr, int mode)
{
Voice *vp = &player->voice[v];
if (mode == 0)
return rs_loop(vp, *countptr);
if (mode == 1)
return rs_plain(v, countptr);
return rs_bidir(vp, *countptr);
}
/* interface function */
resample_t *Resampler::resample_voice(int v, int32_t *countptr)
{
Voice *vp = &player->voice[v];
int mode;
resample_t *result;
int32_t i;
if (vp->sample->sample_rate == playback_rate &&
vp->sample->root_freq == get_note_freq(vp->sample, vp->sample->note_to_use) &&
vp->frequency == vp->orig_frequency)
{
int32_t ofs;
/* Pre-resampled data -- just update the offset and check if
we're out of data. */
ofs = (int32_t)(vp->sample_offset >> FRACTION_BITS); /* Kind of silly to use
FRACTION_BITS here... */
if (*countptr >= (int32_t)((vp->sample->data_length >> FRACTION_BITS) - ofs))
{
/* Note finished. Free the voice. */
vp->timeout = 1;
/* Let the caller know how much data we had left */
*countptr = (int32_t)(vp->sample->data_length >> FRACTION_BITS) - ofs;
}
else
vp->sample_offset += *countptr << FRACTION_BITS;
for (i = 0; i < *countptr; i++) {
resample_buffer[i] = vp->sample->data[i + ofs];
}
return resample_buffer;
}
mode = vp->sample->modes;
if ((mode & MODES_LOOPING) &&
((mode & MODES_ENVELOPE) ||
(vp->status & (VOICE_ON | VOICE_SUSTAINED))))
{
if (mode & MODES_PINGPONG)
{
vp->cache = NULL;
mode = 2; /* Bidir loop */
}
else
mode = 0; /* loop */
}
else
mode = 1; /* no loop */
if (vp->porta_control_ratio)
result = porta_resample_voice(v, countptr, mode);
else if (vp->vibrato_control_ratio)
result = vib_resample_voice(v, countptr, mode);
else
result = normal_resample_voice(v, countptr, mode);
return result;
}
void pre_resample(Sample * sp)
{
double a, b;
splen_t ofs, newlen;
sample_t *newdata, *dest, *src = (sample_t *)sp->data;
int32_t i, count, incr, f, x;
resample_rec_t resrc;
f = get_note_freq(sp, sp->note_to_use);
a = b = ((double)(sp->root_freq) * playback_rate) /
((double)(sp->sample_rate) * f);
if ((int64_t)sp->data_length * a >= 0x7fffffffL)
{
/* Too large to compute */
ctl_cmsg(CMSG_INFO, VERB_DEBUG, " *** Can't pre-resampling for note %d",
sp->note_to_use);
return;
}
newlen = (splen_t)(sp->data_length * a);
count = (newlen >> FRACTION_BITS);
ofs = incr = (sp->data_length - 1) / (count - 1);
if ((double)newlen + incr >= 0x7fffffffL)
{
/* Too large to compute */
ctl_cmsg(CMSG_INFO, VERB_DEBUG, " *** Can't pre-resampling for note %d",
sp->note_to_use);
return;
}
dest = newdata = (sample_t *)safe_malloc((int32_t)(newlen >> (FRACTION_BITS - 1)) + 2);
dest[newlen >> FRACTION_BITS] = 0;
*dest++ = src[0];
resrc.loop_start = 0;
resrc.loop_end = sp->data_length;
resrc.data_length = sp->data_length;
/* Since we're pre-processing and this doesn't have to be done in
real-time, we go ahead and do the higher order interpolation. */
for (i = 1; i < count; i++)
{
x = resample_gauss(src, ofs, &resrc);
*dest++ = (int16_t)((x > 32767) ? 32767 : ((x < -32768) ? -32768 : x));
ofs += incr;
}
sp->data_length = newlen;
sp->loop_start = (splen_t)(sp->loop_start * b);
sp->loop_end = (splen_t)(sp->loop_end * b);
free(sp->data);
sp->data = (sample_t *)newdata;
sp->root_freq = f;
sp->sample_rate = playback_rate;
sp->low_freq = freq_table[0];
sp->high_freq = freq_table[127];
}
}

View File

@ -0,0 +1,88 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
resample.h
*/
#ifndef ___RESAMPLE_H_
#define ___RESAMPLE_H_
#include <stdint.h>
#include "sysdep.h"
namespace TimidityPlus
{
typedef int32_t resample_t;
enum {
RESAMPLE_CSPLINE,
RESAMPLE_LAGRANGE,
RESAMPLE_GAUSS,
RESAMPLE_NEWTON,
RESAMPLE_LINEAR,
RESAMPLE_NONE
};
extern void initialize_resampler_coeffs(void);
extern void free_gauss_table(void);
typedef struct resample_rec {
splen_t loop_start;
splen_t loop_end;
splen_t data_length;
} resample_rec_t;
extern resample_t do_resamplation(sample_t *src, splen_t ofs, resample_rec_t *rec);
extern void pre_resample(Sample *sp);
class Player;
class Resampler // This is only here to put the buffer on the stack without changing all the code.
{
Player *player;
resample_t resample_buffer[AUDIO_BUFFER_SIZE] = { 0 };
int resample_buffer_offset = 0;
resample_t *rs_plain_c(int v, int32_t *countptr);
resample_t *rs_plain(int v, int32_t *countptr);
resample_t *rs_loop_c(Voice *vp, int32_t count);
resample_t *rs_loop(Voice *vp, int32_t count);
resample_t *rs_bidir(Voice *vp, int32_t count);
resample_t *rs_vib_plain(int v, int32_t *countptr);
resample_t *rs_vib_loop(Voice *vp, int32_t count);
resample_t *rs_vib_bidir(Voice *vp, int32_t count);
resample_t *porta_resample_voice(int v, int32_t *countptr, int mode);
resample_t *normal_resample_voice(int v, int32_t *countptr, int mode);
resample_t *vib_resample_voice(int v, int32_t *countptr, int mode);
int rs_update_porta(int v);
int32_t update_vibrato(Voice *vp, int sign);
public:
Resampler(Player *p)
{
player = p;
}
resample_t * resample_voice(int v, int32_t *countptr);
};
}
#endif /* ___RESAMPLE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,814 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* REVERB EFFECT FOR TIMIDITY++-1.X (Version 0.06e 1999/1/28)
*
* Copyright (C) 1997,1998,1999 Masaki Kiryu <mkiryu@usa.net>
* (http://w3mb.kcom.ne.jp/~mkiryu/)
*
* reverb.h
*
*/
#ifndef ___REVERB_H_
#define ___REVERB_H_
#include <stdint.h>
namespace TimidityPlus
{
#define DEFAULT_REVERB_SEND_LEVEL 40
/* */
/* Effect Utitities */
/* */
/*! simple delay */
typedef struct {
int32_t *buf, size, index;
} simple_delay;
/*! Pink Noise Generator */
typedef struct {
float b0, b1, b2, b3, b4, b5, b6;
} pink_noise;
#ifndef SINE_CYCLE_LENGTH
#define SINE_CYCLE_LENGTH 1024
#endif
/*! LFO */
typedef struct {
int32_t buf[SINE_CYCLE_LENGTH];
int32_t count, cycle; /* in samples */
int32_t icycle; /* proportional to (SINE_CYCLE_LENGTH / cycle) */
int type; /* current content of its buffer */
double freq; /* in Hz */
} lfo;
enum {
LFO_NONE = 0,
LFO_SINE,
LFO_TRIANGULAR,
};
/*! modulated delay with allpass interpolation */
typedef struct {
int32_t *buf, size, rindex, windex, hist;
int32_t ndelay, depth; /* in samples */
} mod_delay;
/*! modulated allpass filter with allpass interpolation */
typedef struct {
int32_t *buf, size, rindex, windex, hist;
int32_t ndelay, depth; /* in samples */
double feedback;
int32_t feedbacki;
} mod_allpass;
/*! Moog VCF (resonant IIR state variable filter) */
typedef struct {
int16_t freq, last_freq; /* in Hz */
double res_dB, last_res_dB; /* in dB */
int32_t f, q, p; /* coefficients in fixed-point */
int32_t b0, b1, b2, b3, b4;
} filter_moog;
/*! Moog VCF (resonant IIR state variable filter with distortion) */
typedef struct {
int16_t freq, last_freq; /* in Hz */
double res_dB, last_res_dB; /* in dB */
double dist, last_dist, f, q, p, d, b0, b1, b2, b3, b4;
} filter_moog_dist;
/*! LPF18 (resonant IIR lowpass filter with waveshaping) */
typedef struct {
int16_t freq, last_freq; /* in Hz */
double dist, res, last_dist, last_res; /* in linear */
double ay1, ay2, aout, lastin, kres, value, kp, kp1h;
} filter_lpf18;
/*! 1st order lowpass filter */
typedef struct {
double a;
int32_t ai, iai; /* coefficients in fixed-point */
int32_t x1l, x1r;
} filter_lowpass1;
/*! lowpass / highpass filter */
typedef struct {
double freq, q, last_freq, last_q;
int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r;
int32_t a1, a2, b1, b02;
} filter_biquad;
#ifndef PART_EQ_XG
#define PART_EQ_XG
/*! shelving filter */
typedef struct {
double freq, gain, q;
int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r;
int32_t a1, a2, b0, b1, b2;
} filter_shelving;
struct part_eq_xg {
int8_t bass, treble, bass_freq, treble_freq;
filter_shelving basss, trebles;
int8_t valid;
};
#endif /* PART_EQ_XG */
/*! peaking filter */
typedef struct {
double freq, gain, q;
int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r;
int32_t ba1, a2, b0, b2;
} filter_peaking;
/*! allpass filter */
typedef struct _allpass {
int32_t *buf, size, index;
double feedback;
int32_t feedbacki;
} allpass;
/*! comb filter */
typedef struct _comb {
int32_t *buf, filterstore, size, index;
double feedback, damp1, damp2;
int32_t feedbacki, damp1i, damp2i;
} comb;
/* */
/* Insertion and Variation Effect */
/* */
struct effect_xg_t {
int8_t use_msb, type_msb, type_lsb, param_lsb[16], param_msb[10],
ret, pan, send_reverb, send_chorus, connection, part,
mw_depth, bend_depth, cat_depth, ac1_depth, ac2_depth, cbc1_depth,
cbc2_depth;
struct _EffectList *ef;
};
enum {
EFFECT_NONE,
EFFECT_EQ2,
EFFECT_EQ3,
EFFECT_STEREO_EQ,
EFFECT_OVERDRIVE1,
EFFECT_DISTORTION1,
EFFECT_OD1OD2,
EFFECT_CHORUS,
EFFECT_FLANGER,
EFFECT_SYMPHONIC,
EFFECT_CHORUS_EQ3,
EFFECT_STEREO_OVERDRIVE,
EFFECT_STEREO_DISTORTION,
EFFECT_STEREO_AMP_SIMULATOR,
EFFECT_OD_EQ3,
EFFECT_HEXA_CHORUS,
EFFECT_DELAY_LCR,
EFFECT_DELAY_LR,
EFFECT_ECHO,
EFFECT_CROSS_DELAY,
EFFECT_DELAY_EQ2,
EFFECT_LOFI,
EFFECT_LOFI1,
EFFECT_LOFI2,
EFFECT_XG_AUTO_WAH,
EFFECT_XG_AUTO_WAH_EQ2,
EFFECT_XG_AUTO_WAH_OD,
EFFECT_XG_AUTO_WAH_OD_EQ3,
};
#define MAGIC_INIT_EFFECT_INFO -1
#define MAGIC_FREE_EFFECT_INFO -2
class Reverb;
struct insertion_effect_gs_t {
int32_t type;
int8_t type_lsb, type_msb, parameter[20], send_reverb,
send_chorus, send_delay, control_source1, control_depth1,
control_source2, control_depth2, send_eq_switch;
struct _EffectList *ef;
};
enum {
XG_CONN_INSERTION = 0,
XG_CONN_SYSTEM = 1,
XG_CONN_SYSTEM_CHORUS,
XG_CONN_SYSTEM_REVERB,
};
#define XG_INSERTION_EFFECT_NUM 2
#define XG_VARIATION_EFFECT_NUM 1
typedef struct _EffectList {
int type;
void *info;
const struct _EffectEngine *engine;
struct _EffectList *next_ef;
} EffectList;
struct _EffectEngine {
int type;
const char *name;
void (Reverb::*do_effect)(int32_t *, int32_t, struct _EffectList *);
void (Reverb::*conv_gs)(struct insertion_effect_gs_t *, struct _EffectList *);
void (Reverb::*conv_xg)(struct effect_xg_t *, struct _EffectList *);
int info_size;
};
struct effect_parameter_gs_t {
int8_t type_msb, type_lsb;
const char *name;
int8_t param[20];
int8_t control1, control2;
};
struct effect_parameter_xg_t {
int8_t type_msb, type_lsb;
const char *name;
int8_t param_msb[10], param_lsb[16];
int8_t control;
};
/*! 2-Band EQ */
typedef struct {
int16_t low_freq, high_freq; /* in Hz */
int16_t low_gain, high_gain; /* in dB */
filter_shelving hsf, lsf;
} InfoEQ2;
/*! 3-Band EQ */
typedef struct {
int16_t low_freq, high_freq, mid_freq; /* in Hz */
int16_t low_gain, high_gain, mid_gain; /* in dB */
double mid_width;
filter_shelving hsf, lsf;
filter_peaking peak;
} InfoEQ3;
/*! Stereo EQ */
typedef struct {
int16_t low_freq, high_freq, m1_freq, m2_freq; /* in Hz */
int16_t low_gain, high_gain, m1_gain, m2_gain; /* in dB */
double m1_q, m2_q, level;
int32_t leveli;
filter_shelving hsf, lsf;
filter_peaking m1, m2;
} InfoStereoEQ;
/*! Overdrive 1 / Distortion 1 */
typedef struct {
double level;
int32_t leveli, di; /* in fixed-point */
int8_t drive, pan, amp_sw, amp_type;
filter_moog svf;
filter_biquad lpf1;
void (Reverb::*amp_sim)(int32_t *, int32_t);
} InfoOverdrive1;
/*! OD1 / OD2 */
typedef struct {
double level, levell, levelr;
int32_t levelli, levelri, dli, dri; /* in fixed-point */
int8_t drivel, driver, panl, panr, typel, typer, amp_swl, amp_swr, amp_typel, amp_typer;
filter_moog svfl, svfr;
filter_biquad lpf1;
void (Reverb::*amp_siml)(int32_t *, int32_t), (Reverb::*amp_simr)(int32_t *, int32_t);
void (Reverb::*odl)(int32_t *, int32_t), (Reverb::*odr)(int32_t *, int32_t);
} InfoOD1OD2;
/*! HEXA-CHORUS */
typedef struct {
simple_delay buf0;
lfo lfo0;
double dry, wet, level;
int32_t pdelay, depth; /* in samples */
int8_t pdelay_dev, depth_dev, pan_dev;
int32_t dryi, weti; /* in fixed-point */
int32_t pan0, pan1, pan2, pan3, pan4, pan5;
int32_t depth0, depth1, depth2, depth3, depth4, depth5,
pdelay0, pdelay1, pdelay2, pdelay3, pdelay4, pdelay5;
int32_t spt0, spt1, spt2, spt3, spt4, spt5,
hist0, hist1, hist2, hist3, hist4, hist5;
} InfoHexaChorus;
/*! Plate Reverb */
typedef struct {
simple_delay pd, od1l, od2l, od3l, od4l, od5l, od6l, od7l,
od1r, od2r, od3r, od4r, od5r, od6r, od7r,
td1, td2, td1d, td2d;
lfo lfo1, lfo1d;
allpass ap1, ap2, ap3, ap4, ap6, ap6d;
mod_allpass ap5, ap5d;
filter_lowpass1 lpf1, lpf2;
int32_t t1, t1d;
double decay, ddif1, ddif2, idif1, idif2, dry, wet;
int32_t decayi, ddif1i, ddif2i, idif1i, idif2i, dryi, weti;
} InfoPlateReverb;
/*! Standard Reverb */
typedef struct {
int32_t spt0, spt1, spt2, spt3, rpt0, rpt1, rpt2, rpt3;
int32_t ta, tb, HPFL, HPFR, LPFL, LPFR, EPFL, EPFR;
simple_delay buf0_L, buf0_R, buf1_L, buf1_R, buf2_L, buf2_R, buf3_L, buf3_R;
double fbklev, nmixlev, cmixlev, monolev, hpflev, lpflev, lpfinp, epflev, epfinp, width, wet;
int32_t fbklevi, nmixlevi, cmixlevi, monolevi, hpflevi, lpflevi, lpfinpi, epflevi, epfinpi, widthi, weti;
} InfoStandardReverb;
/*! Freeverb */
#define numcombs 8
#define numallpasses 4
typedef struct {
simple_delay pdelay;
double roomsize, roomsize1, damp, damp1, wet, wet1, wet2, width;
comb combL[numcombs], combR[numcombs];
allpass allpassL[numallpasses], allpassR[numallpasses];
int32_t wet1i, wet2i;
int8_t alloc_flag;
} InfoFreeverb;
/*! 3-Tap Stereo Delay Effect */
typedef struct {
simple_delay delayL, delayR;
int32_t size[3], index[3];
double level[3], feedback, send_reverb;
int32_t leveli[3], feedbacki, send_reverbi;
} InfoDelay3;
/*! Stereo Chorus Effect */
typedef struct {
simple_delay delayL, delayR;
lfo lfoL, lfoR;
int32_t wpt0, spt0, spt1, hist0, hist1;
int32_t rpt0, depth, pdelay;
double level, feedback, send_reverb, send_delay;
int32_t leveli, feedbacki, send_reverbi, send_delayi;
} InfoStereoChorus;
/*! Chorus */
typedef struct {
simple_delay delayL, delayR;
lfo lfoL, lfoR;
int32_t wpt0, spt0, spt1, hist0, hist1;
int32_t rpt0, depth, pdelay;
double dry, wet, feedback, pdelay_ms, depth_ms, rate, phase_diff;
int32_t dryi, weti, feedbacki;
} InfoChorus;
/*! Stereo Overdrive / Distortion */
typedef struct {
double level, dry, wet, drive, cutoff;
int32_t dryi, weti, di;
filter_moog svfl, svfr;
filter_biquad lpf1;
void (Reverb::*od)(int32_t *, int32_t);
} InfoStereoOD;
/*! Delay L,C,R */
typedef struct {
simple_delay delayL, delayR;
int32_t index[3], size[3]; /* L,C,R */
double rdelay, ldelay, cdelay, fdelay; /* in ms */
double dry, wet, feedback, clevel, high_damp;
int32_t dryi, weti, feedbacki, cleveli;
filter_lowpass1 lpf;
} InfoDelayLCR;
/*! Delay L,R */
typedef struct {
simple_delay delayL, delayR;
int32_t index[2], size[2]; /* L,R */
double rdelay, ldelay, fdelay1, fdelay2; /* in ms */
double dry, wet, feedback, high_damp;
int32_t dryi, weti, feedbacki;
filter_lowpass1 lpf;
} InfoDelayLR;
/*! Echo */
typedef struct {
simple_delay delayL, delayR;
int32_t index[2], size[2]; /* L1,R1 */
double rdelay1, ldelay1, rdelay2, ldelay2; /* in ms */
double dry, wet, lfeedback, rfeedback, high_damp, level;
int32_t dryi, weti, lfeedbacki, rfeedbacki, leveli;
filter_lowpass1 lpf;
} InfoEcho;
/*! Cross Delay */
typedef struct {
simple_delay delayL, delayR;
double lrdelay, rldelay; /* in ms */
double dry, wet, feedback, high_damp;
int32_t dryi, weti, feedbacki, input_select;
filter_lowpass1 lpf;
} InfoCrossDelay;
/*! Lo-Fi 1 */
typedef struct {
int8_t lofi_type, pan, pre_filter, post_filter;
double level, dry, wet;
int32_t bit_mask, level_shift, dryi, weti;
filter_biquad pre_fil, post_fil;
} InfoLoFi1;
/*! Lo-Fi 2 */
typedef struct {
int8_t wp_sel, disc_type, hum_type, ms, pan, rdetune, lofi_type, fil_type;
double wp_level, rnz_lev, discnz_lev, hum_level, dry, wet, level;
int32_t bit_mask, level_shift, wp_leveli, rnz_levi, discnz_levi, hum_keveki, dryi, weti;
filter_biquad fil, wp_lpf, hum_lpf, disc_lpf;
} InfoLoFi2;
/*! LO-FI */
typedef struct {
int8_t output_gain, word_length, filter_type, bit_assign, emphasis;
double dry, wet;
int32_t bit_mask, level_shift, dryi, weti;
filter_biquad lpf, srf;
} InfoLoFi;
/*! XG: Auto Wah */
typedef struct {
int8_t lfo_depth, drive;
double resonance, lfo_freq, offset_freq, dry, wet;
int32_t dryi, weti, fil_count, fil_cycle;
lfo lfo;
filter_moog_dist fil0, fil1;
} InfoXGAutoWah;
typedef struct {
double level;
int32_t leveli;
filter_biquad lpf;
} InfoXGAutoWahOD;
/* GS parameters of reverb effect */
struct reverb_status_gs_t
{
/* GS parameters */
int8_t character, pre_lpf, level, time, delay_feedback, pre_delay_time;
InfoStandardReverb info_standard_reverb;
InfoPlateReverb info_plate_reverb;
InfoFreeverb info_freeverb;
InfoDelay3 info_reverb_delay;
filter_lowpass1 lpf;
};
struct chorus_text_gs_t
{
int status;
uint8_t voice_reserve[18], macro[3], pre_lpf[3], level[3], feed_back[3],
delay[3], rate[3], depth[3], send_level[3];
};
/* GS parameters of chorus effect */
struct chorus_status_gs_t
{
/* GS parameters */
int8_t macro, pre_lpf, level, feedback, delay, rate, depth, send_reverb, send_delay;
//struct chorus_text_gs_t text;
InfoStereoChorus info_stereo_chorus;
filter_lowpass1 lpf;
};
/* GS parameters of delay effect */
struct delay_status_gs_t
{
/* GS parameters */
int8_t type, level, level_center, level_left, level_right,
feedback, pre_lpf, send_reverb, time_c, time_l, time_r;
double time_center; /* in ms */
double time_ratio_left, time_ratio_right; /* in pct */
/* for pre-calculation */
int32_t sample[3]; /* center, left, right */
double level_ratio[3]; /* center, left, right */
double feedback_ratio, send_reverb_ratio;
filter_lowpass1 lpf;
InfoDelay3 info_delay;
};
/* GS parameters of channel EQ */
struct eq_status_gs_t
{
/* GS parameters */
int8_t low_freq, high_freq, low_gain, high_gain;
filter_shelving hsf, lsf;
};
/* XG parameters of Multi EQ */
struct multi_eq_xg_t
{
/* XG parameters */
int8_t type, gain1, gain2, gain3, gain4, gain5,
freq1, freq2, freq3, freq4, freq5,
q1, q2, q3, q4, q5, shape1, shape5;
int8_t valid, valid1, valid2, valid3, valid4, valid5;
filter_shelving eq1s, eq5s;
filter_peaking eq1p, eq2p, eq3p, eq4p, eq5p;
};
class Reverb
{
double REV_INP_LEV;
int32_t direct_buffer[AUDIO_BUFFER_SIZE * 2];
int32_t direct_bufsize;
int32_t reverb_effect_buffer[AUDIO_BUFFER_SIZE * 2];
int32_t reverb_effect_bufsize;
int32_t delay_effect_buffer[AUDIO_BUFFER_SIZE * 2];
int32_t chorus_effect_buffer[AUDIO_BUFFER_SIZE * 2];
int32_t eq_buffer[AUDIO_BUFFER_SIZE * 2];
static const struct _EffectEngine effect_engine[];
void free_delay(simple_delay *delay);
void set_delay(simple_delay *delay, int32_t size);
void do_delay(int32_t *stream, int32_t *buf, int32_t size, int32_t *index);
void init_lfo(lfo *lfo, double freq, int type, double phase);
int32_t do_lfo(lfo *lfo);
void do_mod_delay(int32_t *stream, int32_t *buf, int32_t size, int32_t *rindex, int32_t *windex, int32_t ndelay, int32_t depth, int32_t lfoval, int32_t *hist);
void free_mod_allpass(mod_allpass *delay);
void set_mod_allpass(mod_allpass *delay, int32_t ndelay, int32_t depth, double feedback);
void do_mod_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *rindex, int32_t *windex, int32_t ndelay, int32_t depth, int32_t lfoval, int32_t *hist, int32_t feedback);
void free_allpass(allpass *allpass);
void set_allpass(allpass *allpass, int32_t size, double feedback);
void do_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t feedback);
void init_filter_moog(filter_moog *svf);
void calc_filter_moog(filter_moog *svf);
void do_filter_moog(int32_t *stream, int32_t *high, int32_t f, int32_t p, int32_t q, int32_t *b0, int32_t *b1, int32_t *b2, int32_t *b3, int32_t *b4);
void init_filter_moog_dist(filter_moog_dist *svf);
void calc_filter_moog_dist(filter_moog_dist *svf);
void do_filter_moog_dist(double *stream, double *high, double *band, double f, double p, double q, double d, double *b0, double *b1, double *b2, double *b3, double *b4);
void do_filter_moog_dist_band(double *stream, double f, double p, double q, double d, double *b0, double *b1, double *b2, double *b3, double *b4);
void init_filter_lpf18(filter_lpf18 *p);
void calc_filter_lpf18(filter_lpf18 *p);
void do_filter_lpf18(double *stream, double *ay1, double *ay2, double *aout, double *lastin, double kres, double value, double kp, double kp1h);
void do_dummy_clipping(int32_t *stream, int32_t d) {}
void do_hard_clipping(int32_t *stream, int32_t d);
void do_soft_clipping1(int32_t *stream, int32_t d);
void do_soft_clipping2(int32_t *stream, int32_t d);
void do_filter_lowpass1(int32_t *stream, int32_t *x1, int32_t a, int32_t ia);
void do_filter_lowpass1_stereo(int32_t *buf, int32_t count, filter_lowpass1 *p);
void init_filter_biquad(filter_biquad *p);
void calc_filter_biquad_low(filter_biquad *p);
void calc_filter_biquad_high(filter_biquad *p);
void do_filter_biquad(int32_t *stream, int32_t a1, int32_t a2, int32_t b1, int32_t b02, int32_t *x1, int32_t *x2, int32_t *y1, int32_t *y2);
void init_filter_shelving(filter_shelving *p);
void do_shelving_filter_stereo(int32_t* buf, int32_t count, filter_shelving *p);
void do_peaking_filter_stereo(int32_t* buf, int32_t count, filter_peaking *p);
double gs_revchar_to_roomsize(int character);
double gs_revchar_to_level(int character);
double gs_revchar_to_rt(int character);
void init_filter_peaking(filter_peaking *p);
void init_standard_reverb(InfoStandardReverb *info);
void free_standard_reverb(InfoStandardReverb *info);
void do_ch_standard_reverb(int32_t *buf, int32_t count, InfoStandardReverb *info);
void do_ch_standard_reverb_mono(int32_t *buf, int32_t count, InfoStandardReverb *info);
void set_freeverb_allpass(allpass *allpass, int32_t size);
void init_freeverb_allpass(allpass *allpass);
void set_freeverb_comb(comb *comb, int32_t size);
void init_freeverb_comb(comb *comb);
void realloc_freeverb_buf(InfoFreeverb *rev);
void update_freeverb(InfoFreeverb *rev);
void init_freeverb(InfoFreeverb *rev);
void alloc_freeverb_buf(InfoFreeverb *rev);
void free_freeverb_buf(InfoFreeverb *rev);
void do_freeverb_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t feedback);
void do_freeverb_comb(int32_t input, int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t damp1, int32_t damp2, int32_t *fs, int32_t feedback);
void do_ch_freeverb(int32_t *buf, int32_t count, InfoFreeverb *rev);
void init_ch_reverb_delay(InfoDelay3 *info);
void free_ch_reverb_delay(InfoDelay3 *info);
void do_ch_reverb_panning_delay(int32_t *buf, int32_t count, InfoDelay3 *info);
void do_ch_reverb_normal_delay(int32_t *buf, int32_t count, InfoDelay3 *info);
int32_t get_plate_delay(double delay, double t);
void do_ch_plate_reverb(int32_t *buf, int32_t count, InfoPlateReverb *info);
void init_ch_3tap_delay(InfoDelay3 *info);
void free_ch_3tap_delay(InfoDelay3 *info);
void do_ch_3tap_delay(int32_t *buf, int32_t count, InfoDelay3 *info);
void do_ch_cross_delay(int32_t *buf, int32_t count, InfoDelay3 *info);
void do_ch_normal_delay(int32_t *buf, int32_t count, InfoDelay3 *info);
void do_ch_stereo_chorus(int32_t *buf, int32_t count, InfoStereoChorus *info);
void alloc_effect(EffectList *ef);
void do_eq2(int32_t *buf, int32_t count, EffectList *ef);
int32_t do_left_panning(int32_t sample, int32_t pan);
int32_t do_right_panning(int32_t sample, int32_t pan);
double calc_gs_drive(int val);
void do_overdrive1(int32_t *buf, int32_t count, EffectList *ef);
void do_distortion1(int32_t *buf, int32_t count, EffectList *ef);
void do_dual_od(int32_t *buf, int32_t count, EffectList *ef);
void do_hexa_chorus(int32_t *buf, int32_t count, EffectList *ef);
void free_effect_xg(struct effect_xg_t *st);
int clip_int(int val, int min, int max);
void conv_gs_eq2(struct insertion_effect_gs_t *ieffect, EffectList *ef);
void conv_gs_overdrive1(struct insertion_effect_gs_t *ieffect, EffectList *ef);
void conv_gs_dual_od(struct insertion_effect_gs_t *ieffect, EffectList *ef);
double calc_dry_gs(int val);
double calc_wet_gs(int val);
void conv_gs_hexa_chorus(struct insertion_effect_gs_t *ieffect, EffectList *ef);
double calc_dry_xg(int val, struct effect_xg_t *st);
double calc_wet_xg(int val, struct effect_xg_t *st);
void do_eq3(int32_t *buf, int32_t count, EffectList *ef);
void do_stereo_eq(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_eq2(struct effect_xg_t *st, EffectList *ef);
void conv_xg_eq3(struct effect_xg_t *st, EffectList *ef);
void conv_gs_stereo_eq(struct insertion_effect_gs_t *st, EffectList *ef);
void conv_xg_chorus_eq3(struct effect_xg_t *st, EffectList *ef);
void conv_xg_chorus(struct effect_xg_t *st, EffectList *ef);
void conv_xg_flanger(struct effect_xg_t *st, EffectList *ef);
void conv_xg_symphonic(struct effect_xg_t *st, EffectList *ef);
void do_chorus(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_od_eq3(struct effect_xg_t *st, EffectList *ef);
void conv_xg_overdrive(struct effect_xg_t *st, EffectList *ef);
void conv_xg_distortion(struct effect_xg_t *st, EffectList *ef);
void conv_xg_amp_simulator(struct effect_xg_t *st, EffectList *ef);
void do_stereo_od(int32_t *buf, int32_t count, EffectList *ef);
void do_delay_lcr(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_delay_eq2(struct effect_xg_t *st, EffectList *ef);
void conv_xg_delay_lcr(struct effect_xg_t *st, EffectList *ef);
void conv_xg_delay_lr(struct effect_xg_t *st, EffectList *ef);
void do_delay_lr(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_echo(struct effect_xg_t *st, EffectList *ef);
void do_echo(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_cross_delay(struct effect_xg_t *st, EffectList *ef);
void do_cross_delay(int32_t *buf, int32_t count, EffectList *ef);
void conv_gs_lofi1(struct insertion_effect_gs_t *st, EffectList *ef);
inline int32_t apply_lofi(int32_t input, int32_t bit_mask, int32_t level_shift);
void do_lofi1(int32_t *buf, int32_t count, EffectList *ef);
void conv_gs_lofi2(struct insertion_effect_gs_t *st, EffectList *ef);
void do_lofi2(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_lofi(struct effect_xg_t *st, EffectList *ef);
void do_lofi(int32_t *buf, int32_t count, EffectList *ef);
void conv_xg_auto_wah_od(struct effect_xg_t *st, EffectList *ef);
void conv_xg_auto_wah_od_eq3(struct effect_xg_t *st, EffectList *ef);
void conv_xg_auto_wah_eq2(struct effect_xg_t *st, EffectList *ef);
void conv_xg_auto_wah(struct effect_xg_t *st, EffectList *ef);
double calc_xg_auto_wah_freq(int32_t lfo_val, double offset_freq, int8_t depth);
void do_xg_auto_wah(int32_t *buf, int32_t count, EffectList *ef);
void do_xg_auto_wah_od(int32_t *buf, int32_t count, EffectList *ef);
public:
Reverb()
{
// Make sure that this starts out with all zeros.
memset(this, 0, sizeof(*this));
REV_INP_LEV = 1.0;
direct_bufsize = sizeof(direct_buffer);
reverb_effect_bufsize = sizeof(reverb_effect_buffer);
}
~Reverb()
{
free_effect_buffers();
}
void set_dry_signal(int32_t *, int32_t);
void set_dry_signal_xg(int32_t *, int32_t, int32_t);
void mix_dry_signal(int32_t *, int32_t);
void free_effect_buffers(void);
void init_pink_noise(pink_noise *);
float get_pink_noise(pink_noise *);
float get_pink_noise_light(pink_noise *);
void calc_filter_shelving_high(filter_shelving *);
void calc_filter_shelving_low(filter_shelving *);
void calc_filter_peaking(filter_peaking *);
void do_insertion_effect_gs(int32_t*, int32_t);
void do_insertion_effect_xg(int32_t*, int32_t, struct effect_xg_t *);
void do_variation_effect1_xg(int32_t*, int32_t);
void init_ch_effect_xg(void);
EffectList *push_effect(EffectList *, int);
void do_effect_list(int32_t *, int32_t, EffectList *);
void free_effect_list(EffectList *);
void init_filter_lowpass1(filter_lowpass1 *p);
/* */
/* System Effect */
/* */
/* Reverb Effect */
void do_ch_reverb(int32_t *, int32_t);
void set_ch_reverb(int32_t *, int32_t, int32_t);
void init_reverb(void);
void do_ch_reverb_xg(int32_t *, int32_t);
/* Chorus Effect */
void do_ch_chorus(int32_t *, int32_t);
void set_ch_chorus(int32_t *, int32_t, int32_t);
void init_ch_chorus(void);
void do_ch_chorus_xg(int32_t *, int32_t);
/* Delay (Celeste) Effect */
void do_ch_delay(int32_t *, int32_t);
void set_ch_delay(int32_t *, int32_t, int32_t);
void init_ch_delay(void);
/* EQ */
void init_eq_gs(void);
void set_ch_eq_gs(int32_t *, int32_t);
void do_ch_eq_gs(int32_t *, int32_t);
void do_ch_eq_xg(int32_t *, int32_t, struct part_eq_xg *);
void do_multi_eq_xg(int32_t *, int32_t);
// These get accessed directly by the player.
struct multi_eq_xg_t multi_eq_xg;
pink_noise global_pink_noise_light;
struct insertion_effect_gs_t insertion_effect_gs;
struct effect_xg_t insertion_effect_xg[XG_INSERTION_EFFECT_NUM],
variation_effect_xg[XG_VARIATION_EFFECT_NUM], reverb_status_xg, chorus_status_xg;
static const struct effect_parameter_gs_t effect_parameter_gs[];
static const struct effect_parameter_xg_t effect_parameter_xg[];
void init_for_effect()
{
init_pink_noise(&global_pink_noise_light);
init_reverb();
init_ch_delay();
init_ch_chorus();
init_eq_gs();
}
struct reverb_status_gs_t reverb_status_gs;
//struct chorus_text_gs_t chorus_text_gs;
struct chorus_status_gs_t chorus_status_gs;
struct delay_status_gs_t delay_status_gs;
struct eq_status_gs_t eq_status_gs;
////////////////////////////////// from readmidi
void init_delay_status_gs(void);
void recompute_delay_status_gs(void);
void set_delay_macro_gs(int macro);
void init_reverb_status_gs(void);
void recompute_reverb_status_gs(void);
void set_reverb_macro_gm2(int macro);
void set_reverb_macro_gs(int macro);
void init_chorus_status_gs(void);
void recompute_chorus_status_gs();
void set_chorus_macro_gs(int macro);
void init_eq_status_gs(void);
void recompute_eq_status_gs(void);
void init_multi_eq_xg(void);
void set_multi_eq_type_xg(int type);
void recompute_multi_eq_xg(void);
void set_effect_param_xg(struct effect_xg_t *st, int type_msb, int type_lsb);
void recompute_effect_xg(struct effect_xg_t *st);
void realloc_effect_xg(struct effect_xg_t *st);
void init_effect_xg(struct effect_xg_t *st);
void init_all_effect_xg(void);
void init_insertion_effect_gs(void);
void set_effect_param_gs(struct insertion_effect_gs_t *st, int msb, int lsb);
void recompute_insertion_effect_gs(void);
void realloc_insertion_effect_gs(void);
void init_effect_status(int play_system_mode);
};
}
#endif /* ___REVERB_H_ */

View File

@ -0,0 +1,210 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*================================================================
* SBK --> SF2 Conversion
*
* Copyright (C) 1996,1997 Takashi Iwai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*================================================================*/
#include <stdio.h>
#include <math.h>
#include "timidity.h"
#include "common.h"
#include "sffile.h"
#include "sfitem.h"
namespace TimidityPlus
{
/*----------------------------------------------------------------
* prototypes
*----------------------------------------------------------------*/
static int sbk_cutoff(int gen, int val);
static int sbk_filterQ(int gen, int val);
static int sbk_tenpct(int gen, int val);
static int sbk_panpos(int gen, int val);
static int sbk_atten(int gen, int val);
static int sbk_scale(int gen, int val);
static int sbk_time(int gen, int val);
static int sbk_tm_key(int gen, int val);
static int sbk_freq(int gen, int val);
static int sbk_pshift(int gen, int val);
static int sbk_cshift(int gen, int val);
static int sbk_tremolo(int gen, int val);
static int sbk_volsust(int gen, int val);
static int sbk_modsust(int gen, int val);
/*----------------------------------------------------------------
* convertor function table
*----------------------------------------------------------------*/
static SBKConv sbk_convertors[T_EOT] = {
NULL, NULL, NULL, NULL, NULL,
sbk_cutoff, sbk_filterQ, sbk_tenpct, sbk_panpos, sbk_atten, sbk_scale,
sbk_time, sbk_tm_key, sbk_freq, sbk_pshift, sbk_cshift,
sbk_tremolo, sbk_modsust, sbk_volsust,
};
/*----------------------------------------------------------------
* sbk --> sf2 conversion
*----------------------------------------------------------------*/
int sbk_to_sf2(int oper, int amount, const LayerItem *layer_items)
{
const LayerItem *item = &layer_items[oper];
if (item->type < 0 || item->type >= T_EOT) {
fprintf(stderr, "illegal gen item type %d\n", item->type);
return amount;
}
if (sbk_convertors[item->type])
return sbk_convertors[item->type](oper, amount);
return amount;
}
/*----------------------------------------------------------------
* conversion rules for each type
*----------------------------------------------------------------*/
/* initial cutoff */
static int sbk_cutoff(int gen, int val)
{
if (val == 127)
return 14400;
else
return 59 * val + 4366;
/*return 50 * val + 4721;*/
}
/* initial resonance */
static int sbk_filterQ(int gen, int val)
{
return val * 3 / 2;
}
/* chorus/reverb */
static int sbk_tenpct(int gen, int val)
{
return val * 1000 / 256;
}
/* pan position */
static int sbk_panpos(int gen, int val)
{
return val * 1000 / 127 - 500;
}
/* initial attenuation */
static int sbk_atten(int gen, int val)
{
if (val == 0)
return 1000;
return (int)(-200.0 * log10((double)val / 127.0) * 10);
}
/* scale tuning */
static int sbk_scale(int gen, int val)
{
return (val ? 50 : 100);
}
/* env/lfo time parameter */
static int sbk_time(int gen, int val)
{
if (val <= 0) val = 1;
return (int)(log((double)val / 1000.0) / log(2.0) * 1200.0);
}
/* time change per key */
static int sbk_tm_key(int gen, int val)
{
return (int)(val * 5.55);
}
/* lfo frequency */
static int sbk_freq(int gen, int val)
{
if (val == 0) {
if (gen == SF_freqLfo1) return -725;
else /* SF_freqLfo2*/ return -15600;
}
/*return (int)(3986.0 * log10((double)val) - 7925.0);*/
return (int)(1200 * log10((double)val) / log10(2.0) - 7925.0);
}
/* lfo/env pitch shift */
static int sbk_pshift(int gen, int val)
{
return (1200 * val / 64 + 1) / 2;
}
/* lfo/env cutoff freq shift */
static int sbk_cshift(int gen, int val)
{
if (gen == SF_lfo1ToFilterFc)
return (1200 * 3 * val) / 64;
else
return (1200 * 6 * val) / 64;
}
/* lfo volume shift */
static int sbk_tremolo(int gen, int val)
{
return (120 * val) / 64;
}
/* mod env sustain */
static int sbk_modsust(int gen, int val)
{
if (val < 96)
return 1000 * (96 - val) / 96;
else
return 0;
}
/* vol env sustain */
static int sbk_volsust(int gen, int val)
{
if (val < 96)
return (2000 - 21 * val) / 2;
else
return 0;
}
}

View File

@ -0,0 +1,736 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*================================================================
* sffile.c
* read SoundFont file (SBK/SF2) and store the layer lists
*
* Copyright (C) 1996,1997 Takashi Iwai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*================================================================*/
/*
* Modified by Masanao Izumo <mo@goice.co.jp>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
namespace TimidityPlus
{
/*================================================================
* preset / instrument bag record
*================================================================*/
/*----------------------------------------------------------------
* function prototypes
*----------------------------------------------------------------*/
#define NEW(type,nums) (type*)safe_malloc(sizeof(type) * (nums))
static int READCHUNK(SFChunk *vp, struct timidity_file *tf)
{
if (tf_read(vp, 8, 1, tf) != 1)
return -1;
vp->size = LE_LONG(vp->size);
return 1;
}
static int READDW(uint32_t *vp, struct timidity_file *tf)
{
if (tf_read(vp, 4, 1, tf) != 1)
return -1;
*vp = LE_LONG(*vp);
return 1;
}
static int READW(uint16_t *vp, struct timidity_file *tf)
{
if (tf_read(vp, 2, 1, tf) != 1)
return -1;
*vp = LE_SHORT(*vp);
return 1;
}
static int READSTR(char *str, struct timidity_file *tf)
{
int n;
if (tf_read(str, 20, 1, tf) != 1)
return -1;
str[19] = '\0';
n = (int)strlen(str);
while (n > 0 && str[n - 1] == ' ')
n--;
str[n] = '\0';
return n;
}
#define READID(var,tf) tf_read(var, 4, 1, tf)
#define READB(var,tf) tf_read(&var, 1, 1, tf)
#define SKIPB(tf) skip(tf, 1)
#define SKIPW(tf) skip(tf, 2)
#define SKIPDW(tf) skip(tf, 4)
#define FSKIP(size,tf) skip(tf, size)
/*----------------------------------------------------------------*/
/*----------------------------------------------------------------
* id numbers
*----------------------------------------------------------------*/
enum {
/* level 0; chunk */
UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
/* level 1; id only */
INFO_ID, SDTA_ID, PDTA_ID,
/* info stuff; chunk */
IFIL_ID, ISNG_ID, IROM_ID, INAM_ID, IVER_ID, IPRD_ID, ICOP_ID,
ICRD_ID, IENG_ID, ISFT_ID, ICMT_ID,
/* sample data stuff; chunk */
SNAM_ID, SMPL_ID,
/* preset stuff; chunk */
PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID,
/* inst stuff; chunk */
INST_ID, IBAG_ID, IMOD_ID, IGEN_ID,
/* sample header; chunk */
SHDR_ID
};
/*================================================================
* load a soundfont file
*================================================================*/
int Instruments::load_soundfont(SFInfo *sf, struct timidity_file *fd)
{
SFChunk chunk;
sf->preset = NULL;
sf->sample = NULL;
sf->inst = NULL;
sf->sf_name = NULL;
prbags.bag = inbags.bag = NULL;
prbags.gen = inbags.gen = NULL;
prbags.nbags = inbags.nbags =
prbags.ngens = inbags.ngens = 0;
/* check RIFF file header */
READCHUNK(&chunk, fd);
if (chunkid(chunk.id) != RIFF_ID) {
ctl_cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: *** not a RIFF file", fd->filename.c_str());
return -1;
}
/* check file id */
READID(chunk.id, fd);
if (chunkid(chunk.id) != SFBK_ID) {
ctl_cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: *** not a SoundFont file", fd->filename.c_str());
return -1;
}
for (;;) {
if (READCHUNK(&chunk, fd) <= 0)
break;
else if (chunkid(chunk.id) == LIST_ID) {
if (process_list(chunk.size, sf, fd))
break;
}
else {
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: *** illegal id in level 0: %4.4s %4d",
fd->filename.c_str(), chunk.id, chunk.size);
FSKIP(chunk.size, fd);
}
}
/* parse layer structure */
convert_layers(sf);
/* free private tables */
if (prbags.bag) free(prbags.bag);
if (prbags.gen) free(prbags.gen);
if (inbags.bag) free(inbags.bag);
if (inbags.gen) free(inbags.gen);
return 0;
}
/*================================================================
* free buffer
*================================================================*/
void Instruments::free_soundfont(SFInfo *sf)
{
int i;
if (sf->preset) {
for (i = 0; i < sf->npresets; i++)
free_layer(&sf->preset[i].hdr);
free(sf->preset);
}
if (sf->inst) {
for (i = 0; i < sf->ninsts; i++)
free_layer(&sf->inst[i].hdr);
free(sf->inst);
}
if (sf->sample) free(sf->sample);
if (sf->sf_name) free(sf->sf_name);
}
/*----------------------------------------------------------------
* get id value from 4bytes ID string
*----------------------------------------------------------------*/
int Instruments::chunkid(char *id)
{
static struct idstring {
const char *str;
int id;
} idlist[] = {
{"RIFF", RIFF_ID},
{"LIST", LIST_ID},
{"sfbk", SFBK_ID},
{"INFO", INFO_ID},
{"sdta", SDTA_ID},
{"snam", SNAM_ID},
{"smpl", SMPL_ID},
{"pdta", PDTA_ID},
{"phdr", PHDR_ID},
{"pbag", PBAG_ID},
{"pmod", PMOD_ID},
{"pgen", PGEN_ID},
{"inst", INST_ID},
{"ibag", IBAG_ID},
{"imod", IMOD_ID},
{"igen", IGEN_ID},
{"shdr", SHDR_ID},
{"ifil", IFIL_ID},
{"isng", ISNG_ID},
{"irom", IROM_ID},
{"iver", IVER_ID},
{"INAM", INAM_ID},
{"IPRD", IPRD_ID},
{"ICOP", ICOP_ID},
{"ICRD", ICRD_ID},
{"IENG", IENG_ID},
{"ISFT", ISFT_ID},
{"ICMT", ICMT_ID},
};
int i;
for (i = 0; i < sizeof(idlist) / sizeof(idlist[0]); i++) {
if (strncmp(id, idlist[i].str, 4) == 0)
return idlist[i].id;
}
return UNKN_ID;
}
/*================================================================
* process a list chunk
*================================================================*/
int Instruments::process_list(int size, SFInfo *sf, struct timidity_file *fd)
{
SFChunk chunk;
/* read the following id string */
READID(chunk.id, fd); size -= 4;
ctl_cmsg(CMSG_INFO, VERB_DEBUG, "%c%c%c%c:",
chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]);
switch (chunkid(chunk.id)) {
case INFO_ID:
return process_info(size, sf, fd);
case SDTA_ID:
return process_sdta(size, sf, fd);
case PDTA_ID:
return process_pdta(size, sf, fd);
default:
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: *** illegal id in level 1: %4.4s",
fd->filename.c_str(), chunk.id);
FSKIP(size, fd); /* skip it */
return 0;
}
}
/*================================================================
* process info list
*================================================================*/
int Instruments::process_info(int size, SFInfo *sf, struct timidity_file *fd)
{
sf->infopos = tf_tell(fd);
sf->infosize = size;
/* parse the buffer */
while (size > 0) {
SFChunk chunk;
/* read a sub chunk */
if (READCHUNK(&chunk, fd) <= 0)
return -1;
size -= 8;
ctl_cmsg(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:",
chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]);
switch (chunkid(chunk.id)) {
case IFIL_ID:
/* soundfont file version */
READW(&sf->version, fd);
READW(&sf->minorversion, fd);
ctl_cmsg(CMSG_INFO, VERB_DEBUG,
" version %d, minor %d",
sf->version, sf->minorversion);
break;
case INAM_ID:
/* name of the font */
sf->sf_name = (char*)safe_malloc(chunk.size + 1);
tf_read(sf->sf_name, 1, chunk.size, fd);
sf->sf_name[chunk.size] = 0;
ctl_cmsg(CMSG_INFO, VERB_DEBUG,
" name %s", sf->sf_name);
break;
default:
break;
}
size -= chunk.size;
}
return 0;
}
/*================================================================
* process sample data list
*================================================================*/
int Instruments::process_sdta(int size, SFInfo *sf, struct timidity_file *fd)
{
while (size > 0) {
SFChunk chunk;
/* read a sub chunk */
if (READCHUNK(&chunk, fd) <= 0)
return -1;
size -= 8;
ctl_cmsg(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:",
chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]);
switch (chunkid(chunk.id)) {
case SNAM_ID:
/* sample name list */
load_sample_names(chunk.size, sf, fd);
break;
case SMPL_ID:
/* sample data starts from here */
sf->samplepos = tf_tell(fd);
sf->samplesize = chunk.size;
FSKIP(chunk.size, fd);
break;
default:
FSKIP(chunk.size, fd);
break;
}
size -= chunk.size;
}
return 0;
}
/*================================================================
* process preset data list
*================================================================*/
int Instruments::process_pdta(int size, SFInfo *sf, struct timidity_file *fd)
{
while (size > 0) {
SFChunk chunk;
/* read a subchunk */
if (READCHUNK(&chunk, fd) <= 0)
return -1;
size -= 8;
ctl_cmsg(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:",
chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]);
switch (chunkid(chunk.id)) {
case PHDR_ID:
load_preset_header(chunk.size, sf, fd);
break;
case PBAG_ID:
load_bag(chunk.size, &prbags, fd);
break;
case PGEN_ID:
load_gen(chunk.size, &prbags, fd);
break;
case INST_ID:
load_inst_header(chunk.size, sf, fd);
break;
case IBAG_ID:
load_bag(chunk.size, &inbags, fd);
break;
case IGEN_ID:
load_gen(chunk.size, &inbags, fd);
break;
case SHDR_ID:
load_sample_info(chunk.size, sf, fd);
break;
case PMOD_ID: /* ignored */
case IMOD_ID: /* ingored */
default:
FSKIP(chunk.size, fd);
break;
}
size -= chunk.size;
}
return 0;
}
/*----------------------------------------------------------------
* store sample name list; sf1 only
*----------------------------------------------------------------*/
void Instruments::load_sample_names(int size, SFInfo *sf, struct timidity_file *fd)
{
int i, nsamples;
if (sf->version > 1) {
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: *** version 2 has obsolete format??",
fd->filename.c_str());
FSKIP(size, fd);
return;
}
/* each sample name has a fixed lentgh (20 bytes) */
nsamples = size / 20;
if (sf->sample == NULL) {
sf->nsamples = nsamples;
sf->sample = NEW(SFSampleInfo, sf->nsamples);
}
else if (sf->nsamples != nsamples) {
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: *** different # of samples ?? (%d : %d)\n",
fd->filename.c_str(), sf->nsamples, nsamples);
FSKIP(size, fd);
return;
}
/* read each name from file */
for (i = 0; i < sf->nsamples; i++) {
READSTR(sf->sample[i].name, fd);
}
}
/*----------------------------------------------------------------
* preset header list
*----------------------------------------------------------------*/
void Instruments::load_preset_header(int size, SFInfo *sf, struct timidity_file *fd)
{
int i;
sf->npresets = size / 38;
sf->preset = NEW(SFPresetHdr, sf->npresets);
for (i = 0; i < sf->npresets; i++) {
READSTR(sf->preset[i].hdr.name, fd);
READW(&sf->preset[i].preset, fd);
READW(&sf->preset[i].bank, fd);
READW(&sf->preset[i].hdr.bagNdx, fd);
SKIPDW(fd); /* lib; ignored*/
SKIPDW(fd); /* genre; ignored */
SKIPDW(fd); /* morph; ignored */
/* initialize layer table; it'll be parsed later */
sf->preset[i].hdr.nlayers = 0;
sf->preset[i].hdr.layer = NULL;
}
}
/*----------------------------------------------------------------
* instrument header list
*----------------------------------------------------------------*/
void Instruments::load_inst_header(int size, SFInfo *sf, struct timidity_file *fd)
{
int i;
sf->ninsts = size / 22;
sf->inst = NEW(SFInstHdr, sf->ninsts);
for (i = 0; i < sf->ninsts; i++) {
READSTR(sf->inst[i].hdr.name, fd);
READW(&sf->inst[i].hdr.bagNdx, fd);
/* iniitialize layer table; it'll be parsed later */
sf->inst[i].hdr.nlayers = 0;
sf->inst[i].hdr.layer = NULL;
ctl_cmsg(CMSG_INFO, VERB_DEBUG,
" InstHdr %d (%s) bagNdx=%d",
i, sf->inst[i].hdr.name, sf->inst[i].hdr.bagNdx);
}
}
/*----------------------------------------------------------------
* load preset/instrument bag list on the private table
*----------------------------------------------------------------*/
void Instruments::load_bag(int size, SFBags *bagp, struct timidity_file *fd)
{
int i;
size /= 4;
bagp->bag = NEW(uint16_t, size);
for (i = 0; i < size; i++) {
READW(&bagp->bag[i], fd);
SKIPW(fd); /* mod; ignored */
}
bagp->nbags = size;
}
/*----------------------------------------------------------------
* load preset/instrument generator list on the private table
*----------------------------------------------------------------*/
void Instruments::load_gen(int size, SFBags *bagp, struct timidity_file *fd)
{
int i;
size /= 4;
bagp->gen = NEW(SFGenRec, size);
for (i = 0; i < size; i++) {
READW((uint16_t *)&bagp->gen[i].oper, fd);
READW((uint16_t *)&bagp->gen[i].amount, fd);
}
bagp->ngens = size;
}
/*----------------------------------------------------------------
* load sample info list
*----------------------------------------------------------------*/
void Instruments::load_sample_info(int size, SFInfo *sf, struct timidity_file *fd)
{
int i;
int in_rom;
/* the record size depends on the soundfont version */
if (sf->version > 1) {
/* SF2 includes sample name and other infos */
sf->nsamples = size / 46;
sf->sample = NEW(SFSampleInfo, sf->nsamples);
}
else {
/* SBK; sample name may be read already */
int nsamples = size / 16;
if (sf->sample == NULL) {
sf->nsamples = nsamples;
sf->sample = NEW(SFSampleInfo, sf->nsamples);
}
else if (sf->nsamples != nsamples) {
/* overwrite it */
sf->nsamples = nsamples;
}
}
in_rom = 1; /* data may start from ROM samples */
for (i = 0; i < sf->nsamples; i++) {
if (sf->version > 1) /* SF2 only */
READSTR(sf->sample[i].name, fd);
READDW((uint32_t *)&sf->sample[i].startsample, fd);
READDW((uint32_t *)&sf->sample[i].endsample, fd);
READDW((uint32_t *)&sf->sample[i].startloop, fd);
READDW((uint32_t *)&sf->sample[i].endloop, fd);
if (sf->version > 1) { /* SF2 only */
READDW((uint32_t *)&sf->sample[i].samplerate, fd);
READB(sf->sample[i].originalPitch, fd);
READB(sf->sample[i].pitchCorrection, fd);
READW(&sf->sample[i].samplelink, fd);
READW(&sf->sample[i].sampletype, fd);
}
else { /* for SBK; set missing infos */
sf->sample[i].samplerate = 44100;
sf->sample[i].originalPitch = 60;
sf->sample[i].pitchCorrection = 0;
sf->sample[i].samplelink = 0;
/* the first RAM data starts from address 0 */
if (sf->sample[i].startsample == 0)
in_rom = 0;
if (in_rom)
sf->sample[i].sampletype = 0x8001;
else
sf->sample[i].sampletype = 1;
}
}
}
/*================================================================
* convert from bags to layers
*================================================================*/
void Instruments::convert_layers(SFInfo *sf)
{
int i;
if (prbags.bag == NULL || prbags.gen == NULL ||
inbags.bag == NULL || inbags.gen == NULL) {
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: *** illegal bags / gens", sf->sf_name);
return;
}
for (i = 0; i < sf->npresets - 1; i++) {
generate_layers(&sf->preset[i].hdr,
&sf->preset[i + 1].hdr,
&prbags);
}
for (i = 0; i < sf->ninsts - 1; i++) {
generate_layers(&sf->inst[i].hdr,
&sf->inst[i + 1].hdr,
&inbags);
}
}
/*----------------------------------------------------------------
* generate layer lists from stored bags
*----------------------------------------------------------------*/
void Instruments::generate_layers(SFHeader *hdr, SFHeader *next, SFBags *bags)
{
int i;
SFGenLayer *layp;
hdr->nlayers = next->bagNdx - hdr->bagNdx;
if (hdr->nlayers < 0) {
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: illegal layer numbers %d",
"", hdr->nlayers);
return;
}
if (hdr->nlayers == 0)
return;
hdr->layer = (SFGenLayer*)safe_malloc(sizeof(SFGenLayer) * hdr->nlayers);
layp = hdr->layer;
for (layp = hdr->layer, i = hdr->bagNdx; i < next->bagNdx; layp++, i++) {
int genNdx = bags->bag[i];
layp->nlists = bags->bag[i + 1] - genNdx;
if (layp->nlists < 0) {
ctl_cmsg(CMSG_WARNING, VERB_NORMAL,
"%s: illegal list numbers %d",
"", layp->nlists);
return;
}
layp->list = (SFGenRec*)safe_malloc(sizeof(SFGenRec) * layp->nlists);
memcpy(layp->list, &bags->gen[genNdx],
sizeof(SFGenRec) * layp->nlists);
}
}
/*----------------------------------------------------------------
* free a layer
*----------------------------------------------------------------*/
void Instruments::free_layer(SFHeader *hdr)
{
int i;
for (i = 0; i < hdr->nlayers; i++) {
SFGenLayer *layp = &hdr->layer[i];
if (layp->nlists >= 0)
free(layp->list);
}
if (hdr->nlayers > 0)
free(hdr->layer);
}
/* add blank loop for each data */
static const int auto_add_blank = 0;
void Instruments::correct_samples(SFInfo *sf)
{
int i;
SFSampleInfo *sp;
int prev_end;
prev_end = 0;
for (sp = sf->sample, i = 0; i < sf->nsamples; i++, sp++) {
/* correct sample positions for SBK file */
if (sf->version == 1) {
sp->startloop++;
sp->endloop += 2;
}
/* calculate sample data size */
if (sp->sampletype & 0x8000)
sp->size = 0;
else if (sp->startsample < prev_end && sp->startsample != 0)
sp->size = 0;
else {
sp->size = -1;
if (!auto_add_blank && i != sf->nsamples - 1)
sp->size = sp[1].startsample - sp->startsample;
if (sp->size < 0)
sp->size = sp->endsample - sp->startsample + 48;
}
prev_end = sp->endsample;
/* calculate short-shot loop size */
if (auto_add_blank || i == sf->nsamples - 1)
sp->loopshot = 48;
else {
sp->loopshot = sp[1].startsample - sp->endsample;
if (sp->loopshot < 0 || sp->loopshot > 48)
sp->loopshot = 48;
}
}
}
}

View File

@ -0,0 +1,144 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*================================================================
* sffile.h
* SoundFont file (SBK/SF2) format defintions
*
* Copyright (C) 1996,1997 Takashi Iwai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*================================================================*/
/*
* Modified by Masanao Izumo <mo@goice.co.jp>
*/
#ifndef SFFILE_H_DEF
#define SFFILE_H_DEF
namespace TimidityPlus
{
/* chunk record header */
typedef struct _SFChunk {
char id[4];
int32_t size;
} SFChunk;
/* generator record */
typedef struct _SFGenRec {
int16_t oper;
int16_t amount;
} SFGenRec;
/* layered generators record */
typedef struct _SFGenLayer {
int nlists;
SFGenRec *list;
} SFGenLayer;
/* header record */
typedef struct _SFHeader {
char name[20];
uint16_t bagNdx;
/* layered stuff */
int nlayers;
SFGenLayer *layer;
} SFHeader;
/* preset header record */
typedef struct _SFPresetHdr {
SFHeader hdr;
uint16_t preset, bank;
/*int32_t lib, genre, morphology;*/ /* not used */
} SFPresetHdr;
/* instrument header record */
typedef struct _SFInstHdr {
SFHeader hdr;
} SFInstHdr;
/* sample info record */
typedef struct _SFSampleInfo {
char name[20];
int32_t startsample, endsample;
int32_t startloop, endloop;
/* ver.2 additional info */
int32_t samplerate;
uint8_t originalPitch;
int8_t pitchCorrection;
uint16_t samplelink;
uint16_t sampletype; /*1=mono, 2=right, 4=left, 8=linked, $8000=ROM*/
/* optional info */
int32_t size; /* sample size */
int32_t loopshot; /* short-shot loop size */
} SFSampleInfo;
/*----------------------------------------------------------------
* soundfont file info record
*----------------------------------------------------------------*/
typedef struct _SFInfo {
/* file name */
char *sf_name;
/* version of this file */
uint16_t version, minorversion;
/* sample position (from origin) & total size (in bytes) */
int32_t samplepos;
int32_t samplesize;
/* raw INFO chunk list */
int32_t infopos, infosize;
/* preset headers */
int npresets;
SFPresetHdr *preset;
/* sample infos */
int nsamples;
SFSampleInfo *sample;
/* instrument headers */
int ninsts;
SFInstHdr *inst;
} SFInfo;
/*----------------------------------------------------------------
* functions
*----------------------------------------------------------------*/
}
#endif

View File

@ -0,0 +1,98 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*================================================================
* sfitem.c
* soundfont generator table definition
*================================================================*/
#include <stdio.h>
#include "timidity.h"
#include "common.h"
#include "sflayer.h"
#include "sfitem.h"
namespace TimidityPlus
{
/* layer type definitions */
const LayerItem static_layer_items[SF_EOF] = {
{L_INHRT, T_OFFSET, 0, 0, 0}, /* startAddrs */
{L_INHRT, T_OFFSET, 0, 0, 0}, /* endAddrs */
{L_INHRT, T_OFFSET, 0, 0, 0}, /* startloopAddrs */
{L_INHRT, T_OFFSET, 0, 0, 0}, /* endloopAddrs */
{L_INHRT, T_HI_OFF, 0, 0, 0}, /* startAddrsHi */
{L_INHRT, T_PSHIFT, -12000, 12000, 0}, /* lfo1ToPitch */
{L_INHRT, T_PSHIFT, -12000, 12000, 0}, /* lfo2ToPitch */
{L_INHRT, T_PSHIFT, -12000, 12000, 0}, /* env1ToPitch */
{L_INHRT, T_CUTOFF, 1500, 13500, 13500}, /* initialFilterFc */
{L_INHRT, T_FILTERQ, 0, 960, 0}, /* initialFilterQ */
{L_INHRT, T_CSHIFT, -12000, 12000, 0}, /* lfo1ToFilterFc */
{L_INHRT, T_CSHIFT, -12000, 12000, 0}, /* env1ToFilterFc */
{L_INHRT, T_HI_OFF, 0, 0, 0}, /* endAddrsHi */
{L_INHRT, T_TREMOLO, -960, 960, 0}, /* lfo1ToVolume */
{L_INHRT, T_NOP, 0, 0, 0}, /* env2ToVolume / unused1 */
{L_INHRT, T_TENPCT, 0, 1000, 0}, /* chorusEffectsSend */
{L_INHRT, T_TENPCT, 0, 1000, 0}, /* reverbEffectsSend */
{L_INHRT, T_PANPOS, 0, 1000, 0}, /* panEffectsSend */
{L_INHRT, T_NOP, 0, 0, 0}, /* unused */
{L_INHRT, T_NOP, 0, 0, 0}, /* sampleVolume / unused */
{L_INHRT, T_NOP, 0, 0, 0}, /* unused3 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayLfo1 */
{L_INHRT, T_FREQ, -16000, 4500, 0}, /* freqLfo1 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayLfo2 */
{L_INHRT, T_FREQ, -16000, 4500, 0}, /* freqLfo2 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayEnv1 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* attackEnv1 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* holdEnv1 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* decayEnv1 */
{L_INHRT, T_MODSUST, 0, 1000, 0}, /* sustainEnv1 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* releaseEnv1 */
{L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoHoldEnv1 */
{L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoDecayEnv1 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayEnv2 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* attackEnv2 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* holdEnv2 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* decayEnv2 */
{L_INHRT, T_VOLSUST, 0, 1440, 0}, /* sustainEnv2 */
{L_INHRT, T_TIME, -12000, 5000, -12000}, /* releaseEnv2 */
{L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoHoldEnv2 */
{L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoDecayEnv2 */
{L_PRSET, T_NOCONV, 0, 0, 0}, /* instrument */
{L_INHRT, T_NOP, 0, 0, 0}, /* nop */
{L_RANGE, T_RANGE, 0, 0, RANGE(0,127)}, /* keyRange */
{L_RANGE, T_RANGE, 0, 0, RANGE(0,127)}, /* velRange */
{L_INHRT, T_HI_OFF, 0, 0, 0}, /* startloopAddrsHi */
{L_OVWRT, T_NOCONV, 0, 127, -1}, /* keynum */
{L_OVWRT, T_NOCONV, 0, 127, -1}, /* velocity */
{L_INHRT, T_ATTEN, 0, 1440, 0}, /* initialAttenuation */
{L_INHRT, T_NOP, 0, 0, 0}, /* keyTuning */
{L_INHRT, T_HI_OFF, 0, 0, 0}, /* endloopAddrsHi */
{L_INHRT, T_NOCONV, -120, 120, 0}, /* coarseTune */
{L_INHRT, T_NOCONV, -99, 99, 0}, /* fineTune */
{L_INSTR, T_NOCONV, 0, 0, 0}, /* sampleId */
{L_OVWRT, T_NOCONV, 0, 3, 0}, /* sampleFlags */
{L_OVWRT, T_NOCONV, 0, 0, 0}, /* samplePitch (only in SBK) */
{L_INHRT, T_SCALE, 0, 1200, 100}, /* scaleTuning */
{L_OVWRT, T_NOCONV, 0, 127, 0}, /* keyExclusiveClass */
{L_OVWRT, T_NOCONV, 0, 127, -1}, /* rootKey */
};
}

View File

@ -0,0 +1,94 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*================================================================
* sfitem.h
* soundfont generator conversion table
*================================================================*/
#ifndef SFITEM_H_DEF
#define SFITEM_H_DEF
#include "sflayer.h"
#include "sffile.h"
namespace TimidityPlus
{
typedef struct _LayerItem {
int copy; /* copy policy */
int type; /* conversion type */
int minv; /* minimum value */
int maxv; /* maximum value */
int defv; /* default value */
} LayerItem;
/* copy policy */
enum {
L_INHRT, /* add to global */
L_OVWRT, /* overwrite on global */
L_RANGE, /* range */
L_PRSET, /* preset only */
L_INSTR /* instrument only */
};
/* data type */
enum {
T_NOP, /* nothing */
T_NOCONV, /* no conversion */
T_OFFSET, /* address offset */
T_HI_OFF, /* address coarse offset (32k) */
T_RANGE, /* range; composite values (0-127/0-127) */
T_CUTOFF, /* initial cutoff */
T_FILTERQ, /* initial resonance */
T_TENPCT, /* effects send */
T_PANPOS, /* panning position */
T_ATTEN, /* initial attenuation */
T_SCALE, /* scale tuning */
T_TIME, /* envelope/LFO time */
T_TM_KEY, /* time change per key */
T_FREQ, /* LFO frequency */
T_PSHIFT, /* env/LFO pitch shift */
T_CSHIFT, /* env/LFO cutoff shift */
T_TREMOLO, /* LFO tremolo shift */
T_MODSUST, /* modulation env sustain level */
T_VOLSUST, /* volume env sustain level */
T_EOT /* end of type */
};
/* sbk->sf2 convertor function */
typedef int (*SBKConv)(int gen, int amount);
/* macros for range operation */
#define RANGE(lo,hi) (((hi)&0xff) << 8 | ((lo)&0xff))
#define LOWNUM(val) ((val) & 0xff)
#define HIGHNUM(val) (((val) >> 8) & 0xff)
/* layer type definitions */
extern const LayerItem static_layer_items[SF_EOF];
extern int sbk_to_sf2(int oper, int amount, const LayerItem *);
}
#endif

View File

@ -0,0 +1,107 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ___SFLAYER_H_
#define ___SFLAYER_H_
namespace TimidityPlus
{
/*================================================================
* sflayer.h
* SoundFont layer structure
*================================================================*/
enum {
SF_startAddrs, /* 0 sample start address -4 (0to*0xffffff)*/
SF_endAddrs, /* 1 */
SF_startloopAddrs, /* 2 loop start address -4 (0 to * 0xffffff) */
SF_endloopAddrs, /* 3 loop end address -3 (0 to * 0xffffff) */
SF_startAddrsHi, /* 4 high word of startAddrs */
SF_lfo1ToPitch, /* 5 main fm: lfo1-> pitch */
SF_lfo2ToPitch, /* 6 aux fm: lfo2-> pitch */
SF_env1ToPitch, /* 7 pitch env: env1(aux)-> pitch */
SF_initialFilterFc, /* 8 initial filter cutoff */
SF_initialFilterQ, /* 9 filter Q */
SF_lfo1ToFilterFc, /* 10 filter modulation: lfo1->filter*cutoff */
SF_env1ToFilterFc, /* 11 filter env: env1(aux)->filter * cutoff */
SF_endAddrsHi, /* 12 high word of endAddrs */
SF_lfo1ToVolume, /* 13 tremolo: lfo1-> volume */
SF_env2ToVolume, /* 14 Env2Depth: env2-> volume */
SF_chorusEffectsSend, /* 15 chorus */
SF_reverbEffectsSend, /* 16 reverb */
SF_panEffectsSend, /* 17 pan */
SF_auxEffectsSend, /* 18 pan auxdata (internal) */
SF_sampleVolume, /* 19 used internally */
SF_unused3, /* 20 */
SF_delayLfo1, /* 21 delay 0x8000-n*(725us) */
SF_freqLfo1, /* 22 frequency */
SF_delayLfo2, /* 23 delay 0x8000-n*(725us) */
SF_freqLfo2, /* 24 frequency */
SF_delayEnv1, /* 25 delay 0x8000 - n(725us) */
SF_attackEnv1, /* 26 attack */
SF_holdEnv1, /* 27 hold */
SF_decayEnv1, /* 28 decay */
SF_sustainEnv1, /* 29 sustain */
SF_releaseEnv1, /* 30 release */
SF_autoHoldEnv1, /* 31 */
SF_autoDecayEnv1, /* 32 */
SF_delayEnv2, /* 33 delay 0x8000 - n(725us) */
SF_attackEnv2, /* 34 attack */
SF_holdEnv2, /* 35 hold */
SF_decayEnv2, /* 36 decay */
SF_sustainEnv2, /* 37 sustain */
SF_releaseEnv2, /* 38 release */
SF_autoHoldEnv2, /* 39 */
SF_autoDecayEnv2, /* 40 */
SF_instrument, /* 41 */
SF_nop, /* 42 */
SF_keyRange, /* 43 */
SF_velRange, /* 44 */
SF_startloopAddrsHi, /* 45 high word of startloopAddrs */
SF_keynum, /* 46 */
SF_velocity, /* 47 */
SF_initAtten, /* 48 */
SF_keyTuning, /* 49 */
SF_endloopAddrsHi, /* 50 high word of endloopAddrs */
SF_coarseTune, /* 51 */
SF_fineTune, /* 52 */
SF_sampleId, /* 53 */
SF_sampleFlags, /* 54 */
SF_samplePitch, /* 55 SF1 only */
SF_scaleTuning, /* 56 */
SF_keyExclusiveClass, /* 57 */
SF_rootKey, /* 58 */
SF_EOF /* 59 */
};
/*----------------------------------------------------------------
* layer value table
*----------------------------------------------------------------*/
typedef struct _LayerTable {
short val[SF_EOF];
char set[SF_EOF];
} LayerTable;
}
#endif /* ___SFLAYER_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYSDEP_H_INCLUDED
#define SYSDEP_H_INCLUDED 1
#include <limits.h>
#define DEFAULT_AUDIO_BUFFER_BITS 12
#define SAMPLE_LENGTH_BITS 32
#include <stdint.h> // int types are defined here
#include "m_swap.h"
namespace TimidityPlus
{
/* Instrument files are little-endian, MIDI files big-endian, so we
need to do some conversions. */
#define XCHG_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
#define LE_SHORT(x) LittleShort(x)
#define LE_LONG(x) LittleLong(x)
#define BE_SHORT(x) BigShort(x)
#define BE_LONG(x) BigLong(x)
/* max_channels is defined in "timidity.h" */
#if MAX_CHANNELS <= 32
typedef struct _ChannelBitMask
{
uint32_t b; /* 32-bit bitvector */
} ChannelBitMask;
#define CLEAR_CHANNELMASK(bits) ((bits).b = 0)
#define FILL_CHANNELMASK(bits) ((bits).b = ~0)
#define IS_SET_CHANNELMASK(bits, c) ((bits).b & (1u << (c)))
#define SET_CHANNELMASK(bits, c) ((bits).b |= (1u << (c)))
#define UNSET_CHANNELMASK(bits, c) ((bits).b &= ~(1u << (c)))
#define TOGGLE_CHANNELMASK(bits, c) ((bits).b ^= (1u << (c)))
#define COPY_CHANNELMASK(dest, src) ((dest).b = (src).b)
#define REVERSE_CHANNELMASK(bits) ((bits).b = ~(bits).b)
#define COMPARE_CHANNELMASK(bitsA, bitsB) ((bitsA).b == (bitsB).b)
#endif
typedef int16_t sample_t;
typedef int32_t final_volume_t;
# define FINAL_VOLUME(v) (v)
# define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1)
#define MIN_AMP_VALUE (MAX_AMP_VALUE >> 9)
typedef uint32_t splen_t;
#define SPLEN_T_MAX (splen_t)((uint32_t)0xFFFFFFFF)
# define TIM_FSCALE(a,b) ((a) * (double)(1<<(b)))
# define TIM_FSCALENEG(a,b) ((a) * (1.0 / (double)(1<<(b))))
#ifdef _WIN32
#undef PATCH_EXT_LIST
#define PATCH_EXT_LIST { ".pat", 0 }
#endif
#define PATH_SEP '/'
#define PATH_STRING "/"
#define IS_PATH_SEP(c) ((c) == PATH_SEP)
#define NLS "\n"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif /* M_PI */
#if defined(_MSC_VER)
#define strncasecmp(a,b,c) _strnicmp((a),(b),(c))
#define strcasecmp(a,b) _stricmp((a),(b))
#endif /* _MSC_VER */
#define SAFE_CONVERT_LENGTH(len) (6 * (len) + 1)
}
#endif /* SYSDEP_H_INCUDED */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
tables.h
*/
#ifndef ___TABLES_H_
#define ___TABLES_H_
#include <math.h>
#include "sysdep.h"
namespace TimidityPlus
{
inline double lookup_sine(double x)
{
return (sin((2 * M_PI / 1024.0) * (x)));
}
extern double lookup_triangular(int x);
extern double lookup_log(int x);
#define SINE_CYCLE_LENGTH 1024
extern int32_t freq_table[];
extern int32_t freq_table_zapped[];
extern int32_t freq_table_tuning[][128];
extern int32_t freq_table_pytha[][128];
extern int32_t freq_table_meantone[][128];
extern int32_t freq_table_pureint[][128];
extern double *vol_table;
extern double def_vol_table[];
extern double gs_vol_table[];
extern double *xg_vol_table; /* == gs_vol_table */
extern double *pan_table;
extern double bend_fine[];
extern double bend_coarse[];
extern const double midi_time_table[], midi_time_table2[];
extern const uint8_t reverb_macro_presets[];
extern const uint8_t chorus_macro_presets[];
extern const uint8_t delay_macro_presets[];
extern const float delay_time_center_table[];
extern const float pre_delay_time_table[];
extern const float chorus_delay_time_table[];
extern const float rate1_table[];
extern double attack_vol_table[];
extern double perceived_vol_table[];
extern double gm2_vol_table[];
extern float sc_eg_attack_table[];
extern float sc_eg_decay_table[];
extern float sc_eg_release_table[];
extern double sc_vel_table[];
extern double sc_vol_table[];
extern double sc_pan_table[], gm2_pan_table[];
extern double sc_drum_level_table[];
extern double sb_vol_table[];
extern double modenv_vol_table[];
extern const float cb_to_amp_table[];
extern const float reverb_time_table[];
extern const float pan_delay_table[];
extern const float chamberlin_filter_db_to_q_table[];
extern const uint8_t multi_eq_block_table_xg[];
extern const float eq_freq_table_xg[];
extern const float lfo_freq_table_xg[];
extern const float mod_delay_offset_table_xg[];
extern const float reverb_time_table_xg[];
extern const float delay_time_table_xg[];
extern const int16_t cutoff_freq_table_gs[];
extern const int16_t lpf_table_gs[];
extern const int16_t eq_freq_table_gs[];
extern const float lofi_sampling_freq_table_xg[];
extern void init_tables(void);
struct Sample;
int32_t get_note_freq(Sample *sp, int note);
}
#endif /* ___TABLES_H_ */

View File

@ -0,0 +1,149 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2008 Masanao Izumo <iz@onicos.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <shlobj.h>
#endif
#include <time.h>
#include <signal.h>
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "tables.h"
#include "reverb.h"
#include "resample.h"
#include "recache.h"
#include "aq.h"
#include "mix.h"
#include "quantity.h"
#include "c_cvars.h"
namespace TimidityPlus
{
Instruments *instruments;
/* main interfaces (To be used another main) */
int timidity_pre_load_configuration(void);
void timidity_init_player(void);
int timidity_play_main(int nfiles, char **files);
int got_a_configuration;
CRITICAL_SECTION critSect;
/* -------- functions for getopt_long ends here --------- */
int timidity_pre_load_configuration(void)
{
/* Windows */
char *strp;
char local[1024];
/* First, try read configuration file which is in the
* TiMidity directory.
*/
if(GetModuleFileNameA(NULL, local, 1023))
{
local[1023] = '\0';
if (strp = strrchr(local, '\\'))
{
*(++strp) = '\0';
strncat(local, "TIMIDITY.CFG", sizeof(local) - strlen(local) - 1);
if (true)
{
if (!instruments->load("timidity.cfg"))
{
got_a_configuration = 1;
return 0;
}
}
}
}
return 0;
}
int dumb_pass_playing_list(int number_of_files, char *list_of_files[]);
int timidity_play_main(int nfiles, char **files)
{
int need_stdin = 0, need_stdout = 0;
int output_fail = 0;
int retval;
#ifdef _WIN32
InitializeCriticalSection(&critSect);
#endif
/* Open output device */
if(play_mode->open_output() < 0)
{
output_fail = 1;
return 2;
}
retval=dumb_pass_playing_list(nfiles, files);
play_mode->close_output();
#ifdef _WIN32
DeleteCriticalSection (&critSect);
#endif
return retval;
}
}
using namespace TimidityPlus;
void main(int argc, char **argv)
{
int err;
char *files_nbuf = NULL;
int main_ret;
instruments = new Instruments;
if ((err = timidity_pre_load_configuration()) != 0)
return;
main_ret = timidity_play_main(1, &argv[1]);
//free_readmidi();
free_global_mblock();
}

View File

@ -0,0 +1,178 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Historical issues: This file once was a huge header file, but now is
* devided into some smaller ones. Please do not add things to this
* header, but consider put them on other files.
*/
#ifndef TIMIDITY_H_INCLUDED
#define TIMIDITY_H_INCLUDED 1
#include "c_cvars.h"
#include "output.h"
#include "controls.h"
#include "mblock.h"
#ifdef _MSC_VER
#pragma warning(disable:4244) // double->float truncation occurs so often in here that it's pointless to fix it all.
#endif
EXTERN_CVAR(Int, playback_rate)
EXTERN_CVAR(Int, key_adjust)
EXTERN_CVAR(Float, tempo_adjust)
namespace TimidityPlus
{
extern int32_t control_ratio; // derived from playback_rate
}
EXTERN_CVAR(Bool, opt_modulation_wheel)
EXTERN_CVAR(Bool, opt_portamento)
EXTERN_CVAR(Bool, opt_nrpn_vibrato)
EXTERN_CVAR(Int, opt_reverb_control)
EXTERN_CVAR(Int, opt_chorus_control)
EXTERN_CVAR(Bool, opt_surround_chorus)
EXTERN_CVAR(Bool, opt_channel_pressure)
EXTERN_CVAR(Int, opt_lpf_def)
EXTERN_CVAR(Bool, opt_temper_control)
EXTERN_CVAR(Bool, opt_modulation_envelope)
/*
Table of contents:
(1) Flags and definitions to customize timidity
(3) inportant definitions not to customize
(2) #includes -- include other headers
*/
/*****************************************************************************\
section 1: some customize issues
\*****************************************************************************/
/* How many bits to use for the fractional part of sample positions.
This affects tonal accuracy. The entire position counter must fit
in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of
a sample is 1048576 samples (2 megabytes in memory). The GUS gets
by with just 9 bits and a little help from its friends...
"The GUS does not SUCK!!!" -- a happy user :) */
#define FRACTION_BITS 12
/* change FRACTION_BITS above, not this */
#define FRACTION_MASK (~(0xFFFFFFFF << FRACTION_BITS))
/* The number of samples to use for ramping out a dying note. Affects
click removal. */
#define MAX_DIE_TIME 20
/* Define the pre-resampling cache size.
* This value is default. You can change the cache saze with
* command line option.
*/
#define DEFAULT_CACHE_DATA_SIZE (2*1024*1024)
/*****************************************************************************\
section 2: some important definitions
\*****************************************************************************/
/*
Anything below this shouldn't need to be changed unless you're porting
to a new machine with other than 32-bit, big-endian words.
*/
/* Audio buffer size has to be a power of two to allow DMA buffer
fragments under the VoxWare (Linux & FreeBSD) audio driver */
#define AUDIO_BUFFER_SIZE (1<<12)
/* These affect general volume */
#define GUARD_BITS 3
#define AMP_BITS (15-GUARD_BITS)
#define MAX_AMPLIFICATION 800
#define MAX_CHANNELS 32
/* Vibrato and tremolo Choices of the Day */
#define SWEEP_TUNING 38
#define VIBRATO_AMPLITUDE_TUNING 1.0L
#define VIBRATO_RATE_TUNING 38
#define TREMOLO_AMPLITUDE_TUNING 1.0L
#define TREMOLO_RATE_TUNING 38
#define SWEEP_SHIFT 16
#define RATE_SHIFT 5
#define VIBRATO_SAMPLE_INCREMENTS 32
#define MODULATION_WHEEL_RATE (1.0/6.0)
/* #define MODULATION_WHEEL_RATE (midi_time_ratio/8.0) */
/* #define MODULATION_WHEEL_RATE (current_play_tempo/500000.0/32.0) */
#define VIBRATO_DEPTH_TUNING (1.0/4.0)
/* malloc's limit */
#define MAX_SAFE_MALLOC_SIZE (1<<23) /* 8M */
#define DEFAULT_SOUNDFONT_ORDER 0
/*****************************************************************************\
section 3: include other headers
\*****************************************************************************/
namespace TimidityPlus
{
enum play_system_modes
{
DEFAULT_SYSTEM_MODE,
GM_SYSTEM_MODE,
GM2_SYSTEM_MODE,
GS_SYSTEM_MODE,
XG_SYSTEM_MODE
};
const int DEFAULT_VOICES = 256;
// These were configurable in Timidity++ but it doesn't look like this is really needed.
// In case it becomes necessary, they can be turned into CVARs.
const int default_tonebank = 0;
const int special_tonebank = -1;
const int effect_lr_mode = -1;
const int effect_lr_delay_msec = 25;
const int adjust_panning_immediately = 1;
const int antialiasing_allowed = 0;
const int fast_decay = 0;
const int cutoff_allowed = 0;
const int opt_force_keysig = 8;
const int max_voices = DEFAULT_VOICES;
const int temper_type_mute = 0;
const int opt_preserve_silence = 0;
const int opt_init_keysig = 8;
}
#endif /* TIMIDITY_H_INCLUDED */

View File

@ -0,0 +1,666 @@
/*
TiMidity++ -- MIDI to WAVE converter and player
Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
w32_a.c
Functions to play sound on the Windows audio driver (Windows 95/98/NT).
Modified by Masanao Izumo <mo@goice.co.jp>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "timidity.h"
/*****************************************************************************************************************************/
/*****************************************************************************************************************************/
#include "instrum.h"
#include "playmidi.h"
#include "mblock.h"
namespace TimidityPlus
{
extern void *safe_malloc(size_t count);
extern CRITICAL_SECTION critSect;
static int opt_wmme_device_id = -2;
UINT uDeviceID;
#define NOT !
static int open_output (void); /* 0=success, 1=warning, -1=fatal error */
static void close_output (void);
static int output_data (char * Data, int32_t Size);
static int acntl (int request, void * arg);
static void print_device_list(void);
#define DATA_BLOCK_SIZE (4 * AUDIO_BUFFER_SIZE)
#define DATA_BLOCK_NUM 8
static int data_block_trunc_size;
struct MMBuffer
{
int Number;
int Prepared; // Non-zero if this buffer has been prepared.
HGLOBAL hData;
void * Data;
HGLOBAL hHead;
WAVEHDR * Head;
struct MMBuffer * Next;
};
static struct MMBuffer * Buffers;
static volatile struct MMBuffer * FreeBuffers;
static volatile int NumBuffersInUse;
static HWAVEOUT hDevice;
static int BufferDelay; // in milliseconds
static const int AllowSynchronousWaveforms = 1;
/*****************************************************************************************************************************/
static void CALLBACK OnPlaybackEvent (HWAVE hWave, UINT Msg, DWORD_PTR UserData, DWORD_PTR Param1, DWORD_PTR Param2);
static void BufferPoolReset (void);
static struct MMBuffer * GetBuffer ();
static void PutBuffer (struct MMBuffer *);
static const char * MMErrorMessage (MMRESULT Result);
static void WaitForBuffer (int WaitForAllBuffers);
/*****************************************************************************************************************************/
static int detect(void);
#define dpm w32_play_mode
PlayMode dpm =
{
44100,
PE_16BIT,
PF_PCM_STREAM|PF_BUFF_FRAGM_OPT,
-1,
{32},
"Windows audio driver", 'd',
NULL,
open_output,
close_output,
output_data,
acntl,
detect
};
/*****************************************************************************************************************************/
static int open_output(void)
{
int i;
int j;
int IsMono;
WAVEFORMATEX wf;
WAVEOUTCAPS woc;
MMRESULT Result;
UINT DeviceID;
int ret;
if( dpm.name != NULL)
ret = sscanf(dpm.name, "%d", &opt_wmme_device_id);
if ( dpm.name == NULL || ret == 0 || ret == EOF)
opt_wmme_device_id = -2;
if (opt_wmme_device_id == -1){
print_device_list();
return -1;
}
/** Check if there is at least one audio device. **/
if (waveOutGetNumDevs() == 0)
{
//ctl_cmsg (CMSG_ERROR, VERB_NORMAL, "No audio devices present!");
return -1;
}
/** They can't mean these. **/
dpm.encoding = PE_16BIT;
IsMono = false;
memset(&wf, 0, sizeof(wf));
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 2;
wf.nSamplesPerSec = dpm.rate;
i = dpm.rate;
j = 4;
i *= j;
data_block_trunc_size = DATA_BLOCK_SIZE - (DATA_BLOCK_SIZE % j);
wf.nAvgBytesPerSec = i;
wf.nBlockAlign = j;
wf.wBitsPerSample = 16;
wf.cbSize = sizeof(WAVEFORMAT);
/** Open the device. **/
{ CHAR b[256]; wsprintf(b, "Opening device...\n"); OutputDebugString(b); }
hDevice = 0;
if (opt_wmme_device_id == -2){
uDeviceID = WAVE_MAPPER;
}else{
uDeviceID= (UINT)opt_wmme_device_id;
}
if (AllowSynchronousWaveforms)
Result = waveOutOpen(&hDevice, uDeviceID, (LPWAVEFORMATEX) &wf, (DWORD_PTR) OnPlaybackEvent, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC);
else
Result = waveOutOpen(&hDevice, uDeviceID, (LPWAVEFORMATEX) &wf, (DWORD_PTR) OnPlaybackEvent, 0, CALLBACK_FUNCTION);
if (Result)
{
return -1;
}
else
{ CHAR b[256]; wsprintf(b, "Device opened.\n"); OutputDebugString(b); }
/** Get the device ID. **/
DeviceID = 0;
waveOutGetID(hDevice, &DeviceID);
/** Get the device capabilities. **/
memset(&woc, 0, sizeof(WAVEOUTCAPS));
Result = waveOutGetDevCaps(DeviceID, &woc, sizeof(WAVEOUTCAPS));
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Device ID: %d", DeviceID);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Manufacture ID: %d", woc.wMid);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Product ID: %d", woc.wPid);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Driver version: %d", woc.vDriverVersion);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Product name: %s", woc.szPname);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Formats supported: 0x%08X", woc.dwFormats);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Max. channels: %d", woc.wChannels);
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Supported features: 0x%08X", woc.dwSupport);
/** Calculate the buffer delay. **/
BufferDelay = AUDIO_BUFFER_SIZE * 4;
BufferDelay = (BufferDelay * 1000) / dpm.rate;
/** Create the buffer pool. **/
Buffers = (struct MMBuffer *) safe_malloc(DATA_BLOCK_NUM * sizeof(struct MMBuffer));
for (i = 0; i < DATA_BLOCK_NUM; i++)
{
struct MMBuffer * b;
b = &Buffers[i];
b->hData = GlobalAlloc(GMEM_ZEROINIT, DATA_BLOCK_SIZE);
b->Data = (WAVEHDR*)GlobalLock (b->hData);
b->hHead = GlobalAlloc(GMEM_ZEROINIT, sizeof(WAVEHDR));
b->Head = (WAVEHDR*)GlobalLock (b->hHead);
}
BufferPoolReset();
/** Set the file descriptor. **/
dpm.fd = 0;
return 0;
}
/*****************************************************************************************************************************/
static void close_output(void)
{
int i;
if (dpm.fd != -1)
{
WaitForBuffer(1);
{ CHAR b[256]; wsprintf(b, "Closing device...\n"); OutputDebugString(b); }
waveOutReset(hDevice);
waveOutClose(hDevice);
{ CHAR b[256]; wsprintf(b, "Device closed.\n"); OutputDebugString(b); }
/** Free all buffers. **/
for (i = 0; i < DATA_BLOCK_NUM; i++)
{
struct MMBuffer * block;
block = &Buffers[i];
GlobalUnlock(block->hHead);
GlobalFree (block->hHead);
GlobalUnlock(block->hData);
GlobalFree (block->hData);
}
free(Buffers);
/** Reset the file descriptor. **/
dpm.fd = -1;
}
}
static int detect(void)
{
if (waveOutGetNumDevs() == 0) {return 0;} /* not found */
return 1; /* found */
}
/*****************************************************************************************************************************/
#ifdef OutputDebugString
#undef OutputDebugString
#endif
void OutputDebugString(LPSTR sre)
{
}
static int output_data(char * Data, int32_t Size)
{
char * d;
int32_t s;
d = Data;
s = Size;
while (s > 0)
{
int32_t n;
struct MMBuffer * b;
MMRESULT Result;
LPWAVEHDR wh;
if ((b = GetBuffer()) == NULL)
{
WaitForBuffer(0);
continue;
}
if (s <= data_block_trunc_size)
n = s;
else
n = data_block_trunc_size;
CopyMemory(b->Data, d, n);
wh = b->Head;
wh->dwBufferLength = n;
wh->lpData = (LPSTR)b->Data;
wh->dwUser = b->Number;
/** Prepare the buffer. **/
{ CHAR b[256]; wsprintf(b, "%2d: Preparing buffer %d...\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
Result = waveOutPrepareHeader(hDevice, wh, sizeof(WAVEHDR));
if (Result)
{
{ CHAR b[256]; wsprintf(b, "%2d: Buffer preparation failed.\n", NumBuffersInUse); OutputDebugString(b); }
//ctl_cmsg (CMSG_ERROR, VERB_NORMAL, "waveOutPrepareHeader(): %s", MMErrorMessage(Result));
return -1;
}
else
{ CHAR b[256]; wsprintf(b, "%2d: Buffer %d prepared.\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
b->Prepared = 1;
/** Queue the buffer. **/
{ CHAR b[256]; wsprintf(b, "%2d: Queueing buffer %d...\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
Result = waveOutWrite(hDevice, wh, sizeof(WAVEHDR));
if (Result)
{
{ CHAR b[256]; wsprintf(b, "%2d: Buffer queueing failed.\n", NumBuffersInUse); OutputDebugString(b); }
//ctl_cmsg(CMSG_ERROR, VERB_NORMAL, "waveOutWrite(): %s", MMErrorMessage(Result));
return -1;
}
else
{ CHAR b[256]; wsprintf(b, "%2d: Buffer %d queued.\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
d += n;
s -= n;
}
return 0;
}
/*****************************************************************************************************************************/
static int acntl(int request, void *arg)
{
static char dummy_sounds[4*AUDIO_BUFFER_SIZE];
switch(request)
{
case PM_REQ_DISCARD:
{
{ CHAR b[256]; wsprintf(b, "Resetting audio device.\n"); OutputDebugString(b); }
waveOutReset(hDevice);
close_output();
open_output();
{ CHAR b[256]; wsprintf(b, "Audio device reset.\n"); OutputDebugString(b); }
return 0;
}
case PM_REQ_FLUSH:
{
close_output();
open_output();
return 0;
}
}
return -1;
}
/*****************************************************************************************************************************/
static void CALLBACK OnPlaybackEvent(HWAVE hWave, UINT Msg, DWORD_PTR UserData, DWORD_PTR Param1, DWORD_PTR Param2)
{
//ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Msg: 0x%08X, Num. buffers in use: %d", Msg, NumBuffersInUse);
switch (Msg)
{
case WOM_OPEN:
{ CHAR b[256]; wsprintf(b, "%2d: Device opened.\n", NumBuffersInUse); OutputDebugString(b); }
break;
case WOM_CLOSE:
{ CHAR b[256]; wsprintf(b, "%2d: Device closed.\n", NumBuffersInUse); OutputDebugString(b); }
break;
case WOM_DONE:
{
WAVEHDR * wh;
EnterCriticalSection(&critSect);
wh = (WAVEHDR *) Param1;
/* It's not safe to do this here. Read the remarks of waveOutProc() in the SDK on which functions are safe to call.
if (NOT Queueing)
{
{ CHAR b[256]; wsprintf(b, "%2d: Dequeueing buffer %d...\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
waveOutUnprepareHeader(hDevice, wh, sizeof(WAVEHDR));
{ CHAR b[256]; wsprintf(b, "%2d: Buffer %d dequeued.\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
}
else
{ CHAR b[256]; wsprintf(b, "%2d: *** Buffer %d not dequeued! ***\n", NumBuffersInUse, wh->dwUser); OutputDebugString(b); }
*/
PutBuffer(&Buffers[wh->dwUser]);
LeaveCriticalSection(&critSect);
break;
}
default:
{
CHAR b[256];
wsprintf(b, "%2d: Unknown play back event 0x%08X.\n", NumBuffersInUse, Msg);
OutputDebugString(b);
}
}
}
/*****************************************************************************************************************************/
#define DIM(a) sizeof(a) / sizeof(a[0])
static const char * mmsyserr_code_string[] =
{
"no error",
"unspecified error",
"device ID out of range",
"driver failed enable",
"device already allocated",
"device handle is invalid",
"no device driver present",
"memory allocation error",
"function isn't supported",
"error value out of range",
"invalid flag passed",
"invalid parameter passed",
"handle being used",
};
static const char * waverr_code_sring[] =
{
"unsupported wave format",
"still something playing",
"header not prepared",
"device is synchronous",
};
static const char * MMErrorMessage(MMRESULT ErrorCode)
{
static char s[32];
if (ErrorCode >= WAVERR_BASE)
{
ErrorCode -= WAVERR_BASE;
if (ErrorCode > DIM(waverr_code_sring))
{
wsprintf(s, "Unknown wave error %d", ErrorCode);
return s;
}
else
return waverr_code_sring[ErrorCode];
}
else
if (ErrorCode > DIM(mmsyserr_code_string))
{
wsprintf(s, "Unknown multimedia error %d", ErrorCode);
return s;
}
else
return mmsyserr_code_string[ErrorCode];
}
#undef DIM
/*****************************************************************************************************************************/
static void BufferPoolReset(void)
{
int i;
{ CHAR b[256]; wsprintf(b, "Resetting buffer pool...\n"); OutputDebugString(b); }
Buffers[0].Number = 0;
Buffers[0].Prepared = 0;
Buffers[0].Next = &Buffers[1];
for (i = 1; i < DATA_BLOCK_NUM - 1; i++)
{
Buffers[i].Number = i;
Buffers[i].Prepared = 0;
Buffers[i].Next = &Buffers[i + 1];
}
Buffers[i].Number = i;
Buffers[i].Prepared = 0;
Buffers[i].Next = NULL;
FreeBuffers = &Buffers[0];
NumBuffersInUse = 0;
{ CHAR b[256]; wsprintf(b, "Buffer pool reset.\n", NumBuffersInUse); OutputDebugString(b); }
}
/*****************************************************************************************************************************/
static struct MMBuffer * GetBuffer()
{
struct MMBuffer * b;
{ CHAR b[256]; wsprintf(b, "%2d: Getting buffer...\n", NumBuffersInUse); OutputDebugString(b); }
EnterCriticalSection(&critSect);
if (FreeBuffers)
{
b = (struct MMBuffer *)FreeBuffers;
FreeBuffers = FreeBuffers->Next;
NumBuffersInUse++;
/** If this buffer is still prepared we can safely unprepare it because we got it from the free buffer list. **/
if (b->Prepared)
{
waveOutUnprepareHeader(hDevice, (LPWAVEHDR) b->Head, sizeof(WAVEHDR));
b->Prepared = 0;
}
b->Next = NULL;
}
else
b = NULL;
LeaveCriticalSection(&critSect);
{ CHAR b[256]; wsprintf(b, "%2d: Got buffer.\n", NumBuffersInUse); OutputDebugString(b); }
return b;
}
/*****************************************************************************************************************************/
static void PutBuffer(struct MMBuffer * b)
{
{ CHAR b[256]; wsprintf(b, "%2d: Putting buffer...\n", NumBuffersInUse); OutputDebugString(b); }
b->Next = (struct MMBuffer *)FreeBuffers;
FreeBuffers = b;
NumBuffersInUse--;
{ CHAR b[256]; wsprintf(b, "%2d: Buffer put.\n", NumBuffersInUse); OutputDebugString(b); }
}
/*****************************************************************************************************************************/
static void WaitForBuffer(int WaitForAllBuffers)
{
int numbuf;
if (WaitForAllBuffers)
{
{ CHAR b[256]; wsprintf(b, "%2d: Waiting for all buffers to be dequeued...\n", NumBuffersInUse); OutputDebugString(b); }
while (1) {
EnterCriticalSection(&critSect);
numbuf = NumBuffersInUse;
if (numbuf) {
LeaveCriticalSection(&critSect);
Sleep(BufferDelay);
continue;
}
break;
}
LeaveCriticalSection(&critSect);
// while (NumBuffersInUse)
// Sleep(BufferDelay);
{ CHAR b[256]; wsprintf(b, "%2d: All buffers dequeued.\n", NumBuffersInUse); OutputDebugString(b); }
BufferPoolReset();
}
else
{
{ CHAR b[256]; wsprintf(b, "%2d: Waiting %dms...\n", NumBuffersInUse, BufferDelay); OutputDebugString(b); }
Sleep(BufferDelay);
{ CHAR b[256]; wsprintf(b, "%2d: Wait finished.\n", NumBuffersInUse); OutputDebugString(b); }
}
}
/*****************************************************************************************************************************/
#define DEVLIST_MAX 20
static void print_device_list(void){
UINT num;
int i, list_num;
WAVEOUTCAPS woc;
typedef struct tag_DEVICELIST{
int deviceID;
char name[256];
} DEVICELIST;
DEVICELIST device[DEVLIST_MAX];
num = waveOutGetNumDevs();
list_num=0;
for(i = 0 ; i < (int)num && i < DEVLIST_MAX ; i++){
if (MMSYSERR_NOERROR == waveOutGetDevCaps((UINT)i, &woc, sizeof(woc)) ){
device[list_num].deviceID=i;
strcpy(device[list_num].name, woc.szPname);
list_num++;
}
}
for(i=0;i<list_num;i++){
//ctl_cmsg(CMSG_ERROR, VERB_NORMAL, "%2d %s", device[i].deviceID, device[i].name);
}
}
}