From 9beeeadca3d347fefd46da2ef190d3be9653a4ff Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Mon, 31 May 2010 20:01:59 +0200 Subject: wildmidi plugin --- plugins/wildmidi/src/wildmidi_lib.c | 5072 +++++++++++++++++++++++++++++++++++ 1 file changed, 5072 insertions(+) create mode 100644 plugins/wildmidi/src/wildmidi_lib.c (limited to 'plugins/wildmidi/src/wildmidi_lib.c') diff --git a/plugins/wildmidi/src/wildmidi_lib.c b/plugins/wildmidi/src/wildmidi_lib.c new file mode 100644 index 00000000..315bf1a4 --- /dev/null +++ b/plugins/wildmidi/src/wildmidi_lib.c @@ -0,0 +1,5072 @@ +/* + wildmidi_lib.c + + Midi Wavetable Processing library + + Copyright (C)2001-2004 Chris Ison + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Email: cisos@bigpond.net.au + wildcode@users.sourceforge.net + + $Id: wildmidi_lib.c,v 1.18 2004/01/28 05:45:09 wildcode Exp $ + + ======================================== + Changelog + ---------------------------------------- + Aug 3, 2003 + - changed kill envelope from 6th to 5th + - changed data_length, loop_start, loop_end to 22:10 fixed point + - added fractional position to loop_start and loop_end + - added fake reverb + + Aug 4, 2003 + - added MIDI_EVENT_DEBUG to midi event functions + - fixed hold release killing off notes that hadn't been turned off + by note off + - sped up fake reverb by doing it outside the channel mixing loop + + Aug 5, 2003 + - removed note_table init from ParseNewMidi, entries are now fully reset + in do_note_on + - moved fast kill envelope setting to sample loading + - removed envelopes from notes, use ones from sample instead + - optimized do_amp_setup functions + - do_control_volume, do_control_expression, do_channel_pressure, + changed from setting note_table[] to note[] for performance. + - optimizations of sample conversion, + + Aug 6, 2003 + - removed changing sample volumes, the amp setting is now apart of + the midi volume maths. + - re-write conversion functions to make them more clearer and less bug prone + + Aug 7, 2003 + - fixed volume, expression and preasure changes effecting all notes. + + Aug 8, 2003 + - spead up midi processing by using an event index + + Aug 9, 2003 + - spead up sampling and mixing by using a seperate function depending on fixed + modes + - fixed data lock where it would sleep reguardless of lock state + - fixed memory leak ... oops, forgot a free + - removed track data storge, isn't required by the core functions + + Aug 10, 2003 + - created error function and changed all error messages to use it + - malloc, calloc, realloc audit ensuring all are error checked. + - fixed potential reading beyond end of midi bug + + Aug 11, 2003 + - fixed expensive interpolation over-running the sample buffer + - changed stereo option so that changing it worked right away + + Aug 14, 2003 + - optimizations for and to the frequency calc code + - removal of wide stereo (it sucked anyway) + + Aug 15, 2003 + - fixed volume levels for panning when non-linear volumes are used + - removed fake reberb, it sucked on better sound systems. + + Aug 17, 2003 + - fixed autoamp + - added env_time#= and env_level#= to timiidty.cfg parser. + - fixed bug where last event in the midi before the last eot would + have a large delta. This is a bug in the midi file itself. + - fixed some midi's having no sound cause they don't supply patch information. + Now defaulting all channels to bank 0, patch 0. + + Aug 18, 2003 + - preload samples + - optimized envelope checking and controler code + - fixed bug where some samples have an envelope rate setting that doesn't + actually mean anything .. ie: 0x00 0x40 0x80 0xC0 + - fixed amp bug where initial left/right levels were set to 0 + - added timidity's keep=[loop|env] support for drum patches, + now ignores loops and env settings for drum patches unless keep=[loop|env] + is in the patch line in the config. + + Aug 21, 2003 + - float to fixed point math conversions. + - frequency range locked to 100 steps between notes + NOTE:need to test slow pitchbends with this, fast ones are fine + + Aug 24, 2003 + - optimized sample conversions + - optimized note handling and sample/envelope position checks + + Aug 28, 2003 + - compile level optimizations + NOTE: gcc builtins used + - numerous bug fixes + + Aug 30, 2003 + - fixed sample inc calculation bug + - fixed panning volumes, now percieved volume of the sample is the same no matter + panning position. + +` Sep 2, 2003 + - made noteoff/hold behaviour match midi standard + - added remove=sustain to patch line + - added all sound off controller + - fixed all notes off to only effect notes that aren't being held + - changed envelope behaviour so that only non-sustaned samples hit envelope 4 + while note is on. + - Added all controllers off event + + + Sep 4, 2003 + - added master sample data lock + - improved performance of the resampling algo + + ======================================== +*/ + +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# include +#endif +#include "config.h" +#include "wildmidi_lib.h" + +/* + * ========================= + * Global Data and Data Structs + * ========================= + */ + +int WM_Initialized = 0; +signed short int WM_MasterVolume = 948; +unsigned short int WM_SampleRate = 0; +unsigned short int WM_MixerOptions = 0; + +char WM_Version[] = "WildMidi Processing Library " WILDMIDILIB_VERSION; + +struct _lowpass { + signed long int in[2]; + signed long int out[2]; +}; + +struct _filter { + signed long int *delay[4][2]; + unsigned long int delay_pos[4][2]; + struct _lowpass lowpass[4][2]; + signed long int in[2][2]; + signed long int out[2][2]; +}; + +struct _env { + float time; + float level; + unsigned char set; +}; + +struct _sample { + unsigned long int data_length; + unsigned long int loop_start; + unsigned long int loop_end; + unsigned long int loop_size; + unsigned char loop_fraction; + unsigned short int rate; + unsigned long int freq_low; + unsigned long int freq_high; + unsigned long int freq_root; + unsigned char modes; + unsigned long int env_rate[7]; + unsigned long int env_target[7]; + unsigned long int inc_div; + signed short *data; + signed short max_peek; + signed short min_peek; + signed long int peek_adjust; + struct _sample *next; +}; + +struct _patch { + unsigned short patchid; + unsigned char loaded; + char *filename; + signed short int amp; + unsigned char keep; + unsigned char remove; + struct _env env[6]; + unsigned char note; + unsigned long int inuse_count; + struct _sample *first_sample; + struct _patch *next; +}; + +struct _patch *patch[128]; + +int patch_lock; + +struct _channel { + unsigned char bank; + struct _patch *patch; + unsigned char hold; + unsigned char volume; + unsigned char pressure; + unsigned char expression; + signed char balance; + signed char pan; + signed short int left_adjust; + signed short int right_adjust; + signed short int pitch; + signed short int pitch_range; + signed long int pitch_adjust; + unsigned short reg_data; +}; + +#define HOLD_OFF 0x02 + +struct _note { + unsigned short noteid; + unsigned char velocity; + struct _patch *patch; + struct _sample *sample; + unsigned long int sample_pos; + unsigned long int sample_inc; + signed long int env_inc; + unsigned char env; + unsigned long int env_level; + unsigned char modes; + unsigned char hold; + unsigned char active; + struct _note *next; + signed short int vol_lvl; +}; + +struct _miditrack { + unsigned long int length; + unsigned long int ptr; + unsigned long int delta; + unsigned char running_event; + unsigned char EOT; +}; + +struct _mdi_patches { + struct _patch *patch; + struct _mdi_patch *next; +}; + +struct _mdi_index { + unsigned long int offset; + unsigned char event; + unsigned long int delta; +}; + +struct _mdi { + int lock; + unsigned char *data; + unsigned long int size; + unsigned short int divisions ; + unsigned short midi_master_vol; + unsigned long int samples_per_delta; + unsigned long int samples_to_mix; + struct _mdi_index * index; + unsigned long int index_count; + unsigned long int index_size; + struct _WM_Info info; + struct _WM_Info *tmp_info; + unsigned char recalc_samples; + struct _channel channel[16]; + struct _note *note[128]; + struct _note **last_note; + struct _note note_table[2][16][128]; + + struct _patch **patches; + unsigned long int patch_count; + unsigned long int sample_count; + signed short int amp; + +// setup data for auto amp + signed long int log_cur_vol; + signed long int lin_cur_vol; + signed long int log_max_vol; + signed long int lin_max_vol; + + unsigned char ch_vol[16]; + unsigned char ch_exp[16]; + unsigned char note_vel[16][128]; + + struct _filter filter; +}; + +/* Gauss Interpolation code adapted from code supplied by Eric. A. Welsh */ + +double newt_coeffs[58][58]; /* for start/end of samples */ +float *gauss_table[(1<<10)] = {0}; /* don't need doubles */ +int gauss_window[35] = {0}; +int gauss_n = 34; /* do not set this value higher than 34 */ + /* 34 is as high as we can go before errors crop up */ + +void init_gauss (void) { + /* init gauss table */ + int n = 34; + int m, i, k, n_half = (n>>1); + int j; + int sign; + double ck; + double x, x_inc, xz; + double z[35]; + float *gptr; + + 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; + } + z[i] = i / (4*M_PI); + } + + for (i = 0; i <= n; i++) + for (j = 0, sign = pow(-1, i); j <= i; j++, sign *= -1) + newt_coeffs[i][j] *= sign; + + + x_inc = 1.0 / (1<<10); + for (m = 0, x = 0.0; m < (1<<10); m++, x += x_inc) { + xz = (x + n_half) / (4*M_PI); + gptr = gauss_table[m] = realloc(gauss_table[m], (n+1)*sizeof(float)); + + for (k = 0; k <= n; k++) { + ck = 1.0; + + for (i = 0; i <= n; i++) { + if (i == k) + continue; + + ck *= (sin(xz - z[i])) / (sin(z[k] - z[i])); + } + *gptr++ = ck; + } + } +} + +unsigned long int delay_size[4][2]; +signed long int a[5][2]; +signed long int b[5][2]; +signed long int gain_in[4]; +signed long int gain_out[4]; + +void init_lowpass (void) { + float c = 0; + int i; + float f[] = { 512.0, 1024.0, 2048.0, 4096.0 , 8192.0}; + float aa, ab, ba, bb; + + for (i = 0; i < 5; i++) { + c = 1.0 / tan(3.141592654 * f[i] / WM_SampleRate); + aa = 1.0 / (1.0 + 1.4 * c + c * c); + ab = 2.0 * aa; + ba = 2.0 * (1.0 - c * c) * aa; + bb = (1.0 - 1.4 * c + c * c) * aa; + a[i][0] = (signed long int)(aa * 1024.0); + a[i][1] = (signed long int)(ab * 1024.0); + b[i][0] = (signed long int)(ba * 1024.0); + b[i][1] = (signed long int)(bb * 1024.0); + } + gain_in[0] = 772; + gain_out[0] = 772; + gain_in[1] = 570; + gain_out[1] = 570; + gain_in[2] = 520; + gain_out[2] = 520; + gain_in[3] = 512; + gain_out[3] = 512; + + delay_size[0][0] = 2191 * WM_SampleRate / 44100; + delay_size[0][1] = (2191 + 19) * WM_SampleRate / 44100; + delay_size[1][0] = (2971 + 19) * WM_SampleRate / 44100; + delay_size[1][1] = 2971 * WM_SampleRate / 44100; + delay_size[2][0] = 3253 * WM_SampleRate / 44100; + delay_size[2][1] = (3253 + 19) * WM_SampleRate / 44100; + delay_size[3][0] = (3307 + 19) * WM_SampleRate / 44100; + delay_size[3][1] = 3307 * WM_SampleRate / 44100; + +} + +struct _hndl { + void * handle; + struct _hndl *next; + struct _hndl *prev; +}; + +struct _hndl * first_handle = NULL; + +//f: ( VOLUME / 127 ) +//f: pow(( VOLUME / 127 ), 1.660964047 ) +//f: pow(( VOLUME / 127 ), 2.0 ) +//f: pow(( VOLUME / 127 ), 0.602059991 ) +//f: pow(( VOLUME / 127 ), 0.5 ) + +signed short int lin_volume[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 129, 137, 145, 153, 161, 169, 177, 185, 193, 201, 209, 217, 225, 233, 241, 249, 258, 266, 274, 282, 290, 298, 306, 314, 322, 330, 338, 346, 354, 362, 370, 378, 387, 395, 403, 411, 419, 427, 435, 443, 451, 459, 467, 475, 483, 491, 499, 507, 516, 524, 532, 540, 548, 556, 564, 572, 580, 588, 596, 604, 612, 620, 628, 636, 645, 653, 661, 669, 677, 685, 693, 701, 709, 717, 725, 733, 741, 749, 757, 765, 774, 782, 790, 798, 806, 814, 822, 830, 838, 846, 854, 862, 870, 878, 886, 894, 903, 911, 919, 927, 935, 943, 951, 959, 967, 975, 983, 991, 999, 1007, 1015, 1024 }; +signed short int log_volume[] = { 0, 0, 1, 2, 3, 4, 6, 8, 10, 12, 15, 17, 20, 23, 26, 29, 32, 36, 39, 43, 47, 51, 55, 59, 64, 68, 73, 78, 83, 88, 93, 98, 103, 109, 114, 120, 126, 132, 138, 144, 150, 156, 162, 169, 176, 182, 189, 196, 203, 210, 217, 224, 232, 239, 247, 255, 262, 270, 278, 286, 294, 302, 311, 319, 328, 336, 345, 353, 362, 371, 380, 389, 398, 408, 417, 426, 436, 446, 455, 465, 475, 485, 495, 505, 515, 525, 535, 546, 556, 567, 577, 588, 599, 610, 621, 632, 643, 654, 665, 677, 688, 699, 711, 723, 734, 746, 758, 770, 782, 794, 806, 818, 831, 843, 855, 868, 880, 893, 906, 919, 931, 944, 957, 970, 984, 997, 1010, 1024 }; +signed short int sqr_volume[] = { 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 14, 16, 18, 20, 22, 25, 27, 30, 33, 36, 39, 42, 46, 49, 53, 57, 61, 65, 69, 73, 77, 82, 86, 91, 96, 101, 106, 111, 117, 122, 128, 134, 140, 146, 152, 158, 165, 171, 178, 185, 192, 199, 206, 213, 221, 228, 236, 244, 251, 260, 268, 276, 284, 293, 302, 311, 320, 329, 338, 347, 357, 366, 376, 386, 396, 406, 416, 426, 437, 447, 458, 469, 480, 491, 502, 514, 525, 537, 549, 560, 572, 585, 597, 609, 622, 634, 647, 660, 673, 686, 699, 713, 726, 740, 754, 768, 782, 796, 810, 825, 839, 854, 869, 884, 899, 914, 929, 944, 960, 976, 992, 1007, 1024 }; +//signed short int pan_volume[] = { 0, 55, 84, 107, 127, 146, 162, 178, 193, 208, 221, 234, 247, 259, 271, 282, 294, 305, 315, 326, 336, 346, 356, 366, 375, 384, 394, 403, 412, 420, 429, 438, 446, 454, 463, 471, 479, 487, 495, 503, 510, 518, 525, 533, 540, 548, 555, 562, 570, 577, 584, 591, 598, 605, 611, 618, 625, 632, 638, 645, 651, 658, 664, 671, 677, 684, 690, 696, 703, 709, 715, 721, 727, 733, 739, 745, 751, 757, 763, 769, 775, 781, 786, 792, 798, 804, 809, 815, 821, 826, 832, 837, 843, 848, 854, 859, 865, 870, 876, 881, 886, 892, 897, 902, 907, 913, 918, 923, 928, 933, 939, 944, 949, 954, 959, 964, 969, 974, 979, 984, 989, 994, 999, 1004, 1009, 1014, 1019, 1024 }; +signed short int pan_volume[] = { 0, 90, 128, 157, 181, 203, 222, 240, 257, 272, 287, 301, 314, 327, 339, 351, 363, 374, 385, 396, 406, 416, 426, 435, 445, 454, 463, 472, 480, 489, 497, 505, 514, 521, 529, 537, 545, 552, 560, 567, 574, 581, 588, 595, 602, 609, 616, 622, 629, 636, 642, 648, 655, 661, 667, 673, 679, 686, 692, 697, 703, 709, 715, 721, 726, 732, 738, 743, 749, 754, 760, 765, 771, 776, 781, 786, 792, 797, 802, 807, 812, 817, 822, 827, 832, 837, 842, 847, 852, 857, 862, 866, 871, 876, 880, 885, 890, 894, 899, 904, 908, 913, 917, 922, 926, 931, 935, 939, 944, 948, 953, 957, 961, 965, 970, 974, 978, 982, 987, 991, 995, 999, 1003, 1007, 1011, 1015, 1019, 1024 }; + +unsigned long int reverb_val = 92; +unsigned long int comb_size[8][2]; +unsigned long int allpass_size[2][2]; + +float env_time_table[] = { + 0.0, 0.092857143, 0.046428571, 0.030952381, 0.023214286, 0.018571429, 0.015476190, 0.013265306, 0.011607143, 0.010317460, 0.009285714, 0.008441558, 0.007738095, 0.007142857, 0.006632653, 0.006190476, 0.005803571, 0.005462185, 0.005158730, 0.004887218, 0.004642857, 0.004421769, 0.004220779, 0.004037267, 0.003869048, 0.003714286, 0.003571429, 0.003439153, 0.003316327, 0.003201970, 0.003095238, 0.002995392, 0.002901786, 0.002813853, 0.002731092, 0.002653061, 0.002579365, 0.002509653, 0.002443609, 0.002380952, 0.002321429, 0.002264808, 0.002210884, 0.002159468, 0.002110390, 0.002063492, 0.002018634, 0.001975684, 0.001934524, 0.001895044, 0.001857143, 0.001820728, 0.001785714, 0.001752022, 0.001719577, 0.001688312, 0.001658163, 0.001629073, 0.001600985, 0.001573850, 0.001547619, 0.001522248, 0.001497696, 0.001473923, + 0.0, 0.742857143, 0.371428571, 0.247619048, 0.185714286, 0.148571429, 0.123809524, 0.106122449, 0.092857143, 0.082539683, 0.074285714, 0.067532468, 0.061904762, 0.057142857, 0.053061224, 0.049523810, 0.046428571, 0.043697479, 0.041269841, 0.039097744, 0.037142857, 0.035374150, 0.033766234, 0.032298137, 0.030952381, 0.029714286, 0.028571429, 0.027513228, 0.026530612, 0.025615764, 0.024761905, 0.023963134, 0.023214286, 0.022510823, 0.021848739, 0.021224490, 0.020634921, 0.020077220, 0.019548872, 0.019047619, 0.018571429, 0.018118467, 0.017687075, 0.017275748, 0.016883117, 0.016507937, 0.016149068, 0.015805471, 0.015476190, 0.015160350, 0.014857143, 0.014565826, 0.014285714, 0.014016173, 0.013756614, 0.013506494, 0.013265306, 0.013032581, 0.012807882, 0.012590799, 0.012380952, 0.012177986, 0.011981567, 0.011791383, + 0.0, 5.942857143, 2.971428571, 1.980952381, 1.485714286, 1.188571429, 0.990476190, 0.848979592, 0.742857143, 0.660317460, 0.594285714, 0.540259740, 0.495238095, 0.457142857, 0.424489796, 0.396190476, 0.371428571, 0.349579832, 0.330158730, 0.312781955, 0.297142857, 0.282993197, 0.270129870, 0.258385093, 0.247619048, 0.237714286, 0.228571429, 0.220105820, 0.212244898, 0.204926108, 0.198095238, 0.191705069, 0.185714286, 0.180086580, 0.174789916, 0.169795918, 0.165079365, 0.160617761, 0.156390977, 0.152380952, 0.148571429, 0.144947735, 0.141496599, 0.138205980, 0.135064935, 0.132063492, 0.129192547, 0.126443769, 0.123809524, 0.121282799, 0.118857143, 0.116526611, 0.114285714, 0.112129380, 0.110052910, 0.108051948, 0.106122449, 0.104260652, 0.102463054, 0.100726392, 0.099047619, 0.097423888, 0.095852535, 0.094331066, + 0.0, 47.542857143, 23.771428571, 15.847619048, 11.885714286, 9.508571429, 7.923809524, 6.791836735, 5.942857143, 5.282539683, 4.754285714, 4.322077922, 3.961904762, 3.657142857, 3.395918367, 3.169523810, 2.971428571, 2.796638655, 2.641269841, 2.502255639, 2.377142857, 2.263945578, 2.161038961, 2.067080745, 1.980952381, 1.901714286, 1.828571429, 1.760846561, 1.697959184, 1.639408867, 1.584761905, 1.533640553, 1.485714286, 1.440692641, 1.398319328, 1.358367347, 1.320634921, 1.284942085, 1.251127820, 1.219047619, 1.188571429, 1.159581882, 1.131972789, 1.105647841, 1.080519481, 1.056507937, 1.033540373, 1.011550152, 0.990476190, 0.970262391, 0.950857143, 0.932212885, 0.914285714, 0.897035040, 0.880423280, 0.864415584, 0.848979592, 0.834085213, 0.819704433, 0.805811138, 0.792380952, 0.779391101, 0.766820276, 0.754648526 +}; + +#if 0 +unsigned long int freq_table[] = { + 8372018, 8376855, 8381695, 8386538, 8391384, 8396232, 8401084, 8405938, 8410795, 8415654, 8420517, 8425382, 8430250, 8435121, 8439995, 8444871, 8449751, 8454633, 8459518, 8464406, 8469296, 8474190, 8479086, 8483985, 8488887, 8493792, 8498700, 8503610, 8508523, 8513439, 8518358, 8523280, 8528205, 8533132, 8538063, 8542996, 8547932, 8552871, 8557813, 8562757, 8567705, 8572655, 8577608, 8582564, 8587523, 8592485, 8597450, 8602417, 8607387, 8612361, 8617337, 8622316, 8627298, 8632282, 8637270, 8642261, 8647254, 8652250, 8657250, 8662252, 8667257, 8672264, 8677275, 8682289, 8687305, 8692325, 8697347, 8702372, 8707400, 8712431, 8717465, 8722502, 8727542, 8732585, 8737630, 8742679, 8747730, 8752785, 8757842, 8762902, 8767965, 8773031, 8778100, 8783172, 8788247, 8793325, 8798405, 8803489, 8808575, 8813665, 8818757, 8823853, 8828951, 8834052, 8839157, 8844264, 8849374, 8854487, 8859603, 8864722, 8869844, 8874969, 8880097, 8885227, 8890361, 8895498, 8900638, 8905780, 8910926, 8916075, 8921226, 8926381, 8931538, 8936699, 8941863, 8947029, 8952199, 8957371, 8962546, 8967725, 8972906, 8978091, 8983278, 8988469, 8993662, 8998859, 9004058, 9009260, 9014466, 9019674, 9024886, 9030100, 9035318, 9040538, 9045762, 9050988, 9056218, 9061451, 9066686, 9071925, 9077166, 9082411, 9087659, 9092910, 9098163, 9103420, 9108680, 9113943, 9119209, 9124478, 9129750, 9135025, 9140303, 9145584, 9150868, 9156156, 9161446, 9166739, 9172036, 9177335, 9182638, 9187944, 9193252, 9198564, 9203879, 9209197, 9214518, 9219842, 9225169, 9230499, 9235832, 9241169, 9246508, 9251851, 9257196, 9262545, 9267897, 9273252, 9278610, 9283971, 9289335, 9294702, 9300073, 9305446, 9310823, 9316202, 9321585, 9326971, 9332360, 9337752, 9343147, 9348546, 9353947, 9359352, 9364760, 9370171, 9375585, 9381002, 9386422, 9391845, 9397272, 9402701, 9408134, 9413570, 9419009, 9424451, 9429897, 9435345, 9440797, 9446252, 9451710, 9457171, 9462635, 9468102, 9473573, 9479047, 9484524, 9490004, 9495487, 9500973, 9506463, 9511955, 9517451, 9522950, 9528453, 9533958, 9539467, 9544979, 9550494, 9556012, 9561533, 9567058, 9572585, 9578116, 9583650, 9589188, 9594728, 9600272, 9605819, 9611369, 9616922, 9622479, 9628039, 9633602, 9639168, 9644737, 9650310, 9655886, 9661465, 9667047, 9672633, 9678221, 9683813, 9689409, 9695007, 9700609, 9706214, 9711822, 9717433, 9723048, 9728666, 9734287, 9739911, 9745539, 9751170, 9756804, 9762441, 9768082, 9773726, 9779373, 9785023, 9790677, 9796334, 9801994, 9807657, 9813324, 9818994, 9824667, 9830344, 9836024, 9841707, 9847394, 9853083, 9858776, 9864473, 9870172, 9875875, 9881581, 9887291, 9893003, 9898719, 9904439, 9910162, 9915887, 9921617, 9927349, 9933085, 9938825, 9944567, 9950313, 9956062, 9961815, 9967570, 9973330, 9979092, 9984858, 9990627, 9996399, 10002175, 10007954, 10013737, 10019523, 10025312, 10031104, 10036900, 10042700, 10048502, 10054308, 10060117, 10065930, 10071746, 10077565, 10083388, 10089214, 10095043, 10100876, 10106712, 10112552, 10118395, 10124241, 10130091, 10135944, 10141800, 10147660, 10153523, 10159390, 10165260, 10171133, 10177010, 10182890, 10188774, 10194661, 10200551, 10206445, 10212342, 10218243, 10224147, 10230054, 10235965, 10241879, 10247797, 10253718, 10259642, 10265570, 10271502, 10277436, 10283374, 10289316, 10295261, 10301210, 10307162, 10313117, 10319076, 10325038, 10331004, 10336973, 10342945, 10348921, 10354901, 10360884, 10366870, 10372860, 10378853, 10384850, 10390850, 10396854, 10402861, 10408872, 10414886, 10420904, 10426925, 10432949, 10438977, 10445009, 10451044, 10457083, 10463124, 10469170, 10475219, 10481271, 10487327, 10493387, 10499450, 10505516, 10511586, 10517660, 10523737, 10529817, 10535901, 10541989, 10548080, 10554174, 10560273, 10566374, 10572480, 10578589, 10584701, 10590817, 10596936, 10603059, 10609186, 10615316, 10621449, 10627586, 10633727, 10639871, 10646019, 10652170, 10658325, 10664483, 10670645, 10676811, 10682980, 10689153, 10695329, 10701509, 10707692, 10713879, 10720069, 10726264, 10732461, 10738662, 10744867, 10751076, 10757288, 10763503, 10769722, 10775945, 10782172, 10788402, 10794635, 10800872, 10807113, 10813357, 10819605, 10825857, 10832112, 10838371, 10844634, 10850900, 10857169, 10863443, 10869720, 10876000, 10882284, 10888572, 10894864, 10901159, 10907457, 10913760, 10920066, 10926375, 10932689, 10939006, 10945326, 10951650, 10957978, 10964310, 10970645, 10976984, 10983326, 10989673, 10996022, 11002376, 11008733, 11015094, 11021459, 11027827, 11034199, 11040574, 11046954, 11053337, 11059723, 11066114, 11072508, 11078905, 11085307, 11091712, 11098121, 11104533, 11110949, 11117369, 11123793, 11130220, 11136651, 11143086, 11149525, 11155967, 11162413, 11168863, 11175316, 11181773, 11188234, 11194699, 11201167, 11207639, 11214115, 11220594, 11227078, 11233565, 11240055, 11246550, 11253048, 11259550, 11266056, 11272566, 11279079, 11285596, 11292117, 11298642, 11305170, 11311702, 11318238, 11324778, 11331321, 11337868, 11344420, 11350974, 11357533, 11364095, 11370662, 11377232, 11383805, 11390383, 11396964, 11403550, 11410139, 11416731, 11423328, 11429928, 11436533, 11443141, 11449753, 11456368, 11462988, 11469611, 11476238, 11482869, 11489504, 11496143, 11502785, 11509432, 11516082, 11522736, 11529394, 11536056, 11542721, 11549390, 11556064, 11562741, 11569422, 11576107, 11582795, 11589488, 11596184, 11602885, 11609589, 11616297, 11623009, 11629725, 11636444, 11643168, 11649895, 11656627, 11663362, 11670101, 11676844, 11683591, 11690342, 11697097, 11703855, 11710618, 11717384, 11724154, 11730929, 11737707, 11744489, 11751275, 11758065, 11764859, 11771656, 11778458, 11785264, 11792073, 11798887, 11805704, 11812526, 11819351, 11826180, 11833013, 11839851, 11846692, 11853537, 11860386, 11867239, 11874096, 11880956, 11887821, 11894690, 11901563, 11908440, 11915320, 11922205, 11929094, 11935986, 11942883, 11949784, 11956688, 11963597, 11970510, 11977426, 11984347, 11991271, 11998200, 12005133, 12012069, 12019010, 12025954, 12032903, 12039856, 12046812, 12053773, 12060738, 12067706, 12074679, 12081656, 12088637, 12095622, 12102610, 12109603, 12116600, 12123601, 12130606, 12137615, 12144629, 12151646, 12158667, 12165692, 12172722, 12179755, 12186793, 12193834, 12200880, 12207930, 12214983, 12222041, 12229103, 12236169, 12243239, 12250313, 12257392, 12264474, 12271561, 12278651, 12285746, 12292844, 12299947, 12307054, 12314165, 12321280, 12328400, 12335523, 12342651, 12349782, 12356918, 12364058, 12371202, 12378350, 12385502, 12392658, 12399819, 12406984, 12414152, 12421325, 12428502, 12435684, 12442869, 12450059, 12457252, 12464450, 12471652, 12478858, 12486069, 12493283, 12500502, 12507725, 12514952, 12522183, 12529418, 12536658, 12543901, 12551149, 12558401, 12565658, 12572918, 12580183, 12587452, 12594725, 12602002, 12609283, 12616569, 12623859, 12631153, 12638451, 12645754, 12653061, 12660372, 12667687, 12675006, 12682330, 12689658, 12696990, 12704326, 12711667, 12719012, 12726361, 12733714, 12741072, 12748433, 12755800, 12763170, 12770544, 12777923, 12785306, 12792694, 12800085, 12807481, 12814882, 12822286, 12829695, 12837108, 12844525, 12851947, 12859373, 12866803, 12874237, 12881676, 12889119, 12896567, 12904018, 12911474, 12918934, 12926399, 12933868, 12941341, 12948819, 12956301, 12963787, 12971277, 12978772, 12986271, 12993775, 13001283, 13008795, 13016311, 13023832, 13031357, 13038887, 13046421, 13053959, 13061502, 13069049, 13076600, 13084156, 13091716, 13099280, 13106849, 13114422, 13122000, 13129582, 13137168, 13144759, 13152354, 13159953, 13167557, 13175165, 13182778, 13190395, 13198016, 13205642, 13213273, 13220907, 13228546, 13236190, 13243838, 13251490, 13259147, 13266808, 13274474, 13282144, 13289818, 13297497, 13305180, 13312868, 13320560, 13328257, 13335958, 13343663, 13351373, 13359088, 13366807, 13374530, 13382258, 13389990, 13397727, 13405468, 13413214, 13420964, 13428719, 13436478, 13444241, 13452010, 13459782, 13467559, 13475341, 13483127, 13490918, 13498713, 13506512, 13514316, 13522125, 13529938, 13537756, 13545578, 13553405, 13561236, 13569071, 13576912, 13584756, 13592606, 13600460, 13608318, 13616181, 13624048, 13631920, 13639797, 13647678, 13655564, 13663454, 13671349, 13679248, 13687152, 13695060, 13702974, 13710891, 13718813, 13726740, 13734671, 13742607, 13750548, 13758493, 13766443, 13774397, 13782356, 13790319, 13798287, 13806260, 13814237, 13822219, 13830206, 13838197, 13846193, 13854193, 13862198, 13870208, 13878222, 13886241, 13894264, 13902292, 13910325, 13918363, 13926405, 13934451, 13942503, 13950559, 13958619, 13966685, 13974755, 13982829, 13990909, 13998993, 14007081, 14015175, 14023273, 14031375, 14039483, 14047595, 14055712, 14063833, 14071959, 14080090, 14088225, 14096366, 14104511, 14112660, 14120815, 14128974, 14137137, 14145306, 14153479, 14161657, 14169840, 14178027, 14186219, 14194416, 14202618, 14210824, 14219035, 14227251, 14235471, 14243697, 14251927, 14260161, 14268401, 14276645, 14284894, 14293148, 14301407, 14309670, 14317938, 14326211, 14334489, 14342772, 14351059, 14359351, 14367648, 14375949, 14384256, 14392567, 14400883, 14409204, 14417530, 14425860, 14434196, 14442536, 14450881, 14459230, 14467585, 14475944, 14484309, 14492678, 14501052, 14509430, 14517814, 14526202, 14534596, 14542994, 14551397, 14559805, 14568217, 14576635, 14585057, 14593485, 14601917, 14610354, 14618796, 14627242, 14635694, 14644151, 14652612, 14661078, 14669550, 14678026, 14686507, 14694993, 14703483, 14711979, 14720480, 14728985, 14737496, 14746011, 14754531, 14763057, 14771587, 14780122, 14788662, 14797207, 14805757, 14814311, 14822871, 14831436, 14840005, 14848580, 14857160, 14865744, 14874334, 14882928, 14891527, 14900132, 14908741, 14917355, 14925975, 14934599, 14943228, 14951862, 14960502, 14969146, 14977795, 14986449, 14995109, 15003773, 15012442, 15021116, 15029795, 15038480, 15047169, 15055863, 15064563, 15073267, 15081976, 15090691, 15099410, 15108135, 15116864, 15125599, 15134338, 15143083, 15151833, 15160587, 15169347, 15178112, 15186882, 15195657, 15204437, 15213222, 15222013, 15230808, 15239608, 15248414, 15257224, 15266040, 15274861, 15283687, 15292518, 15301354, 15310195, 15319041, 15327893, 15336749, 15345611, 15354477, 15363349, 15372226, 15381108, 15389996, 15398888, 15407786, 15416688, 15425596, 15434509, 15443427, 15452350, 15461279, 15470212, 15479151, 15488095, 15497044, 15505998, 15514958, 15523922, 15532892, 15541867, 15550847, 15559832, 15568823, 15577819, 15586820, 15595826, 15604837, 15613853, 15622875, 15631902, 15640934, 15649972, 15659014, 15668062, 15677115, 15686173, 15695237, 15704306, 15713380, 15722459, 15731543, 15740633, 15749728, 15758828, 15767934, 15777045, 15786161, 15795282, 15804408, 15813540, 15822677, 15831820, 15840967, 15850120, 15859279, 15868442, 15877611, 15886785, 15895965, 15905149, 15914339, 15923535, 15932735, 15941941, 15951153, 15960369, 15969591, 15978818, 15988051, 15997289, 16006532, 16015781, 16025035, 16034294, 16043559, 16052829, 16062104, 16071385, 16080671, 16089962, 16099259, 16108561, 16117869, 16127182, 16136500, 16145824, 16155153, 16164488, 16173828, 16183173, 16192523, 16201880, 16211241, 16220608, 16229980, 16239358, 16248741, 16258130, 16267524, 16276923, 16286328, 16295738, 16305154, 16314575, 16324002, 16333434, 16342871, 16352314, 16361763, 16371217, 16380676, 16390141, 16399611, 16409087, 16418568, 16428055, 16437547, 16447044, 16456548, 16466056, 16475570, 16485090, 16494615, 16504146, 16513682, 16523224, 16532771, 16542323, 16551882, 16561445, 16571015, 16580589, 16590170, 16599755, 16609347, 16618944, 16628546, 16638154, 16647768, 16657387, 16667012, 16676642, 16686278, 16695919, 16705566, 16715219, 16724877, 16734540 +}; +#endif + +unsigned long int freq_table[] = { + 837201792, 837685632, 838169728, 838653568, 839138240, 839623232, 840108480, 840593984, 841079680, 841565184, 842051648, 842538240, 843025152, 843512320, 843999232, 844486976, 844975040, 845463360, 845951936, 846440320, 846929536, 847418944, 847908608, 848398656, 848888960, 849378944, 849869824, 850361024, 850852416, 851344192, 851835584, 852327872, 852820480, 853313280, 853806464, 854299328, 854793024, 855287040, 855781312, 856275904, 856770752, 857265344, 857760704, 858256448, 858752448, 859248704, 859744768, 860241600, 860738752, 861236160, 861733888, 862231360, 862729600, 863228160, 863727104, 864226176, 864725696, 865224896, 865724864, 866225152, 866725760, 867226688, 867727296, 868228736, 868730496, 869232576, 869734912, 870236928, 870739904, 871243072, 871746560, 872250368, 872754496, 873258240, 873762880, 874267840, 874773184, 875278720, 875783936, 876290112, 876796480, 877303232, 877810176, 878317504, 878824512, 879332416, 879840576, 880349056, 880857792, 881366272, 881875712, 882385280, 882895296, 883405440, 883915456, 884426304, 884937408, 885448832, 885960512, 886472512, + 886984192, 887496768, 888009728, 888522944, 889036352, 889549632, 890063680, 890578048, 891092736, 891607680, 892122368, 892637952, 893153792, 893670016, 894186496, 894703232, 895219648, 895737024, 896254720, 896772672, 897290880, 897808896, 898327744, 898846912, 899366336, 899886144, 900405568, 900925952, 901446592, 901967552, 902488768, 903010368, 903531584, 904053760, 904576256, 905099008, 905622016, 906144896, 906668480, 907192512, 907716800, 908241408, 908765632, 909290816, 909816256, 910342144, 910868160, 911394624, 911920768, 912447680, 912975104, 913502720, 914030592, 914558208, 915086784, 915615552, 916144768, 916674176, 917203968, 917733440, 918263744, 918794496, 919325440, 919856704, 920387712, 920919616, 921451840, 921984320, 922517184, 923049728, 923583168, 924116928, 924651008, 925185344, 925720000, 926254336, 926789696, 927325312, 927861120, 928397440, 928933376, 929470208, 930007296, 930544768, 931082560, 931619968, 932158464, 932697152, 933236160, 933775488, 934315072, 934854464, 935394688, 935935296, 936476224, 937017344, 937558208, 938100160, 938642304, 939184640, + 939727488, 940269888, 940813312, 941357056, 941900992, 942445440, 942990016, 943534400, 944079680, 944625280, 945171200, 945717440, 946263360, 946810176, 947357376, 947904832, 948452672, 949000192, 949548608, 950097280, 950646400, 951195776, 951745472, 952294912, 952845184, 953395904, 953946880, 954498176, 955049216, 955601088, 956153408, 956705920, 957258816, 957812032, 958364928, 958918848, 959472960, 960027456, 960582272, 961136768, 961692224, 962248000, 962804032, 963360448, 963916608, 964473600, 965031040, 965588736, 966146816, 966705152, 967263168, 967822144, 968381440, 968941120, 969501056, 970060736, 970621376, 971182272, 971743488, 972305088, 972866368, 973428608, 973991104, 974554048, 975117312, 975680768, 976243968, 976808192, 977372736, 977937536, 978502656, 979067584, 979633344, 980199488, 980765888, 981332736, 981899200, 982466688, 983034432, 983602624, 984171008, 984739776, 985308160, 985877632, 986447360, 987017472, 987587904, 988157952, 988729088, 989300416, 989872192, 990444224, 991016000, 991588672, 992161728, 992735168, 993308864, 993882880, 994456576, 995031296, + 995606336, 996181696, 996757440, 997332800, 997909184, 998485888, 999062912, 999640256, 1000217984, 1000795392, 1001373696, 1001952448, 1002531520, 1003110848, 1003689920, 1004270016, 1004850304, 1005431040, 1006012160, 1006592832, 1007174592, 1007756608, 1008339008, 1008921792, 1009504768, 1010087552, 1010671296, 1011255360, 1011839808, 1012424576, 1013009024, 1013594368, 1014180160, 1014766272, 1015352768, 1015938880, 1016526016, 1017113472, 1017701248, 1018289408, 1018877824, 1019465984, 1020055104, 1020644672, 1021234496, 1021824768, 1022414528, 1023005440, 1023596608, 1024188160, 1024780096, 1025371584, 1025964160, 1026557120, 1027150336, 1027744000, 1028337920, 1028931520, 1029526144, 1030121152, 1030716480, 1031312128, 1031907456, 1032503808, 1033100480, 1033697536, 1034294912, 1034892032, 1035490048, 1036088512, 1036687232, 1037286336, 1037885824, 1038484928, 1039085056, 1039685632, 1040286464, 1040887680, 1041488448, 1042090368, 1042692608, 1043295168, 1043898176, 1044501440, 1045104384, 1045708288, 1046312640, 1046917376, 1047522368, 1048127040, 1048732800, 1049338816, 1049945280, 1050552128, 1051158528, 1051765952, 1052373824, 1052982016, 1053590592, 1054199424, + 1054807936, 1055417600, 1056027456, 1056637760, 1057248448, 1057858752, 1058470016, 1059081728, 1059693824, 1060306304, 1060918336, 1061531392, 1062144896, 1062758656, 1063372928, 1063987392, 1064601664, 1065216896, 1065832448, 1066448448, 1067064704, 1067680704, 1068297728, 1068915136, 1069532864, 1070150976, 1070768640, 1071387520, 1072006720, 1072626240, 1073246080, 1073866368, 1074486272, 1075107200, 1075728512, 1076350208, 1076972160, 1077593856, 1078216704, 1078839680, 1079463296, 1080087040, 1080710528, 1081335168, 1081960064, 1082585344, 1083211008, 1083836928, 1084462592, 1085089280, 1085716352, 1086343936, 1086971648, 1087599104, 1088227712, 1088856576, 1089485824, 1090115456, 1090745472, 1091375104, 1092005760, 1092636928, 1093268352, 1093900160, 1094531584, 1095164160, 1095796992, 1096430336, 1097064064, 1097697280, 1098331648, 1098966400, 1099601536, 1100237056, 1100872832, 1101508224, 1102144768, 1102781824, 1103419136, 1104056832, 1104694144, 1105332608, 1105971328, 1106610432, 1107249920, 1107889152, 1108529408, 1109170048, 1109811072, 1110452352, 1111094144, 1111735552, 1112377984, 1113020928, 1113664128, 1114307712, 1114950912, 1115595264, 1116240000, 1116885120, + 1117530624, 1118175744, 1118821888, 1119468416, 1120115456, 1120762752, 1121410432, 1122057856, 1122706176, 1123355136, 1124004224, 1124653824, 1125303040, 1125953408, 1126604160, 1127255168, 1127906560, 1128557696, 1129209984, 1129862528, 1130515456, 1131168768, 1131822592, 1132475904, 1133130368, 1133785216, 1134440448, 1135096064, 1135751296, 1136407680, 1137064448, 1137721472, 1138379008, 1139036800, 1139694336, 1140353024, 1141012096, 1141671424, 1142331264, 1142990592, 1143651200, 1144312192, 1144973440, 1145635200, 1146296448, 1146958976, 1147621760, 1148285056, 1148948608, 1149612672, 1150276224, 1150940928, 1151606144, 1152271616, 1152937600, 1153603072, 1154269824, 1154936832, 1155604352, 1156272128, 1156939648, 1157608192, 1158277248, 1158946560, 1159616384, 1160286464, 1160956288, 1161627264, 1162298624, 1162970240, 1163642368, 1164314112, 1164987008, 1165660160, 1166333824, 1167007872, 1167681536, 1168356352, 1169031552, 1169707136, 1170383104, 1171059584, 1171735552, 1172412672, 1173090304, 1173768192, 1174446592, 1175124480, 1175803648, 1176483072, 1177163008, 1177843328, 1178523264, 1179204352, 1179885824, 1180567680, 1181249920, 1181932544, 1182614912, 1183298304, + 1183982208, 1184666368, 1185351040, 1186035328, 1186720640, 1187406464, 1188092672, 1188779264, 1189466368, 1190152960, 1190840832, 1191528960, 1192217600, 1192906624, 1193595136, 1194285056, 1194975232, 1195665792, 1196356736, 1197047296, 1197739136, 1198431360, 1199123968, 1199816960, 1200510336, 1201203328, 1201897600, 1202592128, 1203287040, 1203982464, 1204677504, 1205373696, 1206070272, 1206767232, 1207464704, 1208161664, 1208859904, 1209558528, 1210257536, 1210956928, 1211656832, 1212356224, 1213056768, 1213757952, 1214459392, 1215161216, 1215862656, 1216565376, 1217268352, 1217971840, 1218675712, 1219379200, 1220083840, 1220788992, 1221494528, 1222200448, 1222906752, 1223612672, 1224319872, 1225027456, 1225735424, 1226443648, 1227151616, 1227860864, 1228570496, 1229280512, 1229990912, 1230700928, 1231412096, 1232123776, 1232835840, 1233548288, 1234261248, 1234973696, 1235687424, 1236401536, 1237116032, 1237831040, 1238545536, 1239261312, 1239977472, 1240694144, 1241411072, 1242128512, 1242845568, 1243563776, 1244282496, 1245001600, 1245721088, 1246440192, 1247160448, 1247881216, 1248602368, 1249324032, 1250045184, 1250767616, 1251490432, 1252213632, 1252937344, 1253661440, + 1254385152, 1255110016, 1255835392, 1256561152, 1257287424, 1258013184, 1258740096, 1259467648, 1260195456, 1260923648, 1261651584, 1262380800, 1263110272, 1263840256, 1264570624, 1265301504, 1266031872, 1266763520, 1267495552, 1268227968, 1268961024, 1269693440, 1270427264, 1271161472, 1271896064, 1272631168, 1273365760, 1274101632, 1274838016, 1275574784, 1276311808, 1277049472, 1277786624, 1278525056, 1279264000, 1280003328, 1280743040, 1281482368, 1282222976, 1282963968, 1283705344, 1284447232, 1285188736, 1285931392, 1286674560, 1287418240, 1288162176, 1288906624, 1289650688, 1290395904, 1291141760, 1291887872, 1292634496, 1293380608, 1294128128, 1294875904, 1295624320, 1296373120, 1297122304, 1297870976, 1298621056, 1299371520, 1300122496, 1300873856, 1301624832, 1302376960, 1303129600, 1303882752, 1304636288, 1305389312, 1306143872, 1306898688, 1307654016, 1308409600, 1309165696, 1309921536, 1310678528, 1311435904, 1312193920, 1312952192, 1313710080, 1314469248, 1315228928, 1315988992, 1316749568, 1317509632, 1318271104, 1319032960, 1319795200, 1320557952, 1321321088, 1322083840, 1322847872, 1323612416, 1324377216, 1325142656, 1325907584, 1326673920, 1327440512, 1328207744, + 1328975360, 1329742464, 1330510976, 1331279872, 1332049152, 1332819072, 1333589248, 1334359168, 1335130240, 1335901824, 1336673920, 1337446400, 1338218368, 1338991744, 1339765632, 1340539904, 1341314560, 1342088832, 1342864512, 1343640576, 1344417024, 1345193984, 1345971456, 1346748416, 1347526656, 1348305408, 1349084672, 1349864320, 1350643456, 1351424000, 1352205056, 1352986496, 1353768448, 1354550784, 1355332608, 1356115968, 1356899712, 1357683840, 1358468480, 1359252608, 1360038144, 1360824192, 1361610624, 1362397440, 1363183872, 1363971712, 1364760064, 1365548672, 1366337792, 1367127424, 1367916672, 1368707200, 1369498240, 1370289664, 1371081472, 1371873024, 1372665856, 1373459072, 1374252800, 1375047040, 1375840768, 1376635904, 1377431552, 1378227584, 1379024000, 1379820928, 1380617472, 1381415296, 1382213760, 1383012480, 1383811840, 1384610560, 1385410816, 1386211456, 1387012480, 1387814144, 1388615168, 1389417728, 1390220672, 1391024128, 1391827968, 1392632320, 1393436288, 1394241536, 1395047296, 1395853568, 1396660224, 1397466368, 1398274048, 1399082112, 1399890688, 1400699648, 1401508224, 1402318080, 1403128576, 1403939456, 1404750848, 1405562624, 1406374016, 1407186816, + 1408000000, 1408813696, 1409627904, 1410441728, 1411256704, 1412072320, 1412888320, 1413704960, 1414521856, 1415338368, 1416156288, 1416974720, 1417793664, 1418612992, 1419431808, 1420252160, 1421072896, 1421894144, 1422715904, 1423537280, 1424359808, 1425183104, 1426006784, 1426830848, 1427655296, 1428479488, 1429305088, 1430131072, 1430957568, 1431784576, 1432611072, 1433438976, 1434267392, 1435096192, 1435925632, 1436754432, 1437584768, 1438415616, 1439246848, 1440078720, 1440910848, 1441742720, 1442575872, 1443409664, 1444243584, 1445078400, 1445912576, 1446748032, 1447584256, 1448420864, 1449257856, 1450094464, 1450932480, 1451771008, 1452609920, 1453449472, 1454289408, 1455128960, 1455969920, 1456811264, 1457653248, 1458495616, 1459337600, 1460180864, 1461024768, 1461869056, 1462713984, 1463558272, 1464404096, 1465250304, 1466097152, 1466944384, 1467792128, 1468639488, 1469488256, 1470337408, 1471187200, 1472037376, 1472887168, 1473738368, 1474589952, 1475442304, 1476294912, 1477148160, 1478000768, 1478854912, 1479709696, 1480564608, 1481420288, 1482275456, 1483132160, 1483989248, 1484846976, 1485704960, 1486562688, 1487421696, 1488281344, 1489141504, 1490002048, 1490863104, + 1491723776, 1492585856, 1493448448, 1494311424, 1495175040, 1496038144, 1496902656, 1497767808, 1498633344, 1499499392, 1500365056, 1501232128, 1502099712, 1502967808, 1503836416, 1504705536, 1505574016, 1506444032, 1507314688, 1508185856, 1509057408, 1509928576, 1510801280, 1511674240, 1512547840, 1513421952, 1514295680, 1515170816, 1516046464, 1516922624, 1517799296, 1518676224, 1519552896, 1520431104, 1521309824, 1522188928, 1523068800, 1523948032, 1524828672, 1525709824, 1526591616, 1527473792, 1528355456, 1529238784, 1530122496, 1531006720, 1531891712, 1532776832, 1533661824, 1534547968, 1535434880, 1536322304, 1537210112, 1538097408, 1538986368, 1539875840, 1540765696, 1541656192, 1542547072, 1543437440, 1544329472, 1545221888, 1546114944, 1547008384, 1547901440, 1548796032, 1549691136, 1550586624, 1551482752, 1552378368, 1553275520, 1554173184, 1555071232, 1555970048, 1556869248, 1557767936, 1558668288, 1559568896, 1560470272, 1561372032, 1562273408, 1563176320, 1564079616, 1564983424, 1565888000, 1566791808, 1567697408, 1568603392, 1569509760, 1570416896, 1571324416, 1572231424, 1573140096, 1574049152, 1574958976, 1575869184, 1576778752, 1577689984, 1578601728, 1579514112, + 1580426880, 1581339264, 1582253056, 1583167488, 1584082432, 1584997888, 1585913984, 1586829440, 1587746304, 1588663936, 1589582080, 1590500736, 1591418880, 1592338560, 1593258752, 1594179584, 1595100928, 1596021632, 1596944000, 1597866880, 1598790272, 1599714304, 1600638848, 1601562752, 1602488320, 1603414272, 1604340992, 1605268224, 1606194816, 1607123072, 1608051968, 1608981120, 1609911040, 1610841344, 1611771264, 1612702848, 1613634688, 1614567168, 1615500288, 1616432896, 1617367040, 1618301824, 1619237120, 1620172800, 1621108096, 1622044928, 1622982272, 1623920128, 1624858752, 1625797632, 1626736256, 1627676416, 1628616960, 1629558272, 1630499968, 1631441152, 1632384000, 1633327232, 1634271232, 1635215744, 1636159744, 1637105152, 1638051328, 1638998016, 1639945088, 1640892928, 1641840128, 1642788992, 1643738368, 1644688384, 1645638784, 1646588672, 1647540352, 1648492416, 1649445120, 1650398464, 1651351168, 1652305408, 1653260288, 1654215808, 1655171712, 1656128256, 1657084288, 1658041856, 1659000064, 1659958784, 1660918272, 1661876992, 1662837376, 1663798400, 1664759936, 1665721984, 1666683520, 1667646720, 1668610560, 1669574784, 1670539776, 1671505024, 1672470016, 1673436544, +}; + +#define SAMPLE_16BIT 0x01 +#define SAMPLE_UNSIGNED 0x02 +#define SAMPLE_LOOP 0x04 +#define SAMPLE_PINGPONG 0x08 +#define SAMPLE_REVERSE 0x10 +#define SAMPLE_SUSTAIN 0x20 +#define SAMPLE_ENVELOPE 0x40 + +#ifdef DEBUG_SAMPLES +#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx) +#else +#define SAMPLE_CONVERT_DEBUG(dx) +#endif + +#ifdef DEBUG_MIDI +#define MIDI_EVENT_DEBUG(dx,dy) printf("\r%s, %x\n",dx,dy) +#else +#define MIDI_EVENT_DEBUG(dx,dy) +#endif + +#define WM_ERR_MEM 0 +#define WM_ERR_STAT 1 +#define WM_ERR_LOAD 2 +#define WM_ERR_OPEN 3 +#define WM_ERR_READ 4 +#define WM_ERR_INVALID 5 +#define WM_ERR_CORUPT 6 +#define WM_ERR_NOT_INIT 7 +#define WM_ERR_INVALID_ARG 8 + +#define MAX_AUTO_AMP 2.0 + +#define FPBITS 10 +#define FPMASK ((1L<pw_dir; + } else { + home = getenv ("HOME"); + } + if (home) { + buffer_file = realloc(buffer_file,(strlen(buffer_file) + strlen(home) + 1)); + if (buffer_file == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + free(buffer_file); + return NULL; + } + memmove((buffer_file + strlen(home)), (buffer_file + 1), (strlen(buffer_file))); + strncpy (buffer_file, home,strlen(home)); + } + } else if (buffer_file[0] != '/') { + getcwd(buffer_dir,1024); + if (buffer_dir[strlen(buffer_dir)-1] != '/') { + buffer_dir[strlen(buffer_dir)+1] = '\0'; + buffer_dir[strlen(buffer_dir)] = '/'; + } + buffer_file = realloc(buffer_file,(strlen(buffer_file) + strlen(buffer_dir) + 1)); + if (buffer_file == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + free(buffer_file); + return NULL; + } + memmove((buffer_file + strlen(buffer_dir)), buffer_file, strlen(buffer_file)+1); + strncpy (buffer_file,buffer_dir,strlen(buffer_dir)); + } +#endif + if (stat(buffer_file,&buffer_stat)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_STAT, filename, errno); + free(buffer_file); + return NULL; + } + *size = buffer_stat.st_size; + data = malloc(*size); + if (data == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); + free(buffer_file); + return NULL; + } +#ifdef _WIN32 + if ((buffer_fd = open(buffer_file,(O_RDONLY | O_BINARY))) == -1) { +#else + if ((buffer_fd = open(buffer_file,O_RDONLY)) == -1) { +#endif + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_OPEN, filename, errno); + free(buffer_file); + free(data); + return NULL; + } + if (read(buffer_fd,data,*size) != buffer_stat.st_size) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_READ, filename, errno); + free(buffer_file); + free(data); + close(buffer_fd); + return NULL; + } + close(buffer_fd); + free(buffer_file); + return data; +} + +inline void +WM_Lock (int * wmlock) { + LOCK_START: + if (__builtin_expect(((*wmlock) == 0),1)) { + (*wmlock)++; + if (__builtin_expect(((*wmlock) == 1), 1)) { + return; + } + (*wmlock)--; + } +#ifdef _WIN32 + Sleep(10); +#else + usleep(500); +#endif + goto LOCK_START; +} + +inline void +WM_Unlock (int *wmlock) { + (*wmlock)--; +} + +void +WM_InitPatches ( void ) { + int i; + for (i = 0; i < 128; i++) { + patch[i] = NULL; + } +} + +void +WM_FreePatches ( void ) { + int i; + struct _patch * tmp_patch; + struct _sample * tmp_sample; + + WM_Lock(&patch_lock); + for (i = 0; i < 128; i++) { + if (patch[i] != NULL) { + while (patch[i] != NULL) { + if (patch[i]->filename != NULL) { + if (patch[i]->first_sample != NULL) { + while (patch[i]->first_sample != NULL) { + tmp_sample = patch[i]->first_sample->next; + if (patch[i]->first_sample->data != NULL) + free (patch[i]->first_sample->data); + free (patch[i]->first_sample); + patch[i]->first_sample = tmp_sample; + } + } + free (patch[i]->filename); + } + tmp_patch = patch[i]->next; + free(patch[i]); + patch[i] = tmp_patch; + } + } + } + WM_Unlock(&patch_lock); +} + +int +WM_LoadConfig (const char *config_file) { + unsigned long int config_size = 0; + unsigned char *config_buffer = NULL; + char * dir_end = NULL; + char * config_dir = NULL; + unsigned long int config_ptr = 0; + unsigned long int line_start_ptr = 0; + char * line_buffer = NULL; + unsigned long int line_ptr = 0; + char * chr_ptr = NULL; + unsigned short int patchid = 0; + char * new_config = NULL; + struct _patch * tmp_patch; + + if ((config_buffer = WM_BufferFile(config_file, &config_size)) == NULL) { + return -1; + } + if (config_buffer == NULL) { + WM_FreePatches(); + return -1; + } + + dir_end = strrchr(config_file,'/'); + if (dir_end != NULL) { + config_dir = malloc((dir_end - config_file + 2)); + if (config_dir == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (config_buffer); + return -1; + } + strncpy(config_dir, config_file, (dir_end - config_file + 1)); + config_dir[dir_end - config_file + 1] = '\0'; + } + config_ptr = 0; + line_start_ptr = 0; + while (config_ptr < config_size) { + // find end of line + if (config_buffer[config_ptr] != '\n') { + // remove unwanted crud + if (config_buffer[config_ptr] == '\t') { + config_buffer[config_ptr] = ' '; + } else if (config_buffer[config_ptr] == '\r') { + config_buffer[config_ptr] = ' '; + } + if ((config_buffer[config_ptr] == ' ') && (config_ptr == line_start_ptr)) { + line_start_ptr++; + } + + config_ptr++; + continue; + } + config_buffer[config_ptr] = '\0'; + if (config_ptr == line_start_ptr) { + config_ptr++; + line_start_ptr++; + continue; + } + if (config_buffer[line_start_ptr] == '#') { + config_ptr++; + line_start_ptr = config_ptr; + continue; + } + + // copy line into a workable buffer + line_buffer = realloc(line_buffer, (config_ptr - line_start_ptr + 1)); + if (line_buffer == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free(config_dir); + free (config_buffer); + return -1; + } + strcpy(line_buffer, &config_buffer[line_start_ptr]); + config_ptr++; + line_start_ptr = config_ptr; + // remove unwnted crud from line for easier parsing + if ((chr_ptr = strstr(line_buffer," ")) != NULL) { + while ((chr_ptr = strstr(line_buffer," ")) != NULL) { + memmove(chr_ptr, &chr_ptr[1], strlen(chr_ptr)); + } + } + if ((chr_ptr = strchr(line_buffer, '#')) != NULL) { + *chr_ptr = '\0'; + } + if (line_buffer[strlen(line_buffer) -1] == ' ') { + while (line_buffer[strlen(line_buffer) -1] == ' ') { + line_buffer[strlen(line_buffer) -1] = '\0'; + } + } + + // now parse line + if (strncasecmp(line_buffer, "dir ", 4) == 0) { + if (line_buffer[strlen(line_buffer) - 1] == '/') { + config_dir = realloc(config_dir, strlen(&line_buffer[4]) + 1); + if (config_dir == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(config_dir, &line_buffer[4]); + } else { + config_dir = realloc(config_dir, strlen(&line_buffer[4]) + 2); + if (config_dir == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(config_dir, &line_buffer[4]); + strcat(config_dir,"/"); + } + printf ("wildmidi config_dir: %s\n", config_dir); + continue; + } else if (strncasecmp(line_buffer, "source ", 7) == 0) { + if (config_dir != NULL, 0) { + new_config = malloc(strlen(config_dir) + strlen(&line_buffer[7]) + 1); + if (new_config == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(new_config,config_dir); + strcpy(&new_config[strlen(config_dir)], &line_buffer[7]); + } else { + new_config = malloc(strlen(&line_buffer[7]) + 1); + if (new_config == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(new_config, &line_buffer[7]); + } + printf ("wildmidi load new_config: %s\n", new_config); + if (WM_LoadConfig(new_config) == -1) { + free (new_config); + free (line_buffer); + free (config_buffer); + //if (config_dir != NULL) + // free (config_dir); + return -1; + } + free (new_config); + continue; + } else if (strncasecmp(line_buffer, "bank ", 5) == 0) { + printf ("loading bank, config_dir: %s\n", config_dir); + if (!isdigit(line_buffer[5])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in bank line)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + patchid = (atoi(&line_buffer[5]) & 0xFF ) << 8; + continue; + } else if (strncasecmp(line_buffer, "drumset ", 8) == 0) { + if (!isdigit(line_buffer[8])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in drumset line)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + patchid = ((atoi(&line_buffer[8]) & 0xFF ) << 8) | 0x80; + continue; + } else if (isdigit(line_buffer[0])) { + patchid = (patchid & 0xFF80) | (atoi(line_buffer) & 0x7F); + if (patch[(patchid & 0x7F)] == NULL) { + patch[(patchid & 0x7F)] = malloc (sizeof(struct _patch)); + if (patch[(patchid & 0x7F)] == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + tmp_patch = patch[(patchid & 0x7F)]; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } else { + tmp_patch = patch[(patchid & 0x7F)]; + if (tmp_patch->patchid == patchid) { + free (tmp_patch->filename); + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + } else { + if (tmp_patch->next != NULL) { + while (tmp_patch->next != NULL) { + if (tmp_patch->next->patchid == patchid) + break; + tmp_patch = tmp_patch->next; + } + if (tmp_patch->next == NULL) { + tmp_patch->next = malloc (sizeof(struct _patch)); + if (tmp_patch->next == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + tmp_patch = tmp_patch->next; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } else { + tmp_patch = tmp_patch->next; + free (tmp_patch->filename); + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + } + } else { + tmp_patch->next = malloc (sizeof(struct _patch)); + if (tmp_patch->next == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + tmp_patch = tmp_patch->next; + tmp_patch->patchid = patchid; + tmp_patch->filename = NULL; + tmp_patch->amp = 1024; + tmp_patch->note = 0; + tmp_patch->next = NULL; + tmp_patch->first_sample = NULL; + tmp_patch->loaded = 0; + tmp_patch->inuse_count = 0; + } + } + } + + chr_ptr = strchr(line_buffer,' ') + 1; + if (chr_ptr == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + line_ptr = chr_ptr - line_buffer; + chr_ptr = strchr(&line_buffer[line_ptr],' '); + if (chr_ptr != NULL) { + *chr_ptr = '\0'; + } + if (strncasecmp(&line_buffer[(line_ptr + strlen(&line_buffer[line_ptr]) - 5)], ".pat", 4) != 0, 0) { + if (config_dir != NULL) { + tmp_patch->filename = malloc(strlen(config_dir) + strlen(&line_buffer[line_ptr]) + 5); + if (tmp_patch->filename == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(tmp_patch->filename, config_dir); + strcat(tmp_patch->filename, &line_buffer[line_ptr]); + } else { + tmp_patch->filename = malloc(strlen(&line_buffer[line_ptr]) + 5); + if (tmp_patch->filename == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(tmp_patch->filename, &line_buffer[line_ptr]); + } + strcat(tmp_patch->filename, ".pat"); + } else { + if (config_dir != NULL) { + tmp_patch->filename = malloc(strlen(config_dir) + strlen(&line_buffer[line_ptr]) + 1); + if (tmp_patch->filename == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + if (config_dir != NULL) + free (config_dir); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(tmp_patch->filename, config_dir); + strcat(tmp_patch->filename, &line_buffer[line_ptr]); + } else { + tmp_patch->filename = malloc(strlen(&line_buffer[line_ptr]) + 1); + if (tmp_patch->filename == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); + WM_FreePatches(); + free (line_buffer); + free (config_buffer); + return -1; + } + strcpy(tmp_patch->filename, &line_buffer[line_ptr]); + } + } + + tmp_patch->env[0].set = 0x00; + tmp_patch->env[1].set = 0x00; + tmp_patch->env[2].set = 0x00; + tmp_patch->env[3].set = 0x00; + tmp_patch->env[4].set = 0x00; + tmp_patch->env[5].set = 0x00; + tmp_patch->keep = 0; + tmp_patch->remove = 0; + + if (chr_ptr != NULL) { + line_ptr = chr_ptr - line_buffer + 1; + chr_ptr = strstr(&line_buffer[line_ptr], "amp="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[4])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->amp = ((atoi(&chr_ptr[4]) << 10) / 100); + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "note="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[5])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->note = atoi(&chr_ptr[5]); + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "keep=loop"); + if (chr_ptr != NULL) { + tmp_patch->keep |= SAMPLE_LOOP; + } + chr_ptr = strstr(&line_buffer[line_ptr], "keep=env"); + if (chr_ptr != NULL) { + tmp_patch->keep |= SAMPLE_ENVELOPE; + } + chr_ptr = strstr(&line_buffer[line_ptr], "remove=sustain"); + if (chr_ptr != NULL) { + tmp_patch->remove |= SAMPLE_SUSTAIN; + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_time0="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[10])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[0].time = atof(&chr_ptr[10]); + if ((tmp_patch->env[0].time > 45000.0) || (tmp_patch->env[0].time < 1.47)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[0].set &= 0xFE; + } else { + tmp_patch->env[0].set |= 0x01; + } + } + } + + chr_ptr = strstr(&line_buffer[line_ptr], "env_time1="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[10])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[1].time = atof(&chr_ptr[10]); + if ((tmp_patch->env[1].time > 45000.0) || (tmp_patch->env[1].time < 1.47)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[1].set &= 0xFE; + } else { + tmp_patch->env[1].set |= 0x01; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_time2="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[10])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[2].time = atof(&chr_ptr[10]); + if ((tmp_patch->env[2].time > 45000.0) || (tmp_patch->env[2].time < 1.47)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[2].set &= 0xFE; + } else { + tmp_patch->env[2].set |= 0x01; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_time3="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[10])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[3].time = atof(&chr_ptr[10]); + if ((tmp_patch->env[3].time > 45000.0) || (tmp_patch->env[3].time < 1.47)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[3].set &= 0xFE; + } else { + tmp_patch->env[3].set |= 0x01; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_time4="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[10])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[4].time = atof(&chr_ptr[10]); + if ((tmp_patch->env[4].time > 45000.0) || (tmp_patch->env[4].time < 1.47)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[4].set &= 0xFE; + } else { + tmp_patch->env[4].set |= 0x01; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_time5="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[10])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[5].time = atof(&chr_ptr[10]); + if ((tmp_patch->env[5].time > 45000.0) || (tmp_patch->env[5].time < 1.47)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[5].set &= 0xFE; + } else { + tmp_patch->env[5].set |= 0x01; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_level0="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[11])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[0].level = atof(&chr_ptr[10]); + if ((tmp_patch->env[0].level > 1.0) || (tmp_patch->env[0].level < 0.0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[0].set &= 0xFD; + } else { + tmp_patch->env[0].set |= 0x02; + } + } + } + + chr_ptr = strstr(&line_buffer[line_ptr], "env_level1="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[11])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[1].level = atof(&chr_ptr[10]); + if ((tmp_patch->env[1].level > 1.0) || (tmp_patch->env[1].level < 0.0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[1].set &= 0xFD; + } else { + tmp_patch->env[1].set |= 0x02; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_level2="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[11])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[2].level = atof(&chr_ptr[10]); + if ((tmp_patch->env[2].level > 1.0) || (tmp_patch->env[2].level < 0.0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[2].set &= 0xFD; + } else { + tmp_patch->env[2].set |= 0x02; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_level3="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[11])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[3].level = atof(&chr_ptr[10]); + if ((tmp_patch->env[3].level > 1.0) || (tmp_patch->env[3].level < 0.0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[3].set &= 0xFD; + } else { + tmp_patch->env[3].set |= 0x02; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_level4="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[11])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[4].level = atof(&chr_ptr[10]); + if ((tmp_patch->env[4].level > 1.0) || (tmp_patch->env[4].level < 0.0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[4].set &= 0xFD; + } else { + tmp_patch->env[4].set |= 0x02; + } + } + } + chr_ptr = strstr(&line_buffer[line_ptr], "env_level5="); + if (chr_ptr != NULL) { + if (!isdigit(chr_ptr[11])) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(syntax error in patch line)", 0); + } else { + tmp_patch->env[5].level = atof(&chr_ptr[10]); + if ((tmp_patch->env[5].level > 1.0) || (tmp_patch->env[5].level < 0.0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(range error in patch line)", 0); + tmp_patch->env[5].set &= 0xFD; + } else { + tmp_patch->env[5].set |= 0x02; + } + } + } + + } + } + } + + if (line_buffer != NULL) + free (line_buffer); + + free (config_buffer); + + if (config_dir != NULL) + free (config_dir); + + return 0; +} + +/* + * sample data conversion functions + * convert data to signed shorts + */ + +/* 8bit signed */ +int +convert_8s (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit signed ping pong */ +int +convert_8sp (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((new_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data++ << 8); + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data++ << 8); + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (__builtin_expect((read_data != read_end),1)) { + do { + *write_data_b = (*read_data++) << 8; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data != read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit signed reverse */ +int +convert_8sr (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data + gus_sample->data_length - 1; + do { + *write_data = (*read_data++) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data--; + } while (read_data != read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->modes ^= SAMPLE_REVERSE; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + + +/* 8bit signed reverse ping pong */ +int +convert_8srp (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((new_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = (*read_data--) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data-- << 8); + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_start; + do { + *write_data = (*read_data--) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = (*read_data-- << 8); + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = (*read_data--) << 8; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data != read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned */ +int +convert_8u (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = ((*read_data++) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + gus_sample->modes ^= SAMPLE_UNSIGNED; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned ping pong */ +int +convert_8up (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((new_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = ((*read_data++) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data++) ^ 0x80) << 8; + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_end; + do { + *write_data = ((*read_data++) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data++) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (__builtin_expect((read_data != read_end),1)) { + do { + *write_data_b = ((*read_data++) ^ 0x80) << 8; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data != read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned reverse */ +int +convert_8ur (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((gus_sample->data_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data + gus_sample->data_length - 1; + do { + *write_data = ((*read_data++) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data--; + } while (read_data != read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 8bit unsigned reverse ping pong */ +int +convert_8urp (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc((new_length + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + write_data_a = write_data + dloop_length; + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + dloop_length; + read_end = data + gus_sample->loop_start; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data != read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = ((*read_data--) ^ 0x80) << 8; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data != read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed */ +int +convert_16s (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1),sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = *read_data++; + *write_data |= (*read_data++) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed ping pong */ +int +convert_16sp (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++); + *write_data |= (*read_data++) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = *(read_data++); + *write_data |= (*read_data++) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (__builtin_expect((read_data != read_end),1)) { + do { + *write_data_b = *(read_data++); + *write_data_b |= (*read_data++) << 8; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data < read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit signed reverse */ +int +convert_16sr (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; + do { + *write_data = *read_data++; + *write_data |= (*read_data++) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data--; + } while (read_data < read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_REVERSE; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + + +/* 16bit signed reverse ping pong */ +int +convert_16srp (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + + *write_data = (*read_data--) << 8; + *write_data |= *read_data--; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = (*read_data-- << 8); + *write_data |= *read_data--; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_start; + do { + *write_data = (*read_data--) << 8; + *write_data |= *read_data--; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) << 8); + *write_data |= *read_data--; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = (*read_data--) << 8; + *write_data_b |= *read_data--; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data < read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned */ +int +convert_16u (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1),sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = *read_data++; + *write_data |= ((*read_data++) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_UNSIGNED; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned ping pong */ +int +convert_16up (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->loop_start; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_end; + do { + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = (*read_data++); + *write_data |= ((*read_data++) ^ 0x80) << 8; + *write_data_b++ = *write_data; + read_end = data + gus_sample->data_length; + if (__builtin_expect((read_data != read_end),1)) { + do { + *write_data_b = (*read_data++); + *write_data_b |= ((*read_data++) ^ 0x80) << 8; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data < read_end); + } + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG; + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned reverse */ +int +convert_16ur (unsigned char *data, struct _sample *gus_sample ) { + unsigned char *read_data = data; + unsigned char *read_end = data + gus_sample->data_length; + signed short int *write_data = NULL; + unsigned long int tmp_loop = 0; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((gus_sample->data_length >> 1) + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; + do { + *write_data = *read_data++; + *write_data |= ((*read_data++) ^ 0x80) << 8; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data--; + } while (read_data < read_end); + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; + gus_sample->loop_start = gus_sample->data_length - tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); + gus_sample->loop_start >>= 1; + gus_sample->loop_end >>= 1; + gus_sample->data_length >>= 1; + gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + +/* 16bit unsigned reverse ping pong */ +int +convert_16urp (unsigned char *data, struct _sample *gus_sample ) { + unsigned long int loop_length = gus_sample->loop_end - gus_sample->loop_start; + unsigned long int dloop_length = loop_length * 2; + unsigned long int new_length = gus_sample->data_length + dloop_length; + unsigned char *read_data = data + gus_sample->data_length - 1; + unsigned char *read_end = data + gus_sample->loop_end; + signed short int *write_data = NULL; + signed short int *write_data_a = NULL; + signed short int *write_data_b = NULL; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + gus_sample->data = calloc(((new_length >> 1) + 1), sizeof(signed short int)); + if (__builtin_expect((gus_sample->data != NULL),1)) { + write_data = gus_sample->data; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + write_data_a = write_data + (dloop_length >> 1); + *write_data_a-- = *write_data; + write_data++; + write_data_b = write_data + (dloop_length >> 1); + read_end = data + gus_sample->loop_start; + do { + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + *write_data_a-- = *write_data; + *write_data_b++ = *write_data; + if (*write_data > gus_sample->max_peek) { + gus_sample->max_peek = *write_data; + } else if (*write_data < gus_sample->min_peek) { + gus_sample->min_peek = *write_data; + } + write_data++; + } while (read_data < read_end); + + *write_data = ((*read_data--) ^ 0x80) << 8; + *write_data |= *read_data--; + *write_data_b++ = *write_data; + read_end = data - 1; + do { + *write_data_b = ((*read_data--) ^ 0x80) << 8; + *write_data_b |= *read_data--; + if (*write_data_b > gus_sample->max_peek) { + gus_sample->max_peek = *write_data_b; + } else if (*write_data_b < gus_sample->min_peek) { + gus_sample->min_peek = *write_data_b; + } + write_data_b++; + } while (read_data < read_end); + gus_sample->loop_start += loop_length; + gus_sample->loop_end += dloop_length; + gus_sample->data_length = new_length; + gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; + return 0; + } + + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); + return -1; +} + + +/* sample loading */ + +int +load_sample (struct _patch *sample_patch) { + unsigned char *gus_patch; + unsigned long int gus_size; + unsigned long int gus_ptr; + unsigned char no_of_samples; + struct _sample *gus_sample = NULL; + unsigned long int i = 0; + + int (*do_convert[])(unsigned char *data, struct _sample *gus_sample ) = { + convert_8s, + convert_16s, + convert_8u, + convert_16u, + convert_8sp, + convert_16sp, + convert_8up, + convert_16up, + convert_8sr, + convert_16sr, + convert_8ur, + convert_16ur, + convert_8srp, + convert_16srp, + convert_8urp, + convert_16urp + }; + unsigned long int tmp_loop; + + SAMPLE_CONVERT_DEBUG(__FUNCTION__); + SAMPLE_CONVERT_DEBUG(sample_patch->filename); + sample_patch->loaded = 1; + if ((gus_patch = WM_BufferFile(sample_patch->filename,&gus_size)) == NULL) { + return -1; + } + if (gus_size < 239) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0); + free(gus_patch); + return -1; + } + if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(unsupported format)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0); + free(gus_patch); + return -1; + } + if (gus_patch[82] > 1) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(unsupported format)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0); + free(gus_patch); + return -1; + } + if (gus_patch[151] > 1) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(unsupported format)", 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0); + free(gus_patch); + return -1; + } + + no_of_samples = gus_patch[198]; + sample_patch->first_sample = NULL; + gus_ptr = 239; + while (no_of_samples) { + unsigned long int tmp_cnt; + if (sample_patch->first_sample == NULL) { + sample_patch->first_sample = malloc(sizeof(struct _sample)); + gus_sample = sample_patch->first_sample; + } else { + gus_sample->next = malloc(sizeof(struct _sample)); + gus_sample = gus_sample->next; + } + if (gus_sample == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, sample_patch->filename, 0); + return -1; + } + + gus_sample->next = NULL; + gus_sample->loop_fraction = gus_patch[gus_ptr+7]; + gus_sample->data_length = (gus_patch[gus_ptr+11] << 24) | (gus_patch[gus_ptr+10] << 16) | (gus_patch[gus_ptr+9] << 8) | gus_patch[gus_ptr+8]; + gus_sample->loop_start = (gus_patch[gus_ptr+15] << 24) | (gus_patch[gus_ptr+14] << 16) | (gus_patch[gus_ptr+13] << 8) | gus_patch[gus_ptr+12]; + gus_sample->loop_end = (gus_patch[gus_ptr+19] << 24) | (gus_patch[gus_ptr+18] << 16) | (gus_patch[gus_ptr+17] << 8) | gus_patch[gus_ptr+16]; + gus_sample->rate = (gus_patch[gus_ptr+21] << 8) | gus_patch[gus_ptr+20]; + gus_sample->freq_low = ((gus_patch[gus_ptr+25] << 24) | (gus_patch[gus_ptr+24] << 16) | (gus_patch[gus_ptr+23] << 8) | gus_patch[gus_ptr+22]); + gus_sample->freq_high = ((gus_patch[gus_ptr+29] << 24) | (gus_patch[gus_ptr+28] << 16) | (gus_patch[gus_ptr+27] << 8) | gus_patch[gus_ptr+26]); + gus_sample->freq_root = ((gus_patch[gus_ptr+33] << 24) | (gus_patch[gus_ptr+32] << 16) | (gus_patch[gus_ptr+31] << 8) | gus_patch[gus_ptr+30]); + + /* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */ + /* Result is 0.001% inacurate */ + gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2; + +#if 0 + printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n", + gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]); + printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n", + gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]); +#endif + gus_sample->modes = gus_patch[gus_ptr+55] & 0x7F; + if ((sample_patch->remove & SAMPLE_SUSTAIN) && (gus_sample->modes & SAMPLE_SUSTAIN)) { + gus_sample->modes ^= SAMPLE_SUSTAIN; + } + if (sample_patch->patchid & 0x0080) { + if (!(sample_patch->keep & SAMPLE_LOOP)) { + gus_sample->modes &= 0xFB; + } + if (!(sample_patch->keep & SAMPLE_ENVELOPE)) { + gus_sample->modes &= 0xBF; + } + } + + + if (gus_sample->loop_start > gus_sample->loop_end) { + tmp_loop = gus_sample->loop_end; + gus_sample->loop_end = gus_sample->loop_start; + gus_sample->loop_start = tmp_loop; + gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) | ((gus_sample->loop_fraction & 0xf0) >> 4); + } + for (i = 0; i < 6; i++) { + if (gus_sample->modes & SAMPLE_ENVELOPE) { + unsigned char env_rate = gus_patch[gus_ptr+37+i]; + if (sample_patch->env[i].set & 0x02) { + gus_sample->env_target[i] = 16448 * (unsigned long int)(255.0 * sample_patch->env[i].level); + } else { + gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr+43+i]; + } + + if (sample_patch->env[i].set & 0x01) { + gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * (sample_patch->env[i].time / 1000.0))); + } else { + gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[env_rate])); + if (gus_sample->env_rate[i] == 0) { + fprintf(stderr,"\rWarning: libWildMidi %s found invalid envelope(%lu) rate setting in %s. Using %f instead.\n",__FUNCTION__, i, sample_patch->filename, env_time_table[63]); + gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[63])); + } + } + } else { + gus_sample->env_target[i] = 4194303; + gus_sample->env_rate[i] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[63])); + } + } + + gus_sample->env_target[6] = 0; + gus_sample->env_rate[6] = (unsigned long int)(4194303.0 / ((float)WM_SampleRate * env_time_table[63])); + + if ((sample_patch->patchid == 47) && (!(gus_sample->modes & SAMPLE_LOOP))) { + for (i = 3; i < 6; i++) { + gus_sample->env_target[i] = gus_sample->env_target[2]; + gus_sample->env_rate[i] = gus_sample->env_rate[2]; + } + } + + gus_ptr += 96; + tmp_cnt = gus_sample->data_length; + +/* convert to float */ + gus_sample->min_peek = 0; + gus_sample->max_peek = 0; + + if (do_convert[(((gus_sample->modes & 0x18) >> 1)| (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample) == -1) { + return -1; + + }; + + if (gus_sample->max_peek > (-gus_sample->min_peek)) { + gus_sample->peek_adjust = 33553408 / gus_sample->max_peek; + } else { + gus_sample->peek_adjust = 33554432 / (-gus_sample->min_peek); + } + gus_sample->peek_adjust = (gus_sample->peek_adjust * sample_patch->amp) >> 10; + + gus_ptr += tmp_cnt; + gus_sample->loop_start = (gus_sample->loop_start << 10) | (((gus_sample->loop_fraction & 0x0f) << 10) / 16); + gus_sample->loop_end = (gus_sample->loop_end << 10) | (((gus_sample->loop_fraction & 0xf0) << 6) / 16); + gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start; + gus_sample->data_length = gus_sample->data_length << 10; + no_of_samples--; + } + free(gus_patch); + return 0; +} + + +struct _patch * +get_patch_data(struct _mdi *mdi, unsigned short patchid) { + struct _patch *search_patch; + + WM_Lock(&patch_lock); + + search_patch = patch[patchid & 0x007F]; + + if (search_patch == NULL) { + WM_Unlock(&patch_lock); + return NULL; + } + + while(search_patch != NULL) { + if (search_patch->patchid == patchid) { + WM_Unlock(&patch_lock); + return search_patch; + } + search_patch = search_patch->next; + } + if ((patchid >> 8) != 0) { + WM_Unlock(&patch_lock); + return (get_patch_data(mdi, patchid & 0x00FF)); + } + WM_Unlock(&patch_lock); + return NULL; +} + +void +load_patch (struct _mdi *mdi, unsigned short patchid) { + int i; + struct _patch *tmp_patch = NULL; + + for (i = 0; i < mdi->patch_count; i++) { + if (mdi->patches[i]->patchid == patchid) { + return; + } + } + + tmp_patch = get_patch_data(mdi, patchid); + if (tmp_patch == NULL) { + return; + } + + WM_Lock(&patch_lock); + if (!tmp_patch->loaded) { + if (load_sample(tmp_patch) == -1) { + WM_Unlock(&patch_lock); + return; + } + } + + if (tmp_patch->first_sample == NULL) { + WM_Unlock(&patch_lock); + return; + } + + mdi->patch_count++; + mdi->patches = realloc(mdi->patches, (sizeof(struct _patch) * mdi->patch_count)); + mdi->patches[mdi->patch_count -1] = tmp_patch; + tmp_patch->inuse_count++; + WM_Unlock(&patch_lock); + return; +} + + +struct _sample * +get_sample_data (struct _patch *sample_patch, unsigned long int freq) { + struct _sample *last_sample = NULL; + struct _sample *return_sample = NULL; + + WM_Lock(&patch_lock); + if (sample_patch == NULL) { + WM_Unlock(&patch_lock); + return NULL; + } + if (sample_patch->first_sample == NULL) { + WM_Unlock(&patch_lock); + return NULL; + } + if (freq == 0) { + WM_Unlock(&patch_lock); + return sample_patch->first_sample; + } + + return_sample = sample_patch->first_sample; + last_sample = sample_patch->first_sample; + while (last_sample != NULL) { + if (freq > last_sample->freq_low) { + if (freq < last_sample->freq_high) { + WM_Unlock(&patch_lock); + return last_sample; + } else { + return_sample = last_sample; + } + } + last_sample = last_sample->next; + } + WM_Unlock(&patch_lock); + return return_sample; +} + +unsigned long int +read_var_length (struct _mdi *mdi, struct _miditrack *track) { + unsigned long int var_data = 0; + if (mdi->data[track->ptr] > 0x7f) { + while(mdi->data[track->ptr] > 0x7f) { + var_data |= mdi->data[track->ptr] & 0x7f; + track->ptr++; + if (track->ptr > mdi->size) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + return 0xFFFFFFFF; + } + var_data = (var_data << 7); + } + } + var_data |= mdi->data[track->ptr] & 0x7f; + track->ptr++; + + if (track->ptr > mdi->size) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + return 0xFFFFFFFF; + } + + return var_data; +} + +void +do_note_off (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + struct _note *nte; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + nte = &mdi->note_table[0][ch][mdi->data[ptr]]; + if (!nte->active) + nte = &mdi->note_table[1][ch][mdi->data[ptr]]; + if (!nte->active) { + return; + } + + if ((ch == 9) && (!(nte->modes & SAMPLE_LOOP))) { + return; + } + + if (nte->hold) { + nte->hold |= HOLD_OFF; + } else { +#if 0 + if (nte->modes & SAMPLE_SUSTAIN) { + nte->env = 3; + if (nte->env_level > nte->sample->env_target[3]) { + nte->env_inc = -nte->sample->env_rate[3]; + } else { + nte->env_inc = nte->sample->env_rate[3]; + } + } else +#endif + { + if (nte->env < 4) { + nte->env = 4; + if (nte->env_level > nte->sample->env_target[4]) { + nte->env_inc = -nte->sample->env_rate[4]; + } else { + nte->env_inc = nte->sample->env_rate[4]; + } + } + } + } + return; +} + +inline unsigned long int +get_inc (struct _mdi *mdi, struct _note *nte) { + int ch = nte->noteid >> 8; + signed long int note_f; + unsigned long int freq; + + if (__builtin_expect((nte->patch->note != 0),0)) { + note_f = nte->patch->note * 100; + } else { + note_f = (nte->noteid & 0x7f) * 100; + } + note_f += mdi->channel[ch].pitch_adjust; + if (__builtin_expect((note_f < 0), 0)) { + note_f = 0; + } else if (__builtin_expect((note_f > 12700), 0)) { + note_f = 12700; + } + freq = freq_table[(note_f % 1200)] >> (10 - (note_f / 1200)); + return (((freq / ((WM_SampleRate * 100) / 1024)) * 1024 / nte->sample->inc_div)); +} + +inline signed short int +get_volume(struct _mdi *mdi, unsigned char ch, struct _note *nte) { + signed long int volume; + + if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) { + volume = (lin_volume[mdi->channel[ch].volume] * + lin_volume[mdi->channel[ch].expression] * + lin_volume[nte->velocity]) / 1048576; + } else { + volume = (sqr_volume[mdi->channel[ch].volume] * + sqr_volume[mdi->channel[ch].expression] * + sqr_volume[nte->velocity]) / 1048576; + } + return ((volume * nte->sample->peek_adjust) >> 10); +} + +void +do_note_on (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + struct _note *nte; + unsigned long int freq = 0; + struct _patch *patch; + struct _sample *sample; + + if (mdi->data[ptr+1] == 0x00) { + do_note_off(ch, mdi, ptr); + return; + } + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (ch != 9) { + patch = mdi->channel[ch].patch; + if (patch == NULL) { + return; + } + freq = freq_table[(mdi->data[ptr] % 12) * 100] >> (10 -(mdi->data[ptr] / 12)); + } else { + patch = get_patch_data(mdi, ((mdi->channel[ch].bank << 8) | mdi->data[ptr] | 0x80)); + if (patch == NULL) { + return; + } + if (patch->note) { + freq = freq_table[(patch->note % 12) * 100] >> (10 -(patch->note / 12)); + } else { + freq = freq_table[(mdi->data[ptr] % 12) * 100] >> (10 -(mdi->data[ptr] / 12)); + } + } + + sample = get_sample_data(patch, (freq / 100)); + + if (sample == NULL) { + return; + } + + nte = &mdi->note_table[0][ch][mdi->data[ptr]]; + + if (nte->active) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) && (!(nte->hold & HOLD_OFF))) + return; + nte->next = &mdi->note_table[1][ch][mdi->data[ptr]]; + nte->env = 6; + nte->env_inc = -nte->sample->env_rate[6]; + nte = &mdi->note_table[1][ch][mdi->data[ptr]]; + } else { + if (mdi->note_table[1][ch][mdi->data[ptr]].active) { + if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) && (!(nte->hold & HOLD_OFF))) + return; + mdi->note_table[1][ch][mdi->data[ptr]].next = nte; + mdi->note_table[1][ch][mdi->data[ptr]].env = 6; + mdi->note_table[1][ch][mdi->data[ptr]].env_inc = -mdi->note_table[1][ch][mdi->data[ptr]].sample->env_rate[6]; + } else { + *mdi->last_note = nte; + mdi->last_note++; + nte->active = 1; + } + } + nte->noteid = (ch << 8) | mdi->data[ptr]; + nte->patch = patch; + nte->sample = sample; + nte->sample_pos = 0; + nte->sample_inc = get_inc (mdi, nte); + nte->velocity = mdi->data[ptr+1]; + nte->env = 0; + nte->env_inc = nte->sample->env_rate[0]; + nte->env_level = 0; + nte->modes = sample->modes; + nte->hold = mdi->channel[ch].hold; + nte->vol_lvl = get_volume(mdi, ch, nte); + nte->next = NULL; +} + +void +do_aftertouch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + struct _note *nte; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + nte = &mdi->note_table[0][ch][mdi->data[ptr]]; + if (!nte->active) { + nte = &mdi->note_table[1][ch][mdi->data[ptr]]; + if (!nte->active) { + return; + } + } + + nte->velocity = mdi->data[ptr+1]; + nte->vol_lvl = get_volume(mdi, ch, nte); + + if (nte->next) { + nte->next->velocity = mdi->data[ptr+1]; + nte->next->vol_lvl = get_volume(mdi, ch, nte->next); + } +} + + +void +do_pan_adjust (struct _mdi *mdi, unsigned char ch) { + signed short int pan_adjust = mdi->channel[ch].balance + mdi->channel[ch].pan; + signed long int left, right; + + if (pan_adjust > 63) { + pan_adjust = 63; + } else if (pan_adjust < -64) { + pan_adjust = -64; + } + + pan_adjust += 64; + + if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) { + left = (lin_volume[127 - pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576; + right= (lin_volume[pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576; + } else { + left = (pan_volume[127 - pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576; + right = (pan_volume[pan_adjust] * WM_MasterVolume * mdi->amp) / 1048576; + } + + mdi->channel[ch].left_adjust = left; + mdi->channel[ch].right_adjust = right; +} + +void +do_control (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + struct _note **note_data = mdi->note; + + switch (mdi->data[ptr]) { + case 0: // Bank Select + mdi->channel[ch].bank = mdi->data[ptr+1]; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + break; + case 6: // Data Entry Course + if (mdi->channel[ch].reg_data == 0x0000) { // Pitch Bend Range + int data_tmp; + data_tmp = mdi->channel[ch].pitch_range % 100; + mdi->channel[ch].pitch_range = mdi->data[ptr+1] * 100 + data_tmp; + } + break; + case 7: // Channel Volume + mdi->channel[ch].volume = mdi->data[ptr+1]; + + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8) == ch) { + (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data); + if ((*note_data)->next) + (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next); + } + note_data++; + } while (note_data != mdi->last_note); + } + break; + case 8: // Channel Balance + mdi->channel[ch].balance = mdi->data[ptr+1] - 64; + do_pan_adjust(mdi, ch); + break; + case 9: + break; + case 10: // Channel Pan + mdi->channel[ch].pan = mdi->data[ptr+1] - 64; + do_pan_adjust(mdi, ch); + break; + case 11: // Channel Expression + mdi->channel[ch].expression = mdi->data[ptr+1]; + + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8) == ch) { + (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data); + if ((*note_data)->next) + (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next); + } + note_data++; + } while (note_data != mdi->last_note); + } + break; + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + break; + case 38: // Data Entry Fine + if (mdi->channel[ch].reg_data == 0x0000) { // Pitch Bend Range + int data_tmp; + data_tmp = mdi->channel[ch].pitch_range / 100; + mdi->channel[ch].pitch_range = (data_tmp * 100) + mdi->data[ptr+1]; + } + break; + case 39: + case 40: + case 41: + case 42: + case 43: + printf("\rController %i used\n",mdi->data[ptr]); + break; + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + case 63: + break; + case 64: // Channel Hold + if (mdi->data[ptr+1] > 63) { + mdi->channel[ch].hold = 1; + } else { + mdi->channel[ch].hold = 0; + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8) == ch) { + if ((*note_data)->hold & HOLD_OFF) { + if ((*note_data)->modes & SAMPLE_ENVELOPE) { +#if 0 + if ((*note_data)->modes & SAMPLE_SUSTAIN) { + (*note_data)->env = 3; + if ((*note_data)->env_level > (*note_data)->sample->env_target[3]) { + (*note_data)->env_inc = -(*note_data)->sample->env_rate[3]; + } else { + (*note_data)->env_inc = (*note_data)->sample->env_rate[3]; + } + } else +#endif + { + if ((*note_data)->env < 4) { + (*note_data)->env = 4; + if ((*note_data)->env_level > (*note_data)->sample->env_target[4]) { + (*note_data)->env_inc = -(*note_data)->sample->env_rate[4]; + } else { + (*note_data)->env_inc = (*note_data)->sample->env_rate[4]; + } + } + } + } + } + (*note_data)->hold = 0x00; + } + note_data++; + } while (note_data != mdi->last_note); + } + } + break; + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + break; + case 100: // Registered Param Fine + mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0xFF00) | mdi->data[ptr+1]; + break; + case 101: // Registered Param Course + mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0xFF) | (mdi->data[ptr+1] << 8); + break; + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + break; + case 120: // All Channel Sound Off + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8) == ch) { + (*note_data)->active = 0; + if ((*note_data)->next) { + (*note_data)->next = NULL; + } + } + note_data++; + } while (note_data != mdi->last_note); + mdi->last_note = mdi->note; + } + break; + case 121: // All Controlers Off + mdi->channel[ch].expression = 127; + mdi->channel[ch].pressure = 0; + mdi->channel[ch].volume = 100; + mdi->channel[ch].pan = 0; + mdi->channel[ch].balance = 0; + mdi->channel[ch].reg_data = 0xffff; + mdi->channel[ch].pitch_range = 200; + mdi->channel[ch].pitch = 0; + mdi->channel[ch].pitch_adjust = 0; + mdi->channel[ch].hold = 0; + do_pan_adjust(mdi, ch); + + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8 ) == ch) { + (*note_data)->sample_inc = get_inc (mdi, *note_data); + (*note_data)->velocity = 0; + (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data); + (*note_data)->hold = 0; + + if ((*note_data)->next) { + (*note_data)->next->velocity = mdi->data[ptr]; + (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next); + } + + } + note_data++; + } while (note_data != mdi->last_note); + } + break; + case 122: + break; + case 123: // All Channel Notes Off + if (ch == 9) + return; + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8) == ch) { + if (!(*note_data)->hold){ + if ((*note_data)->modes & SAMPLE_ENVELOPE) { + if ((*note_data)->env < 5) { + if ((*note_data)->env_level > (*note_data)->sample->env_target[5]) { + (*note_data)->env_inc = -(*note_data)->sample->env_rate[5]; + } else { + (*note_data)->env_inc = (*note_data)->sample->env_rate[5]; + } + (*note_data)->env = 5; + } + } + } else { + (*note_data)->hold |= HOLD_OFF; + } + } + note_data++; + } while (note_data != mdi->last_note); + } + break; + case 124: + case 125: + case 126: + case 127: + break; + } +} + +void +do_patch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (ch != 9) { + mdi->channel[ch].patch = get_patch_data(mdi, ((mdi->channel[ch].bank << 8) | mdi->data[ptr])); + } else { + mdi->channel[ch].bank = mdi->data[ptr]; + } +} + +void +do_channel_pressure (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + struct _note **note_data = mdi->note; + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8 ) == ch) { + (*note_data)->velocity = mdi->data[ptr]; + (*note_data)->vol_lvl = get_volume(mdi, ch, *note_data); + + if ((*note_data)->next) { + (*note_data)->next->velocity = mdi->data[ptr]; + (*note_data)->next->vol_lvl = get_volume(mdi, ch, (*note_data)->next); + } + } + note_data++; + } while (note_data != mdi->last_note); + } +} + +void +do_pitch (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + struct _note **note_data = mdi->note; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + mdi->channel[ch].pitch = ((mdi->data[ptr+1] << 7) | mdi->data[ptr]) - 0x2000; + + if (mdi->channel[ch].pitch < 0) { + mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range * mdi->channel[ch].pitch / 8192; + } else { + mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range * mdi->channel[ch].pitch / 8191; + } + + if (note_data != mdi->last_note) { + do { + if (((*note_data)->noteid >> 8 ) == ch) { + (*note_data)->sample_inc = get_inc (mdi, *note_data); + } + note_data++; + } while (note_data != mdi->last_note); + } +} + +void +do_message (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + unsigned char event_type = 0xF0 | ch; + static unsigned long int tempo = 500000; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (event_type == 0xFF) { + if ((mdi->data[ptr] == 0x51) && (mdi->data[ptr+1] == 3)) { + tempo = (mdi->data[ptr+2] << 16) | (mdi->data[ptr+3] << 8) | mdi->data[ptr+4]; + if (tempo == 0) + mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions); + else + mdi->samples_per_delta = (WM_SampleRate << 10) / ((1000000 * mdi->divisions) / tempo); + } + } +} + + +void +do_null (unsigned char ch, struct _mdi *mdi, unsigned long int ptr) { + MIDI_EVENT_DEBUG(__FUNCTION__,ch); +}; + + +void +WM_ResetToStart(midi * handle) { + struct _mdi *mdi = (struct _mdi *)handle; + int i; + + mdi->index_count = 0; + mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions); + mdi->samples_to_mix = 0; + mdi->info.current_sample= 0; + + for (i=0; i<16; i++) { + mdi->channel[i].bank = 0; + mdi->channel[i].patch = NULL; + mdi->channel[i].hold = 0; + mdi->channel[i].volume = 100; + mdi->channel[i].pressure = 127; + mdi->channel[i].expression = 127; + mdi->channel[i].balance = 0; + mdi->channel[i].pan = 0; + mdi->channel[i].left_adjust = 1.0; + mdi->channel[i].right_adjust = 1.0; + mdi->channel[i].pitch = 0; + mdi->channel[i].pitch_range = 200; + mdi->channel[i].reg_data = 0xFFFF; + } +} + +void +WM_RecalcSamples (midi * handle) { + struct _mdi *mdi = (struct _mdi *)handle; + struct _note **note_data = mdi->note; + unsigned long int total_samples = 0; + unsigned long int count_a; + unsigned long int count_b; + unsigned long int env_level; + + if (note_data != mdi->last_note) { + do { + env_level = (*note_data)->env_level; + count_a = 0; + count_b = 0; + if ((*note_data)->env < 4) { + if (env_level > (*note_data)->sample->env_target[3]) { + count_a += (env_level - (*note_data)->sample->env_target[3] + (*note_data)->sample->env_rate[3] - 1) / (*note_data)->sample->env_rate[3]; + } else { + count_a += ((*note_data)->sample->env_target[3] - env_level + (*note_data)->sample->env_rate[3] - 1) / (*note_data)->sample->env_rate[3]; + } + env_level = (*note_data)->sample->env_target[3]; + } + if ((*note_data)->env < 5) { + if (env_level > (*note_data)->sample->env_target[4]) { + count_a += (env_level - (*note_data)->sample->env_target[4] + (*note_data)->sample->env_rate[4] - 1) / (*note_data)->sample->env_rate[4]; + } else { + count_a += ((*note_data)->sample->env_target[4] - env_level + (*note_data)->sample->env_rate[4] - 1) / (*note_data)->sample->env_rate[4]; + } + env_level = (*note_data)->sample->env_target[4]; + } + if ((*note_data)->env < 6) { + if (env_level > (*note_data)->sample->env_target[5]) { + count_a += (env_level - (*note_data)->sample->env_target[5] + (*note_data)->sample->env_rate[5] - 1) / (*note_data)->sample->env_rate[5]; + } else { + count_a += ((*note_data)->sample->env_target[5] - env_level + (*note_data)->sample->env_rate[5] - 1) / (*note_data)->sample->env_rate[5]; + } + env_level = (*note_data)->sample->env_target[5]; + } + if ((*note_data)->env == 6) { + count_a = (env_level + (*note_data)->sample->env_rate[6] - 1) / (*note_data)->sample->env_rate[6]; + env_level = (*note_data)->sample->env_target[6]; + } + if (env_level != 0) { + if ((*note_data)->modes & SAMPLE_LOOP) { + unsigned long int smpl_pos = (*note_data)->sample_pos + (count_a * (*note_data)->sample_inc); + if (smpl_pos > ((*note_data)->sample->loop_end << 10)) { + while (smpl_pos > ((*note_data)->sample->loop_end << 10)) { + smpl_pos -= ((*note_data)->sample->loop_end - (*note_data)->sample->loop_start) << 10; + } + count_a += (((*note_data)->sample->data_length << 10) - smpl_pos + (*note_data)->sample_inc - 1) / (*note_data)->sample_inc; + } + } else { + count_b = (((*note_data)->sample->data_length << 10) - (*note_data)->sample_pos + (*note_data)->sample_inc - 1) / (*note_data)->sample_inc; + } + if (count_b != 0) { + if (count_b < count_a) { + if (total_samples < count_b) + total_samples = count_b; + } else { + if (total_samples < count_a) + total_samples = count_a; + } + } else { + if (total_samples < count_a) + total_samples = count_a; + } + } else { + if (!((*note_data)->modes & SAMPLE_LOOP)) { + count_b = (((*note_data)->sample->data_length << 10) - (*note_data)->sample_pos) / (*note_data)->sample_inc; + if (count_b < count_a) { + if (total_samples < count_b) + total_samples = count_b; + } else { + if (total_samples < count_a) + total_samples = count_a; + } + } else { + if (total_samples < count_a) + total_samples = count_a; + } + } + note_data++; + } while (note_data != mdi->last_note); + } + mdi->info.approx_total_samples += total_samples; + mdi->recalc_samples = 0; +} + +void +do_amp_setup_note_off (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + mdi->note_vel[ch][mdi->data[track->ptr]] = 0; + + track->running_event = 0x80 | ch; + track->ptr += 2; + return; +} + +void +do_amp_setup_note_on (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (mdi->data[track->ptr+1] == 0x00) { + do_amp_setup_note_off(ch, mdi, track); + track->running_event = 0x90 | ch; + return; + } + + if (mdi->note_vel[ch][mdi->data[track->ptr]]) { + mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + } + + mdi->note_vel[ch][mdi->data[track->ptr]] = mdi->data[track->ptr+1]; + + mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + if (mdi->lin_cur_vol > mdi->lin_max_vol) { + mdi->lin_max_vol = mdi->lin_cur_vol; + } + if (mdi->log_cur_vol > mdi->log_max_vol) { + mdi->log_max_vol = mdi->log_cur_vol; + } + if (ch == 9) { + load_patch(mdi, ((mdi->channel[ch].bank << 8) | (mdi->data[track->ptr] | 0x80))); + } + + track->running_event = 0x90 | ch; + track->ptr += 2; + return; +} + +void +do_amp_setup_aftertouch (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + unsigned char pres = mdi->data[track->ptr+1]; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (pres == 0) + pres = 1; + + if (mdi->note_vel[ch][mdi->data[track->ptr]] != 0) { + mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + mdi->note_vel[ch][mdi->data[track->ptr]] = pres; + + mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][mdi->data[track->ptr]]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + if (mdi->lin_cur_vol > mdi->lin_max_vol) { + mdi->lin_max_vol = mdi->lin_cur_vol; + } + if (mdi->log_cur_vol > mdi->log_max_vol) { + mdi->log_max_vol = mdi->log_cur_vol; + } + } + track->running_event = 0xA0 | ch; + track->ptr += 2; + return; +} + + +void +do_amp_setup_control (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + int i; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (mdi->data[track->ptr] == 0x00) { + mdi->channel[ch].bank = mdi->data[track->ptr + 1]; + } else if (mdi->data[track->ptr] == 0x07) { + for (i=0; i < 128; i++) { + if (mdi->note_vel[ch][i] == 0) + continue; + mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][i]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][i]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][i]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->data[track->ptr + 1]]) / 1048576; + mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][i]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->data[track->ptr + 1]]) / 1048576; + + } + mdi->ch_vol[ch] = mdi->data[track->ptr + 1]; + if (mdi->lin_cur_vol > mdi->lin_max_vol) { + mdi->lin_max_vol = mdi->lin_cur_vol; + } + if (mdi->log_cur_vol > mdi->log_max_vol) { + mdi->log_max_vol = mdi->log_cur_vol; + } + } else if (mdi->data[track->ptr] == 0x0B) { + for (i=0; i < 128; i++) { + if (mdi->note_vel[ch][i] == 0) + continue; + mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][i]] * + lin_volume[mdi->ch_vol[ch]] * lin_volume[mdi->ch_exp[ch]]) / 1048576; + mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][i]] * + log_volume[mdi->ch_vol[ch]] * log_volume[mdi->ch_exp[ch]]) / 1048576; + + mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][i]] * + lin_volume[mdi->ch_vol[ch]] * lin_volume[mdi->data[track->ptr + 1]]) / 1048576; + mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][i]] * + log_volume[mdi->ch_vol[ch]] * log_volume[mdi->data[track->ptr + 1]]) / 1048576; + + } + mdi->ch_exp[ch] = mdi->data[track->ptr + 1]; + if (mdi->lin_cur_vol > mdi->lin_max_vol) { + mdi->lin_max_vol = mdi->lin_cur_vol; + } + if (mdi->log_cur_vol > mdi->log_max_vol) { + mdi->log_max_vol = mdi->log_cur_vol; + } + } + + track->running_event = 0xB0 | ch; + track->ptr += 2; + return; +} + +void +do_amp_setup_patch (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + if (ch == 9) { + mdi->channel[ch].bank = mdi->data[track->ptr]; + } else { + load_patch(mdi, ((mdi->channel[ch].bank << 8) | mdi->data[track->ptr])); + } + track->running_event = 0xC0 | ch; + track->ptr++; + return; +} + +void +do_amp_setup_channel_pressure (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + int i; + unsigned char pres = mdi->data[track->ptr]; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + + if (pres == 0) + pres = 1; + + for (i=0; i < 128; i++) { + if (mdi->note_vel[ch][i] == 0) + continue; + mdi->lin_cur_vol -= (lin_volume[mdi->note_vel[ch][i]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol -= (sqr_volume[mdi->note_vel[ch][i]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + mdi->note_vel[ch][i] = pres; + + mdi->lin_cur_vol += (lin_volume[mdi->note_vel[ch][i]] * + lin_volume[mdi->ch_exp[ch]] * lin_volume[mdi->ch_vol[ch]]) / 1048576; + mdi->log_cur_vol += (sqr_volume[mdi->note_vel[ch][i]] * + log_volume[mdi->ch_exp[ch]] * log_volume[mdi->ch_vol[ch]]) / 1048576; + + } + if (mdi->lin_cur_vol > mdi->lin_max_vol) { + mdi->lin_max_vol = mdi->lin_cur_vol; + } + if (mdi->log_cur_vol > mdi->log_max_vol) { + mdi->log_max_vol = mdi->log_cur_vol; + } + track->running_event = 0xD0 | ch; + track->ptr++; + return; +} + +void +do_amp_setup_pitch (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + track->running_event = 0xE0 | ch; + track->ptr += 2; + return; +} + +void +do_amp_setup_message (unsigned char ch, struct _mdi *mdi, struct _miditrack *track) { + unsigned long int event_length; + unsigned char event_type = 0xF0 | ch; + unsigned char event_data = mdi->data[track->ptr]; + static unsigned long int tempo = 500000; + + MIDI_EVENT_DEBUG(__FUNCTION__,ch); + if (event_type == 0xF0) { + track->running_event = 0x00; + do { + track->ptr++; + } while ( mdi->data[track->ptr] != 0xF7); + track->ptr++; + } else { + track->ptr += 1; + event_length = read_var_length(mdi, track); + if (event_length == 0xFFFFFFFF) { + track->delta = 0xFFFFFFFF; + return; + } + if (event_type == 0xFF) { + if ((event_data == 0x2F) && (event_length == 0)) { // Track End + track->EOT = 1; + return; + } else if ((event_data == 0x51) && (event_length == 3)) { // Tempo Change + tempo = (mdi->data[track->ptr] << 16) | (mdi->data[track->ptr+1] << 8) | mdi->data[track->ptr+2]; + if (tempo == 0) + mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions); + else + mdi->samples_per_delta = (WM_SampleRate << 10) / ((1000000 * mdi->divisions) / tempo); + } + } + track->ptr += event_length; + } +} + + +struct _mdi * +WM_ParseNewMidi(unsigned char *mididata, unsigned long int midisize ) { + int i; + unsigned char eot[] = { 0xff, 0x2f, 0x00}; + unsigned long int index_count = 0; + unsigned long int temp_delta = 0xffffff00; + struct _mdi *mdi = NULL; + void (*do_event[])(unsigned char ch, struct _mdi *midifile, struct _miditrack *track) = { + *do_amp_setup_note_off, + *do_amp_setup_note_on, + *do_amp_setup_aftertouch, + *do_amp_setup_control, + *do_amp_setup_patch, + *do_amp_setup_channel_pressure, + *do_amp_setup_pitch, + *do_amp_setup_message + }; + unsigned long int midiofs = 0; + unsigned long int midi_track_counter = 0; + unsigned long int last_delta; + unsigned long int minus_delta = 0; + unsigned char current_event = 0; + unsigned short int no_tracks; + unsigned long int EOT_count = 0; + struct _miditrack *tmp_trackdata; + struct _hndl *tmp_handle = NULL; + + mdi = malloc(sizeof(struct _mdi)); + if (mdi == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno); + free (mididata); + return NULL; + } + + // Initialize data + memset(mdi, 0, sizeof(struct _mdi)); + mdi->lock = 0; + mdi->data = mididata; + mdi->size = midisize; + mdi->info.mixer_options = WM_MixerOptions; + + mdi->index = malloc(((midisize / 2) + 1)* sizeof(struct _mdi_index)); + if (mdi->index == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno); + free(mdi); + return NULL; + } + + load_patch(mdi, 0x0000); + + for (i=0; i<16; i++) { + mdi->channel[i].volume = 100; + mdi->channel[i].pressure = 127; + mdi->channel[i].expression = 127; + mdi->channel[i].pitch_range = 200; + mdi->channel[i].reg_data = 0xFFFF; + mdi->ch_vol[i] = 100; + mdi->ch_exp[i] = 127; + mdi->channel[i].patch = get_patch_data(mdi, 0x0000); + } + + midiofs = 0; + if (strncmp(mididata,"RIFF",4) == 0) + midiofs = 20; + + if (strncmp(&mididata[midiofs],"MThd",4) != 0) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID,"(not a midi file)", 0); + free(mdi->index); + free(mdi); + return NULL; + } + + if ((midiofs + 25) > midisize) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT,"(too short)", 0); + free(mdi->index); + free(mdi); + return NULL; + } + + midiofs += 9; + if (mididata[midiofs] > 1) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, NULL, 0); + free(mdi->index); + free(mdi); + return NULL; + } + midiofs++; + + no_tracks = mididata[midiofs] << 8 | mididata[midiofs+1]; + midiofs += 2; + + mdi->divisions = mididata[midiofs] << 8 | mididata[midiofs+1]; + mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions); + midiofs += 2; + + tmp_trackdata = calloc(no_tracks, sizeof(struct _miditrack)); + + if (first_handle == NULL) { + first_handle = malloc(sizeof(struct _hndl)); + if (first_handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno); + free(mdi->data); + free(mdi); + return NULL; + } + first_handle->handle = (void *)mdi; + first_handle->prev = NULL; + first_handle->next = NULL; + } else { + tmp_handle = first_handle; + if (tmp_handle->next != NULL) { + while (tmp_handle->next != NULL) + tmp_handle = tmp_handle->next; + } + tmp_handle->next = malloc(sizeof(struct _hndl)); + if (tmp_handle->next == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM," to parse midi data", errno); + free(tmp_trackdata); + free(mdi->data); + free(mdi); + return NULL; + } + tmp_handle->next->prev = tmp_handle; + tmp_handle = tmp_handle->next; + tmp_handle->next = NULL; + tmp_handle->handle = (void *)mdi; + } + + + // grab track offsets; + + midi_track_counter = 0; + while (midi_track_counter != no_tracks) { + if ((midiofs + 12) > midisize) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + if (strncmp(&mididata[midiofs],"MTrk",4) != 0) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(Expected track header)", 0); + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + midiofs += 4; + tmp_trackdata[midi_track_counter].length = mididata[midiofs] << 24 | mididata[midiofs+1] << 16 | mididata[midiofs+2] << 8 | mididata[midiofs+3]; + midiofs += 4; + + if (midisize < (midiofs + tmp_trackdata[midi_track_counter].length)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + tmp_trackdata[midi_track_counter].ptr = midiofs; + tmp_trackdata[midi_track_counter].EOT = 0; + tmp_trackdata[midi_track_counter].running_event = 0; + tmp_trackdata[midi_track_counter].delta = read_var_length(mdi, &tmp_trackdata[midi_track_counter]); + if (tmp_trackdata[midi_track_counter].delta == 0xFFFFFFFF) { + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + midiofs += tmp_trackdata[midi_track_counter].length; + + if (memcmp(&mididata[midiofs-3], eot,3) != 0) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(Expected EOT)", 0); + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + if (tmp_trackdata[midi_track_counter].delta < temp_delta) { + temp_delta = tmp_trackdata[midi_track_counter].delta; + } + midi_track_counter++; + } + +// set midi info + mdi->index[0].offset = 0; + mdi->index[0].delta = temp_delta; + + while (EOT_count != no_tracks) { + last_delta = 0; + for (i = 0; i < no_tracks; i++) { + if (tmp_trackdata[i].EOT) { + continue; + } + if (tmp_trackdata[i].delta) { + tmp_trackdata[i].delta -= minus_delta; + if (tmp_trackdata[i].delta) { + if ((last_delta == 0) || (last_delta > tmp_trackdata[i].delta)) { + last_delta = tmp_trackdata[i].delta; + } + continue; + } + } + do { + if (mdi->data[tmp_trackdata[i].ptr] < 0x80) { + current_event = tmp_trackdata[i].running_event; + if (current_event < 0x80) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(expected event)", 0); + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + } else { + current_event = mdi->data[tmp_trackdata[i].ptr]; + tmp_trackdata[i].ptr++; + } + + + index_count++; + mdi->index[index_count].offset = tmp_trackdata[i].ptr; + mdi->index[index_count].delta = 0; + mdi->index[index_count].event = current_event; + + do_event[((current_event & 0xF0) >> 4) - 8]((current_event & 0x0F), mdi, &tmp_trackdata[i]); + if (tmp_trackdata[i].delta == 0xFFFFFFFF) { + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + if (tmp_trackdata[i].EOT) { + EOT_count++; + break; + } + tmp_trackdata[i].delta = read_var_length(mdi, &tmp_trackdata[i]); + if (tmp_trackdata[i].delta == 0xFFFFFFFF) { + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + } while (!(tmp_trackdata[i].delta)); + if ((last_delta == 0) || (last_delta > tmp_trackdata[i].delta)) { + if (tmp_trackdata[i].delta != 0) { + last_delta = tmp_trackdata[i].delta; + } + } + } +// printf("\rLast Delta %lu\n",last_delta); + mdi->index[index_count].delta = last_delta; + mdi->samples_to_mix += last_delta * mdi->samples_per_delta; + mdi->sample_count += mdi->samples_to_mix >> 10; + mdi->samples_to_mix %= 1024; + minus_delta = last_delta; + } + mdi->sample_count -= (mdi->index[index_count - 1].delta * mdi->samples_per_delta) >> 10; + mdi->index[index_count - 1].delta = 0; + mdi->index_size = index_count; + mdi->index = realloc(mdi->index, (sizeof(struct _mdi_index) * mdi->index_size)); + if (mdi->index == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); + WildMidi_Close(mdi); + free(tmp_trackdata); + return NULL; + } + mdi->info.approx_total_samples = mdi->sample_count + 1; + mdi->samples_to_mix = 0; + mdi->sample_count = 0; + mdi->info.current_sample = 0; + mdi->samples_per_delta = (WM_SampleRate << 10) / (2 * mdi->divisions); + mdi->recalc_samples = 1; + mdi->last_note = mdi->note; + if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) { + mdi->amp = 281; + } else { + mdi->amp = 281 * mdi->lin_max_vol / mdi->log_max_vol; + } + + for (i = 0; i < 16; i++) { + mdi->channel[i].bank = 0; + do_pan_adjust(mdi, i); + } + + for (i = 0; i < 4; i++) { + mdi->filter.lowpass[i][0].in[0] = 0; + mdi->filter.lowpass[i][0].in[1] = 0; + mdi->filter.lowpass[i][1].in[0] = 0; + mdi->filter.lowpass[i][1].in[1] = 0; + + mdi->filter.lowpass[i][0].out[0] = 0; + mdi->filter.lowpass[i][0].out[1] = 0; + mdi->filter.lowpass[i][1].out[0] = 0; + mdi->filter.lowpass[i][1].out[1] = 0; + + mdi->filter.delay_pos[i][0] = 0; + mdi->filter.delay_pos[i][1] = 0; + + mdi->filter.delay[i][0] = malloc(delay_size[i][0] * sizeof(signed long int)); + mdi->filter.delay[i][1] = malloc(delay_size[i][1] * sizeof(signed long int)); + memset (mdi->filter.delay[i][0], 0, (delay_size[i][0] * sizeof(signed long int))); + memset (mdi->filter.delay[i][1], 0, (delay_size[i][1] * sizeof(signed long int))); + + } + mdi->filter.in[0][0] = 0; + mdi->filter.in[0][1] = 0; + mdi->filter.in[1][0] = 0; + mdi->filter.in[1][1] = 0; + mdi->filter.out[0][0] = 0; + mdi->filter.out[0][1] = 0; + mdi->filter.out[1][0] = 0; + mdi->filter.out[1][1] = 0; + + free(tmp_trackdata); + return (mdi); +} + +/* + * ========================= + * External Functions + * ========================= + */ + +const char * +WildMidi_GetString (unsigned short int info) { + switch (info) { + case WM_GS_VERSION: + return WM_Version; + } + return NULL; +} + +int +WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options) { + if (WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + + if (config_file == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL config file pointer)", 0); + return -1; + } + WM_InitPatches(); + if (WM_LoadConfig(config_file) == -1) { + return -1; + } + + if (options & 0xFFD8) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0); + WM_FreePatches(); + return -1; + } + WM_MixerOptions = options; + + if ((rate < 11000) || (rate > 65000)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(rate out of bounds, range is 11000 - 65000)", 0); + WM_FreePatches(); + return -1; + } + WM_SampleRate = rate; + WM_Initialized = 1; + patch_lock = 0; + + init_gauss(); + init_lowpass(); + return 0; +} + +int +WildMidi_MasterVolume (unsigned char master_volume) { + struct _mdi *mdi = NULL; + struct _hndl * tmp_handle = first_handle; + int i = 0; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (master_volume > 127) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(master volume out of range, range is 0-127)", 0); + return -1; + } + + WM_MasterVolume = lin_volume[master_volume]; + + if (tmp_handle != NULL) { + while(tmp_handle != NULL) { + mdi = (struct _mdi *)tmp_handle->handle; + for (i = 0; i < 16; i++) { + do_pan_adjust(mdi, i); + } + tmp_handle = tmp_handle->next; + } + } + + return 0; +} + +int +WildMidi_Close (midi * handle) { + struct _mdi *mdi = (struct _mdi *)handle; + struct _hndl * tmp_handle; + struct _sample *tmp_sample; + int i; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + if (first_handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(no midi's open)", 0); + return -1; + } + WM_Lock(&mdi->lock); + if (first_handle->handle == handle) { + tmp_handle = first_handle->next; + free (first_handle); + first_handle = tmp_handle; + if (first_handle != NULL) + first_handle->prev = NULL; + } else { + tmp_handle = first_handle; + while (tmp_handle->handle != handle) { + tmp_handle = tmp_handle->next; + if (tmp_handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(handle does not exist)", 0); + return -1; + } + } + tmp_handle->prev->next = tmp_handle->next; + if (tmp_handle->next != NULL) { + tmp_handle->next->prev = tmp_handle->prev; + } + free (tmp_handle); + } + + if (mdi->patch_count != 0) { + WM_Lock(&patch_lock); + for (i = 0; i < mdi->patch_count; i++) { + mdi->patches[i]->inuse_count--; + if (mdi->patches[i]->inuse_count == 0) { + //free samples here + if (mdi->patches[i]->first_sample != NULL) { + while (mdi->patches[i]->first_sample != NULL) { + tmp_sample = mdi->patches[i]->first_sample->next; + if (mdi->patches[i]->first_sample->data) + free(mdi->patches[i]->first_sample->data); + free(mdi->patches[i]->first_sample); + mdi->patches[i]->first_sample = tmp_sample; + } + mdi->patches[i]->loaded = 0; + } + } + } + WM_Unlock(&patch_lock); + free (mdi->patches); + } + if (mdi->data != NULL) { + free (mdi->data); + } + if (mdi->tmp_info != NULL) { + free (mdi->tmp_info); + } + if (mdi->index != NULL) + free (mdi->index); + free (mdi); + // no need to unlock cause the struct containing the lock no-longer exists; + return 0; +} + +midi * +WildMidi_Open (const char *midifile) { + unsigned char *mididata = NULL; + unsigned long int midisize = 0; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (midifile == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL filename)", 0); + return NULL; + } + + if ((mididata = WM_BufferFile(midifile, &midisize)) == NULL) { + return NULL; + } + + return (void *)WM_ParseNewMidi(mididata,midisize); +} + +midi * +WildMidi_OpenBuffer (unsigned char *midibuffer, unsigned long int size) { + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (midibuffer == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL midi data buffer)", 0); + return NULL; + } + + return (void *)WM_ParseNewMidi(midibuffer,size); +} + +int +WildMidi_LoadSamples( midi * handle) { + return 0; +} + +int +WildMidi_FastSeek ( midi * handle, unsigned long int *sample_pos) { + struct _mdi *mdi = (struct _mdi *)handle; + struct _note **note_data = mdi->note; + void (*do_event[])(unsigned char ch, struct _mdi *midifile, unsigned long int ptr) = { + *do_null, + *do_null, + *do_aftertouch, + *do_control, + *do_patch, + *do_channel_pressure, + *do_pitch, + *do_message + }; + unsigned long int real_samples_to_mix = 0; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + WM_Lock(&mdi->lock); + if (sample_pos == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL seek position pointer)", 0); + WM_Unlock(&mdi->lock); + return -1; + } + + if (*sample_pos == mdi->info.current_sample) { + WM_Unlock(&mdi->lock); + return 0; + } + + if (*sample_pos > mdi->info.current_sample) { + if ((mdi->sample_count == 0) && (mdi->index_count == mdi->index_size) && (mdi->last_note == 0)) { + *sample_pos = mdi->info.current_sample; + WM_Unlock(&mdi->lock); + return 0; + } + } else { + WM_ResetToStart(handle); + } + + //reset all notes + if (note_data != mdi->last_note) { + do { + (*note_data)->active = 0; + *note_data = NULL; + note_data++; + } while (note_data != mdi->last_note); + mdi->last_note = mdi->note; + } + + while (*sample_pos != mdi->info.current_sample) { + if (!mdi->sample_count) { + if (mdi->index_count != mdi->index_size) { + + do { + if (mdi->index_count == mdi->index_size) { + break; + } + + if (mdi->index_count != 0) { + do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset); + } + } while (mdi->index[mdi->index_count++].delta == 0); + + mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta; + mdi->sample_count = mdi->samples_to_mix >> 10; + mdi->samples_to_mix %= 1024; + } else { + mdi->sample_count = WM_SampleRate; + } + } + + if (mdi->sample_count <= (*sample_pos - mdi->info.current_sample)) { + real_samples_to_mix = mdi->sample_count; + if (real_samples_to_mix == 0) { + continue; + } + } else { + real_samples_to_mix = (*sample_pos - mdi->info.current_sample); + } + + mdi->info.current_sample += real_samples_to_mix; + mdi->sample_count -= real_samples_to_mix; + if ((mdi->index_count == mdi->index_size) && (mdi->last_note == 0)) { + mdi->sample_count = 0; + *sample_pos = mdi->info.current_sample; + WM_Unlock(&mdi->lock); + return 0; + } + } + WM_Unlock(&mdi->lock); + return 0; +} + +int +WildMidi_SampledSeek ( midi * handle, unsigned long int *sample_pos) { + struct _mdi *mdi = (struct _mdi *)handle; + struct _note **note_data = mdi->note; + unsigned long int real_samples_to_mix = 0; + unsigned long int tmp_samples_to_mix = 0; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + WM_Lock(&mdi->lock); + if (sample_pos == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL seek position pointer)", 0); + WM_Unlock(&mdi->lock); + return -1; + } + + if (*sample_pos == mdi->info.current_sample) { + WM_Unlock(&mdi->lock); + return 0; + } + + if (*sample_pos > mdi->info.current_sample) { + if ((mdi->sample_count == 0) && (mdi->index_count == mdi->index_size) && (mdi->last_note == 0)) { + *sample_pos = mdi->info.current_sample; + WM_Unlock(&mdi->lock); + return 0; + } + } else { + WM_ResetToStart(handle); + if (note_data != mdi->last_note) { + do { + (*note_data)->active = 0; + *note_data = NULL; + note_data++; + } while (note_data != mdi->last_note); + mdi->last_note = mdi->note; + } + } + + while (*sample_pos != mdi->info.current_sample) { + if (!mdi->sample_count) { + if (mdi->index_count != mdi->index_size) { + + do { + if (mdi->index_count == mdi->index_size) { + break; + } + + if (mdi->index_count != 0) { + do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset); + } + } while (mdi->index[mdi->index_count++].delta == 0); + + mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta; + mdi->sample_count = mdi->samples_to_mix >> 10; + mdi->samples_to_mix %= 1024; + } else { + if (mdi->recalc_samples) { + WM_RecalcSamples(mdi); + } + mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample; + if (mdi->sample_count == 0) { + WM_Unlock(&mdi->lock); + return 0; + } + } + } + + if (mdi->sample_count <= (*sample_pos - mdi->info.current_sample)) { + real_samples_to_mix = mdi->sample_count; + if (real_samples_to_mix == 0) { + continue; + } + } else { + real_samples_to_mix = (*sample_pos - mdi->info.current_sample); + } + + // do mixing here + tmp_samples_to_mix = real_samples_to_mix; + do { + + if (mdi->last_note != mdi->note) { + note_data = mdi->note; + while (note_data != mdi->last_note) { + + +/* + * ======================== + * sample position checking + * ======================== + */ + (*note_data)->sample_pos += (*note_data)->sample_inc; + if (__builtin_expect(((*note_data)->sample_pos > (*note_data)->sample->loop_end), 0)) { + if ((*note_data)->modes & SAMPLE_LOOP) { + (*note_data)->sample_pos = (*note_data)->sample->loop_start + (((*note_data)->sample_pos - (*note_data)->sample->loop_start) % (*note_data)->sample->loop_size); + } else if (__builtin_expect(((*note_data)->sample_pos >= (*note_data)->sample->data_length), 0)) { + if (__builtin_expect(((*note_data)->next == NULL), 1)) { + goto KILL_NOTE; + } + goto RESTART_NOTE; + } + } + if (__builtin_expect(((*note_data)->env_inc == 0), 0)) { + note_data++; + continue; + } + (*note_data)->env_level += (*note_data)->env_inc; + if (__builtin_expect(((*note_data)->env_level > 4194304), 0)) { + (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env]; + } + if (__builtin_expect((((*note_data)->env_inc < 0) && + ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env])) || + (((*note_data)->env_inc > 0) && + ((*note_data)->env_level < (*note_data)->sample->env_target[(*note_data)->env])), 1)) { + note_data++; + continue; + } + (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env]; + switch ((*note_data)->env) { + case 0: + if (!((*note_data)->modes & SAMPLE_ENVELOPE)) { + (*note_data)->env_inc = 0; + note_data++; + continue; + } + break; + case 2: + if ((*note_data)->modes & SAMPLE_SUSTAIN) { + (*note_data)->env_inc = 0; + note_data++; + continue; + } + break; + case 5: + if (__builtin_expect(((*note_data)->env_level == 0), 1)) { + goto KILL_NOTE; + } + // sample release + if ((*note_data)->modes & SAMPLE_LOOP) + (*note_data)->modes ^= SAMPLE_LOOP; + (*note_data)->env_inc = 0; + note_data++; + continue; + case 6: + if (__builtin_expect(((*note_data)->next != NULL), 1)) { + RESTART_NOTE: + (*note_data)->active = 0; + *note_data = (*note_data)->next; + (*note_data)->active = 1; + note_data++; + + } else { + KILL_NOTE: + (*note_data)->active = 0; + mdi->last_note--; + if (note_data != mdi->last_note) { + *note_data = *mdi->last_note; + } + } + continue; + } + (*note_data)->env++; + if ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env]) { + (*note_data)->env_inc = -(*note_data)->sample->env_rate[(*note_data)->env]; + } else { + (*note_data)->env_inc = (*note_data)->sample->env_rate[(*note_data)->env]; + } + note_data++; + continue; + } + } else { + break; + } + } while (--tmp_samples_to_mix); + mdi->info.current_sample += real_samples_to_mix; + mdi->sample_count -= real_samples_to_mix; + if (mdi->index_count == mdi->index_size) { + if (mdi->last_note == 0) { + mdi->sample_count = 0; + *sample_pos = mdi->info.current_sample; + WM_Unlock(&mdi->lock); + return 0; + } + } + } + WM_Unlock(&mdi->lock); + return 0; +} + +int +WildMidi_GetOutput_Linear (midi * handle, char * buffer, unsigned long int size) { + unsigned long int buffer_used = 0; + struct _mdi *mdi = (struct _mdi *)handle; + unsigned long int real_samples_to_mix = 0; + unsigned long int data_pos; + signed long int premix, left_mix, right_mix; + signed long int vol_mul; + struct _note **note_data = NULL; + unsigned long int count; + + if (__builtin_expect((!WM_Initialized),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (__builtin_expect((handle == NULL),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + if (__builtin_expect((buffer == NULL),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0); + return -1; + } + + if (__builtin_expect((size == 0),0)) { + return 0; + } + + if (__builtin_expect((size % 4),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0); + return -1; + } + + WM_Lock(&mdi->lock); + if (__builtin_expect(((mdi->index_count == mdi->index_size) && (mdi->last_note == 0)), 0)) { + WM_Unlock(&mdi->lock); + return 0; + } + + buffer_used = 0; + memset(buffer, 0, size); + + do { + if (__builtin_expect((!mdi->sample_count),0)) { + if (__builtin_expect((mdi->index_count != mdi->index_size),1)) { + do { + if (__builtin_expect((mdi->index_count == mdi->index_size), 0)) { + break; + } + + if (__builtin_expect((mdi->index_count != 0), 1)) { + do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset); + } + } while (mdi->index[mdi->index_count++].delta == 0); + + mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta; + mdi->sample_count = mdi->samples_to_mix >> 10; + mdi->samples_to_mix %= 1024; + } else { + if (mdi->recalc_samples) { + WM_RecalcSamples(mdi); + } + mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample; + if (mdi->sample_count == 0) { + WM_Unlock(&mdi->lock); + return buffer_used; + } + } + } + if (__builtin_expect((mdi->sample_count > (size >> 2)),1)) { + real_samples_to_mix = size >> 2; + } else { + real_samples_to_mix = mdi->sample_count; + if (real_samples_to_mix == 0) { + continue; + } + } + + // do mixing here + count = real_samples_to_mix; + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (__builtin_expect((mdi->last_note != mdi->note),1)) { + while (note_data != mdi->last_note) { +/* + * =================== + * resample the sample + * =================== + */ + data_pos = (*note_data)->sample_pos >> FPBITS; + vol_mul = (((*note_data)->vol_lvl * ((*note_data)->env_level >> 12)) >> FPBITS); + + premix = ((*note_data)->sample->data[data_pos] + + (((*note_data)->sample->data[data_pos + 1] - (*note_data)->sample->data[data_pos]) * + (signed long int)((*note_data)->sample_pos & FPMASK) >> FPBITS)) * vol_mul / 1024; + + left_mix += premix * mdi->channel[(*note_data)->noteid >> 8].left_adjust; + right_mix += premix * mdi->channel[(*note_data)->noteid >> 8].right_adjust; + +/* + * ======================== + * sample position checking + * ======================== + */ + (*note_data)->sample_pos += (*note_data)->sample_inc; + if (__builtin_expect(((*note_data)->sample_pos > (*note_data)->sample->loop_end), 0)) { + if ((*note_data)->modes & SAMPLE_LOOP) { + (*note_data)->sample_pos = (*note_data)->sample->loop_start + (((*note_data)->sample_pos - (*note_data)->sample->loop_start) % (*note_data)->sample->loop_size); + } else if (__builtin_expect(((*note_data)->sample_pos >= (*note_data)->sample->data_length), 0)) { + if (__builtin_expect(((*note_data)->next == NULL), 1)) { + goto KILL_NOTE; + + } + goto RESTART_NOTE; + } + } + + if (__builtin_expect(((*note_data)->env_inc == 0), 0)) { + note_data++; + continue; + } + + (*note_data)->env_level += (*note_data)->env_inc; + if (__builtin_expect(((*note_data)->env_level > 4194304), 0)) { + (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env]; + } + if (__builtin_expect((((*note_data)->env_inc < 0) && + ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env])) || + (((*note_data)->env_inc > 0) && + ((*note_data)->env_level < (*note_data)->sample->env_target[(*note_data)->env])), 1)) { + note_data++; + continue; + } + + (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env]; + switch ((*note_data)->env) { + case 0: + if (!((*note_data)->modes & SAMPLE_ENVELOPE)) { + (*note_data)->env_inc = 0; + note_data++; + continue; + } + break; + case 2: + if ((*note_data)->modes & SAMPLE_SUSTAIN) { + (*note_data)->env_inc = 0; + note_data++; + continue; + } + break; + case 5: + if (__builtin_expect(((*note_data)->env_level == 0), 1)) { + goto KILL_NOTE; + } + // sample release + if ((*note_data)->modes & SAMPLE_LOOP) + (*note_data)->modes ^= SAMPLE_LOOP; + (*note_data)->env_inc = 0; + note_data++; + continue; + case 6: + if (__builtin_expect(((*note_data)->next != NULL), 1)) { + RESTART_NOTE: + (*note_data)->active = 0; + *note_data = (*note_data)->next; + (*note_data)->active = 1; + note_data++; + + } else { + KILL_NOTE: + (*note_data)->active = 0; + mdi->last_note--; + if (note_data != mdi->last_note) { + *note_data = *mdi->last_note; + } + } + continue; + } + (*note_data)->env++; + if ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env]) { + (*note_data)->env_inc = -(*note_data)->sample->env_rate[(*note_data)->env]; + } else { + (*note_data)->env_inc = (*note_data)->sample->env_rate[(*note_data)->env]; + } + note_data++; + continue; + } +/* + * ========================= + * mix the channels together + * ========================= + */ + + left_mix /= 1024; + right_mix /= 1024; + } + +#ifdef EXPERIMENT_626 +/* + * ========================== + * Experimental Reverb Engine + * ========================== + */ + + if (mdi->info.mixer_options & WM_MO_REVERB) { + signed long int filteral = mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]]; + signed long int filterar = mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]]; + signed long int filterbl = mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]]; + signed long int filterbr = mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]]; + signed long int filtercl = mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]]; + signed long int filtercr = mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]]; + signed long int filterdl = mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]]; + signed long int filterdr = mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]]; + signed long int tfal = (a[0][0] * filteral + a[0][1] * mdi->filter.lowpass[0][0].in[0] + a[0][0] * mdi->filter.lowpass[0][0].in[1] - b[0][0] * mdi->filter.lowpass[0][0].out[0] - b[0][1] * mdi->filter.lowpass[0][0].out[1]) / 1024; + signed long int tfar = (a[0][0] * filterar + a[0][1] * mdi->filter.lowpass[0][1].in[0] + a[0][0] * mdi->filter.lowpass[0][1].in[1] - b[0][0] * mdi->filter.lowpass[0][1].out[0] - b[0][1] * mdi->filter.lowpass[0][1].out[1]) / 1024; + signed long int tfbl = (a[1][0] * filterbl + a[1][1] * mdi->filter.lowpass[1][0].in[0] + a[1][0] * mdi->filter.lowpass[1][0].in[1] - b[1][0] * mdi->filter.lowpass[1][0].out[0] - b[1][1] * mdi->filter.lowpass[1][0].out[1]) / 1024; + signed long int tfbr = (a[1][0] * filterbr + a[1][1] * mdi->filter.lowpass[1][1].in[0] + a[1][0] * mdi->filter.lowpass[1][1].in[1] - b[1][0] * mdi->filter.lowpass[1][1].out[0] - b[1][1] * mdi->filter.lowpass[1][1].out[1]) / 1024; + signed long int tfcl = (a[2][0] * filtercl + a[2][1] * mdi->filter.lowpass[2][0].in[0] + a[2][0] * mdi->filter.lowpass[2][0].in[1] - b[2][0] * mdi->filter.lowpass[2][0].out[0] - b[2][1] * mdi->filter.lowpass[2][0].out[1]) / 1024; + signed long int tfcr = (a[2][0] * filtercr + a[2][1] * mdi->filter.lowpass[2][1].in[0] + a[2][0] * mdi->filter.lowpass[2][1].in[1] - b[2][0] * mdi->filter.lowpass[2][1].out[0] - b[2][1] * mdi->filter.lowpass[2][1].out[1]) / 1024; + signed long int tfdl = (a[3][0] * filterdl + a[3][1] * mdi->filter.lowpass[3][0].in[0] + a[3][0] * mdi->filter.lowpass[3][0].in[1] - b[3][0] * mdi->filter.lowpass[3][0].out[0] - b[3][1] * mdi->filter.lowpass[3][0].out[1]) / 1024; + signed long int tfdr = (a[3][0] * filterdr + a[3][1] * mdi->filter.lowpass[3][1].in[0] + a[3][0] * mdi->filter.lowpass[3][1].in[1] - b[3][0] * mdi->filter.lowpass[3][1].out[0] - b[3][1] * mdi->filter.lowpass[3][1].out[1]) / 1024; + signed long int tfl, tflo; + signed long int tfr, tfro; + + mdi->filter.lowpass[0][0].in[1] = mdi->filter.lowpass[0][0].in[0]; + mdi->filter.lowpass[0][0].in[0] = filteral; + mdi->filter.lowpass[0][1].in[1] = mdi->filter.lowpass[0][1].in[0]; + mdi->filter.lowpass[0][1].in[0] = filterar; + mdi->filter.lowpass[1][0].in[1] = mdi->filter.lowpass[1][0].in[0]; + mdi->filter.lowpass[1][0].in[0] = filterbl; + mdi->filter.lowpass[1][1].in[1] = mdi->filter.lowpass[1][1].in[0]; + mdi->filter.lowpass[1][1].in[0] = filterbr; + mdi->filter.lowpass[2][0].in[1] = mdi->filter.lowpass[2][0].in[0]; + mdi->filter.lowpass[2][0].in[0] = filtercl; + mdi->filter.lowpass[2][1].in[1] = mdi->filter.lowpass[2][1].in[0]; + mdi->filter.lowpass[2][1].in[0] = filtercr; + mdi->filter.lowpass[3][0].in[1] = mdi->filter.lowpass[3][0].in[0]; + mdi->filter.lowpass[3][0].in[0] = filterdl; + mdi->filter.lowpass[3][1].in[1] = mdi->filter.lowpass[3][1].in[0]; + mdi->filter.lowpass[3][1].in[0] = filterdr; + + mdi->filter.lowpass[0][0].out[1] = mdi->filter.lowpass[0][0].out[0]; + mdi->filter.lowpass[0][0].out[0] = tfal; + mdi->filter.lowpass[0][1].out[1] = mdi->filter.lowpass[0][1].out[0]; + mdi->filter.lowpass[0][1].out[0] = tfar; + mdi->filter.lowpass[1][0].out[1] = mdi->filter.lowpass[1][0].out[0]; + mdi->filter.lowpass[1][0].out[0] = tfbl; + mdi->filter.lowpass[1][1].out[1] = mdi->filter.lowpass[1][1].out[0]; + mdi->filter.lowpass[1][1].out[0] = tfbr; + mdi->filter.lowpass[2][0].out[1] = mdi->filter.lowpass[2][0].out[0]; + mdi->filter.lowpass[2][0].out[0] = tfcl; + mdi->filter.lowpass[2][1].out[1] = mdi->filter.lowpass[2][1].out[0]; + mdi->filter.lowpass[2][1].out[0] = tfcr; + mdi->filter.lowpass[3][0].out[1] = mdi->filter.lowpass[3][0].out[0]; + mdi->filter.lowpass[3][0].out[0] = tfdl; + mdi->filter.lowpass[3][1].out[1] = mdi->filter.lowpass[3][1].out[0]; + mdi->filter.lowpass[3][1].out[0] = tfdr; + + mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]] = (tfbr * 405 + tfcr * 368) / 1024 + (left_mix * gain_in[0] / 1024); + mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]] = (tfbl * 402 + tfcl * 370) / 1024 + (right_mix * gain_in[0] / 1024); + mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]] = (tfar * -545 + tfdr * -364) / 1024 + (left_mix * gain_in[1] / 1024); + mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]] = (tfal * -550 + tfdl * -362) / 1024 + (right_mix * gain_in[1] / 1024); + mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]] = (tfar * 545 + tfdr * -364) / 1024 + (left_mix * gain_in[2] / 1024); + mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]] = (tfal * 550 + tfdl * 362) / 1024 + (right_mix * gain_in[2] / 1024); + mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]] = (tfbr * 405 + tfcr * -368) / 1024 + (left_mix * gain_in[3] / 1024); + mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]] = (tfbl * 402 + tfcl * -370) / 1024 + (right_mix * gain_in[3] / 1024); + + tfl = ((tfal * gain_out[0] / 1024) + (tfbl * gain_out[1] / 1024) + (tfcl * gain_out[2] / 1024) + (tfdl * gain_out[3] / 1024)); + tfr = ((tfar * gain_out[0] / 1024) + (tfbr * gain_out[1] / 1024) + (tfcr * gain_out[2] / 1024) + (tfdr * gain_out[3] / 1024)); + + tflo = (a[4][0] * tfl + a[4][1] * mdi->filter.in[0][0] + a[4][0] * mdi->filter.in[1][0] - b[4][0] * mdi->filter.out[0][0] - b[4][1] * mdi->filter.out[1][0]) / 1024; + tfro = (a[4][0] * tfr + a[4][1] * mdi->filter.in[0][1] + a[4][0] * mdi->filter.in[1][1] - b[4][0] * mdi->filter.out[0][1] - b[4][1] * mdi->filter.out[1][1]) / 1024; + + mdi->filter.in[1][0] = mdi->filter.in[0][0]; + mdi->filter.in[0][0] = tfl; + mdi->filter.in[1][1] = mdi->filter.in[0][1]; + mdi->filter.in[0][1] = tfr; + mdi->filter.out[1][0] = mdi->filter.out[0][0]; + mdi->filter.out[0][0] = tflo; + mdi->filter.out[1][1] = mdi->filter.out[0][1]; + mdi->filter.out[0][1] = tfro; + + left_mix += tflo; + right_mix += tfro; + + mdi->filter.delay_pos[0][0]++; + mdi->filter.delay_pos[0][1]++; + mdi->filter.delay_pos[1][0]++; + mdi->filter.delay_pos[1][1]++; + mdi->filter.delay_pos[2][0]++; + mdi->filter.delay_pos[2][1]++; + mdi->filter.delay_pos[3][0]++; + mdi->filter.delay_pos[3][1]++; + + if (mdi->filter.delay_pos[0][0] == delay_size[0][0]) mdi->filter.delay_pos[0][0] = 0; + if (mdi->filter.delay_pos[0][1] == delay_size[0][1]) mdi->filter.delay_pos[0][1] = 0; + if (mdi->filter.delay_pos[1][0] == delay_size[1][0]) mdi->filter.delay_pos[1][0] = 0; + if (mdi->filter.delay_pos[1][1] == delay_size[1][1]) mdi->filter.delay_pos[1][1] = 0; + if (mdi->filter.delay_pos[2][0] == delay_size[2][0]) mdi->filter.delay_pos[2][0] = 0; + if (mdi->filter.delay_pos[2][1] == delay_size[2][1]) mdi->filter.delay_pos[2][1] = 0; + if (mdi->filter.delay_pos[3][0] == delay_size[3][0]) mdi->filter.delay_pos[3][0] = 0; + if (mdi->filter.delay_pos[3][1] == delay_size[3][1]) mdi->filter.delay_pos[3][1] = 0; + + } +#endif + if (left_mix > 32767) { + left_mix = 32767; + } else if (left_mix < -32768) { + left_mix = -32768; + } + + if (right_mix > 32767) { + right_mix = 32767; + } else if (right_mix < -32768) { + right_mix = -32768; + } + + +/* + * =================== + * Write to the buffer + * =================== + */ + (*buffer++) = left_mix & 0xff; + (*buffer++) = (left_mix >> 8) & 0xff; + (*buffer++) = right_mix & 0xff; + (*buffer++) = (right_mix >> 8) & 0xff; + } while (--count); + + buffer_used += real_samples_to_mix * 4; + size -= (real_samples_to_mix << 2); + mdi->info.current_sample += real_samples_to_mix; + mdi->sample_count -= real_samples_to_mix; + if (mdi->index_count == mdi->index_size) { + if (mdi->last_note == 0) { + mdi->sample_count = 0; + WM_Unlock(&mdi->lock); + return buffer_used; + } + } + } while (size); + + if ((mdi->index_count == mdi->index_size) && (mdi->recalc_samples)) { + WM_RecalcSamples(mdi); + mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample; + } + WM_Unlock(&mdi->lock); + return buffer_used; +} + +int +WildMidi_GetOutput_Gauss (midi * handle, char * buffer, unsigned long int size) { + unsigned long int buffer_used = 0; + struct _mdi *mdi = (struct _mdi *)handle; + unsigned long int real_samples_to_mix = 0; + unsigned long int data_pos; + signed long int premix, left_mix, right_mix; + signed long int vol_mul; + struct _note **note_data = NULL; + unsigned long int count; + signed short int *sptr; + double y, xd; + float *gptr, *gend; + int left, right, temp_n; + int ii, jj; + + + if (__builtin_expect((!WM_Initialized),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (__builtin_expect((handle == NULL),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + if (__builtin_expect((buffer == NULL),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0); + return -1; + } + + if (__builtin_expect((size == 0),0)) { + return 0; + } + + if (__builtin_expect((size % 4),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0); + return -1; + } + + WM_Lock(&mdi->lock); + if (__builtin_expect(((mdi->index_count == mdi->index_size) && (mdi->last_note == 0)), 0)) { + WM_Unlock(&mdi->lock); + return 0; + } + + buffer_used = 0; + memset(buffer, 0, size); + + do { + if (__builtin_expect((!mdi->sample_count),0)) { + if (__builtin_expect((mdi->index_count != mdi->index_size),1)) { + do { + if (__builtin_expect((mdi->index_count == mdi->index_size), 0)) { + break; + } + + if (__builtin_expect((mdi->index_count != 0), 1)) { + do_event[((mdi->index[mdi->index_count].event & 0xF0) >> 4) - 8]((mdi->index[mdi->index_count].event & 0x0F), mdi, mdi->index[mdi->index_count].offset); + } + } while (mdi->index[mdi->index_count++].delta == 0); + + mdi->samples_to_mix += mdi->index[mdi->index_count-1].delta * mdi->samples_per_delta; + mdi->sample_count = mdi->samples_to_mix >> 10; + mdi->samples_to_mix %= 1024; + } else { + if (mdi->recalc_samples) { + WM_RecalcSamples(mdi); + } + mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample; + if (mdi->sample_count == 0) { + WM_Unlock(&mdi->lock); + return buffer_used; + } + } + } + if (__builtin_expect((mdi->sample_count > (size >> 2)),1)) { + real_samples_to_mix = size >> 2; + } else { + real_samples_to_mix = mdi->sample_count; + if (real_samples_to_mix == 0) { + continue; + } + } + + // do mixing here + count = real_samples_to_mix; + do { + note_data = mdi->note; + left_mix = right_mix = 0; + if (__builtin_expect((mdi->last_note != mdi->note),1)) { + while (note_data != mdi->last_note) { +/* + * =================== + * resample the sample + * =================== + */ + data_pos = (*note_data)->sample_pos >> FPBITS; + vol_mul = (((*note_data)->vol_lvl * ((*note_data)->env_level >> 12)) >> FPBITS); + + /* check to see if we're near one of the ends */ + left = data_pos; + right = ((*note_data)->sample->data_length>>FPBITS)- left -1; + temp_n = (right<<1)-1; + if (temp_n <= 0) + temp_n = 1; + if (temp_n > (left<<1)+1) + temp_n = (left<<1)+1; + + /* use Newton if we can't fill the window */ + if (temp_n < gauss_n) { + xd = (*note_data)->sample_pos & FPMASK; + xd /= (1L<>1; + y = 0; + sptr = (*note_data)->sample->data + ((*note_data)->sample_pos>>FPBITS) - (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; + } else { /* otherwise, use Gauss as usual */ + y = 0; + gptr = gauss_table[(*note_data)->sample_pos & FPMASK]; + gend = gptr + gauss_n; + sptr = (*note_data)->sample->data + ((*note_data)->sample_pos >> FPBITS) - (gauss_n>>1); + do { + y += *(sptr++) * *(gptr++); + } while (gptr <= gend); + } + + premix = y * vol_mul / 1024; + + left_mix += premix * mdi->channel[(*note_data)->noteid >> 8].left_adjust; + right_mix += premix * mdi->channel[(*note_data)->noteid >> 8].right_adjust; + +/* + * ======================== + * sample position checking + * ======================== + */ + (*note_data)->sample_pos += (*note_data)->sample_inc; + if (__builtin_expect(((*note_data)->sample_pos > (*note_data)->sample->loop_end), 0)) { + if ((*note_data)->modes & SAMPLE_LOOP) { + (*note_data)->sample_pos = (*note_data)->sample->loop_start + (((*note_data)->sample_pos - (*note_data)->sample->loop_start) % (*note_data)->sample->loop_size); + } else if (__builtin_expect(((*note_data)->sample_pos >= (*note_data)->sample->data_length), 0)) { + if (__builtin_expect(((*note_data)->next == NULL), 1)) { + goto KILL_NOTE; + + } + goto RESTART_NOTE; + } + } + + if (__builtin_expect(((*note_data)->env_inc == 0), 0)) { + note_data++; + continue; + } + + (*note_data)->env_level += (*note_data)->env_inc; + if (__builtin_expect(((*note_data)->env_level > 4194304), 0)) { + (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env]; + } + if (__builtin_expect((((*note_data)->env_inc < 0) && + ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env])) || + (((*note_data)->env_inc > 0) && + ((*note_data)->env_level < (*note_data)->sample->env_target[(*note_data)->env])), 1)) { + note_data++; + continue; + } + + (*note_data)->env_level = (*note_data)->sample->env_target[(*note_data)->env]; + switch ((*note_data)->env) { + case 0: + if (!((*note_data)->modes & SAMPLE_ENVELOPE)) { + (*note_data)->env_inc = 0; + note_data++; + continue; + } + break; + case 2: + if ((*note_data)->modes & SAMPLE_SUSTAIN) { + (*note_data)->env_inc = 0; + note_data++; + continue; + } + break; + case 5: + if (__builtin_expect(((*note_data)->env_level == 0), 1)) { + goto KILL_NOTE; + } + // sample release + if ((*note_data)->modes & SAMPLE_LOOP) + (*note_data)->modes ^= SAMPLE_LOOP; + (*note_data)->env_inc = 0; + note_data++; + continue; + case 6: + if (__builtin_expect(((*note_data)->next != NULL), 1)) { + RESTART_NOTE: + (*note_data)->active = 0; + *note_data = (*note_data)->next; + (*note_data)->active = 1; + note_data++; + + } else { + KILL_NOTE: + (*note_data)->active = 0; + mdi->last_note--; + if (note_data != mdi->last_note) { + *note_data = *mdi->last_note; + } + } + continue; + } + (*note_data)->env++; + if ((*note_data)->env_level > (*note_data)->sample->env_target[(*note_data)->env]) { + (*note_data)->env_inc = -(*note_data)->sample->env_rate[(*note_data)->env]; + } else { + (*note_data)->env_inc = (*note_data)->sample->env_rate[(*note_data)->env]; + } + note_data++; + continue; + } +/* + * ========================= + * mix the channels together + * ========================= + */ + + left_mix /= 1024; + right_mix /= 1024; + } + +#ifdef EXPERIMENT_626 +/* + * ========================== + * Experimental Reverb Engine + * ========================== + */ + + if (mdi->info.mixer_options & WM_MO_REVERB) { + signed long int filteral = mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]]; + signed long int filterar = mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]]; + signed long int filterbl = mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]]; + signed long int filterbr = mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]]; + signed long int filtercl = mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]]; + signed long int filtercr = mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]]; + signed long int filterdl = mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]]; + signed long int filterdr = mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]]; + signed long int tfal = (a[0][0] * filteral + a[0][1] * mdi->filter.lowpass[0][0].in[0] + a[0][0] * mdi->filter.lowpass[0][0].in[1] - b[0][0] * mdi->filter.lowpass[0][0].out[0] - b[0][1] * mdi->filter.lowpass[0][0].out[1]) / 1024; + signed long int tfar = (a[0][0] * filterar + a[0][1] * mdi->filter.lowpass[0][1].in[0] + a[0][0] * mdi->filter.lowpass[0][1].in[1] - b[0][0] * mdi->filter.lowpass[0][1].out[0] - b[0][1] * mdi->filter.lowpass[0][1].out[1]) / 1024; + signed long int tfbl = (a[1][0] * filterbl + a[1][1] * mdi->filter.lowpass[1][0].in[0] + a[1][0] * mdi->filter.lowpass[1][0].in[1] - b[1][0] * mdi->filter.lowpass[1][0].out[0] - b[1][1] * mdi->filter.lowpass[1][0].out[1]) / 1024; + signed long int tfbr = (a[1][0] * filterbr + a[1][1] * mdi->filter.lowpass[1][1].in[0] + a[1][0] * mdi->filter.lowpass[1][1].in[1] - b[1][0] * mdi->filter.lowpass[1][1].out[0] - b[1][1] * mdi->filter.lowpass[1][1].out[1]) / 1024; + signed long int tfcl = (a[2][0] * filtercl + a[2][1] * mdi->filter.lowpass[2][0].in[0] + a[2][0] * mdi->filter.lowpass[2][0].in[1] - b[2][0] * mdi->filter.lowpass[2][0].out[0] - b[2][1] * mdi->filter.lowpass[2][0].out[1]) / 1024; + signed long int tfcr = (a[2][0] * filtercr + a[2][1] * mdi->filter.lowpass[2][1].in[0] + a[2][0] * mdi->filter.lowpass[2][1].in[1] - b[2][0] * mdi->filter.lowpass[2][1].out[0] - b[2][1] * mdi->filter.lowpass[2][1].out[1]) / 1024; + signed long int tfdl = (a[3][0] * filterdl + a[3][1] * mdi->filter.lowpass[3][0].in[0] + a[3][0] * mdi->filter.lowpass[3][0].in[1] - b[3][0] * mdi->filter.lowpass[3][0].out[0] - b[3][1] * mdi->filter.lowpass[3][0].out[1]) / 1024; + signed long int tfdr = (a[3][0] * filterdr + a[3][1] * mdi->filter.lowpass[3][1].in[0] + a[3][0] * mdi->filter.lowpass[3][1].in[1] - b[3][0] * mdi->filter.lowpass[3][1].out[0] - b[3][1] * mdi->filter.lowpass[3][1].out[1]) / 1024; + signed long int tfl, tflo; + signed long int tfr, tfro; + + mdi->filter.lowpass[0][0].in[1] = mdi->filter.lowpass[0][0].in[0]; + mdi->filter.lowpass[0][0].in[0] = filteral; + mdi->filter.lowpass[0][1].in[1] = mdi->filter.lowpass[0][1].in[0]; + mdi->filter.lowpass[0][1].in[0] = filterar; + mdi->filter.lowpass[1][0].in[1] = mdi->filter.lowpass[1][0].in[0]; + mdi->filter.lowpass[1][0].in[0] = filterbl; + mdi->filter.lowpass[1][1].in[1] = mdi->filter.lowpass[1][1].in[0]; + mdi->filter.lowpass[1][1].in[0] = filterbr; + mdi->filter.lowpass[2][0].in[1] = mdi->filter.lowpass[2][0].in[0]; + mdi->filter.lowpass[2][0].in[0] = filtercl; + mdi->filter.lowpass[2][1].in[1] = mdi->filter.lowpass[2][1].in[0]; + mdi->filter.lowpass[2][1].in[0] = filtercr; + mdi->filter.lowpass[3][0].in[1] = mdi->filter.lowpass[3][0].in[0]; + mdi->filter.lowpass[3][0].in[0] = filterdl; + mdi->filter.lowpass[3][1].in[1] = mdi->filter.lowpass[3][1].in[0]; + mdi->filter.lowpass[3][1].in[0] = filterdr; + + mdi->filter.lowpass[0][0].out[1] = mdi->filter.lowpass[0][0].out[0]; + mdi->filter.lowpass[0][0].out[0] = tfal; + mdi->filter.lowpass[0][1].out[1] = mdi->filter.lowpass[0][1].out[0]; + mdi->filter.lowpass[0][1].out[0] = tfar; + mdi->filter.lowpass[1][0].out[1] = mdi->filter.lowpass[1][0].out[0]; + mdi->filter.lowpass[1][0].out[0] = tfbl; + mdi->filter.lowpass[1][1].out[1] = mdi->filter.lowpass[1][1].out[0]; + mdi->filter.lowpass[1][1].out[0] = tfbr; + mdi->filter.lowpass[2][0].out[1] = mdi->filter.lowpass[2][0].out[0]; + mdi->filter.lowpass[2][0].out[0] = tfcl; + mdi->filter.lowpass[2][1].out[1] = mdi->filter.lowpass[2][1].out[0]; + mdi->filter.lowpass[2][1].out[0] = tfcr; + mdi->filter.lowpass[3][0].out[1] = mdi->filter.lowpass[3][0].out[0]; + mdi->filter.lowpass[3][0].out[0] = tfdl; + mdi->filter.lowpass[3][1].out[1] = mdi->filter.lowpass[3][1].out[0]; + mdi->filter.lowpass[3][1].out[0] = tfdr; + + mdi->filter.delay[0][0][mdi->filter.delay_pos[0][0]] = (tfbr * 405 + tfcr * 368) / 1024 + (left_mix * gain_in[0] / 1024); + mdi->filter.delay[0][1][mdi->filter.delay_pos[0][1]] = (tfbl * 402 + tfcl * 370) / 1024 + (right_mix * gain_in[0] / 1024); + mdi->filter.delay[1][0][mdi->filter.delay_pos[1][0]] = (tfar * -545 + tfdr * -364) / 1024 + (left_mix * gain_in[1] / 1024); + mdi->filter.delay[1][1][mdi->filter.delay_pos[1][1]] = (tfal * -550 + tfdl * -362) / 1024 + (right_mix * gain_in[1] / 1024); + mdi->filter.delay[2][0][mdi->filter.delay_pos[2][0]] = (tfar * 545 + tfdr * -364) / 1024 + (left_mix * gain_in[2] / 1024); + mdi->filter.delay[2][1][mdi->filter.delay_pos[2][1]] = (tfal * 550 + tfdl * 362) / 1024 + (right_mix * gain_in[2] / 1024); + mdi->filter.delay[3][0][mdi->filter.delay_pos[3][0]] = (tfbr * 405 + tfcr * -368) / 1024 + (left_mix * gain_in[3] / 1024); + mdi->filter.delay[3][1][mdi->filter.delay_pos[3][1]] = (tfbl * 402 + tfcl * -370) / 1024 + (right_mix * gain_in[3] / 1024); + + tfl = ((tfal * gain_out[0] / 1024) + (tfbl * gain_out[1] / 1024) + (tfcl * gain_out[2] / 1024) + (tfdl * gain_out[3] / 1024)); + tfr = ((tfar * gain_out[0] / 1024) + (tfbr * gain_out[1] / 1024) + (tfcr * gain_out[2] / 1024) + (tfdr * gain_out[3] / 1024)); + + tflo = (a[4][0] * tfl + a[4][1] * mdi->filter.in[0][0] + a[4][0] * mdi->filter.in[1][0] - b[4][0] * mdi->filter.out[0][0] - b[4][1] * mdi->filter.out[1][0]) / 1024; + tfro = (a[4][0] * tfr + a[4][1] * mdi->filter.in[0][1] + a[4][0] * mdi->filter.in[1][1] - b[4][0] * mdi->filter.out[0][1] - b[4][1] * mdi->filter.out[1][1]) / 1024; + + mdi->filter.in[1][0] = mdi->filter.in[0][0]; + mdi->filter.in[0][0] = tfl; + mdi->filter.in[1][1] = mdi->filter.in[0][1]; + mdi->filter.in[0][1] = tfr; + mdi->filter.out[1][0] = mdi->filter.out[0][0]; + mdi->filter.out[0][0] = tflo; + mdi->filter.out[1][1] = mdi->filter.out[0][1]; + mdi->filter.out[0][1] = tfro; + + left_mix += tflo; + right_mix += tfro; + + mdi->filter.delay_pos[0][0]++; + mdi->filter.delay_pos[0][1]++; + mdi->filter.delay_pos[1][0]++; + mdi->filter.delay_pos[1][1]++; + mdi->filter.delay_pos[2][0]++; + mdi->filter.delay_pos[2][1]++; + mdi->filter.delay_pos[3][0]++; + mdi->filter.delay_pos[3][1]++; + + if (mdi->filter.delay_pos[0][0] == delay_size[0][0]) mdi->filter.delay_pos[0][0] = 0; + if (mdi->filter.delay_pos[0][1] == delay_size[0][1]) mdi->filter.delay_pos[0][1] = 0; + if (mdi->filter.delay_pos[1][0] == delay_size[1][0]) mdi->filter.delay_pos[1][0] = 0; + if (mdi->filter.delay_pos[1][1] == delay_size[1][1]) mdi->filter.delay_pos[1][1] = 0; + if (mdi->filter.delay_pos[2][0] == delay_size[2][0]) mdi->filter.delay_pos[2][0] = 0; + if (mdi->filter.delay_pos[2][1] == delay_size[2][1]) mdi->filter.delay_pos[2][1] = 0; + if (mdi->filter.delay_pos[3][0] == delay_size[3][0]) mdi->filter.delay_pos[3][0] = 0; + if (mdi->filter.delay_pos[3][1] == delay_size[3][1]) mdi->filter.delay_pos[3][1] = 0; + + } +#endif + if (left_mix > 32767) { + left_mix = 32767; + } else if (left_mix < -32768) { + left_mix = -32768; + } + + if (right_mix > 32767) { + right_mix = 32767; + } else if (right_mix < -32768) { + right_mix = -32768; + } + + +/* + * =================== + * Write to the buffer + * =================== + */ + (*buffer++) = left_mix & 0xff; + (*buffer++) = (left_mix >> 8) & 0xff; + (*buffer++) = right_mix & 0xff; + (*buffer++) = (right_mix >> 8) & 0xff; + } while (--count); + + buffer_used += real_samples_to_mix * 4; + size -= (real_samples_to_mix << 2); + mdi->info.current_sample += real_samples_to_mix; + mdi->sample_count -= real_samples_to_mix; + if (mdi->index_count == mdi->index_size) { + if (mdi->last_note == 0) { + mdi->sample_count = 0; + WM_Unlock(&mdi->lock); + return buffer_used; + } + } + } while (size); + + if ((mdi->index_count == mdi->index_size) && (mdi->recalc_samples)) { + WM_RecalcSamples(mdi); + mdi->sample_count = mdi->info.approx_total_samples - mdi->info.current_sample; + } + WM_Unlock(&mdi->lock); + return buffer_used; +} + +int +WildMidi_GetOutput (midi * handle, char * buffer, unsigned long int size) { + struct _mdi *mdi = (struct _mdi *)handle; + + if (__builtin_expect((!WM_Initialized),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (__builtin_expect((handle == NULL),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + if (__builtin_expect((buffer == NULL),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL buffer pointer)", 0); + return -1; + } + + if (__builtin_expect((size == 0),0)) { + return 0; + } + + if (__builtin_expect((size % 4),0)) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(size not a multiple of 4)", 0); + return -1; + } + if (mdi->info.mixer_options & WM_MO_EXPENSIVE_INTERPOLATION) { + return WildMidi_GetOutput_Gauss (handle, buffer,size); + } else { + return WildMidi_GetOutput_Linear (handle, buffer, size); + } +} + +int +WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting) { + struct _mdi *mdi = (struct _mdi *)handle; + struct _note **note_data = mdi->note; + int i; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return -1; + } + WM_Lock(&mdi->lock); + if ((!(options & 0x0007)) || (options & 0xFFF8)){ + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", 0); + WM_Unlock(&mdi->lock); + return -1; + } + if (setting & 0xFFF8) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid setting)", 0); + WM_Unlock(&mdi->lock); + return -1; + } + + mdi->info.mixer_options = ((mdi->info.mixer_options & (0x00FF ^ options)) | (options & setting)); + + if (options & WM_MO_LINEAR_VOLUME) { + if (mdi->info.mixer_options & WM_MO_LINEAR_VOLUME) { + mdi->amp = 281; + } else { + mdi->amp = 281 * mdi->lin_max_vol / mdi->log_max_vol; + } + for (i = 0; i < 16; i++) { + do_pan_adjust(mdi, i); + } + if (note_data != mdi->last_note) { + do { + (*note_data)->vol_lvl = get_volume(mdi, ((*note_data)->noteid >> 8), *note_data); + if ((*note_data)->next) + (*note_data)->next->vol_lvl = get_volume(mdi, ((*note_data)->noteid >> 8), (*note_data)->next); + note_data++; + } while (note_data != mdi->last_note); + } + } + + if (options & WM_MO_REVERB) { + for (i = 0; i < 4; i++) { + mdi->filter.lowpass[i][0].in[0] = 0; + mdi->filter.lowpass[i][0].in[1] = 0; + mdi->filter.lowpass[i][1].in[0] = 0; + mdi->filter.lowpass[i][1].in[1] = 0; + + mdi->filter.lowpass[i][0].out[0] = 0; + mdi->filter.lowpass[i][0].out[1] = 0; + mdi->filter.lowpass[i][1].out[0] = 0; + mdi->filter.lowpass[i][1].out[1] = 0; + + mdi->filter.delay_pos[i][0] = 0; + mdi->filter.delay_pos[i][1] = 0; + + memset (mdi->filter.delay[i][0], 0, (delay_size[i][0] * sizeof(signed long int))); + memset (mdi->filter.delay[i][1], 0, (delay_size[i][1] * sizeof(signed long int))); + } + } + WM_Unlock(&mdi->lock); + return 0; +} + +struct _WM_Info * +WildMidi_GetInfo (midi * handle) { + struct _mdi *mdi = (struct _mdi *)handle; + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return NULL; + } + if (handle == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", 0); + return NULL; + } + WM_Lock(&mdi->lock); + if (mdi->tmp_info == NULL) { + mdi->tmp_info = malloc(sizeof(struct _WM_Info)); + if (mdi->tmp_info == NULL) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to set info", 0); + WM_Unlock(&mdi->lock); + return NULL; + } + } + mdi->tmp_info->current_sample = mdi->info.current_sample; + mdi->tmp_info->approx_total_samples = mdi->info.approx_total_samples; + mdi->tmp_info->mixer_options = mdi->info.mixer_options; + WM_Unlock(&mdi->lock); + return mdi->tmp_info; +} + +int +WildMidi_Shutdown ( void ) { + struct _hndl * tmp_hdle; + + if (!WM_Initialized) { + WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_NOT_INIT, NULL, 0); + return -1; + } + if (first_handle != NULL) { + while (first_handle != NULL) { + tmp_hdle = first_handle->next; + WildMidi_Close((struct _mdi *)first_handle->handle); + free (first_handle); + first_handle = tmp_hdle; + } + } + WM_FreePatches(); + WM_Initialized = 0; + return 0; +} + -- cgit v1.2.3