Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: ff0b9731d6
Fetching contributors…

Cannot retrieve contributors at this time

2048 lines (1744 sloc) 62.716 kb
// This file is distributed under a BSD license. See LICENSE.txt for details.
#include "_viruz2.hpp"
#pragma lekktor(off)
#if sLINK_VIRUZ2
/****************************************************************************
* synth.h *
****************************************************************************/
extern "C"
{
extern unsigned int __stdcall synthGetSize();
extern void __stdcall synthInit(void *pthis, const void *patchmap, int samplerate=44100);
extern void __stdcall synthRender(void *pthis, void *buf, int smp, void *buf2=0, int add=0);
extern void __stdcall synthProcessMIDI(void *pthis, const void *ptr);
extern void __stdcall synthSetGlobals(void *pthis, const void *ptr);
extern void __stdcall synthGetPoly(void *pthis, void *dest);
extern void __stdcall synthGetPgm(void *pthis, void *dest);
// extern void __stdcall synthGetLD(void *pthis, float *l, float *r);
// only if VUMETER define is set in synth source
// vu output values are floats, 1.0 == 0dB
// you might want to clip or logarithmize the values for yourself
extern void __stdcall synthSetVUMode(void *pthis, int mode); // 0: peak, 1: rms
extern void __stdcall synthGetChannelVU(void *pthis, int ch, float *l, float *r); // ch: 0..15
extern void __stdcall synthGetMainVU(void *pthis, float *l, float *r);
extern long __stdcall synthGetFrameSize(void *pthis);
}
#ifdef RONAN
extern void __stdcall synthSetLyrics(void *pthis, const char **ptr);
#endif
/****************************************************************************
* phonemtab.h *
****************************************************************************/
#ifdef RONAN
// file automatically generated by kram.exe - do not ask
#pragma pack (push, 1)
struct Phoneme
{
sF32 f1f, f1b;
sF32 f2f, f2b;
sF32 f3f, f3b;
sF32 fnf;
sF32 a_voicing, a_aspiration, a_frication, a_bypass;
sF32 a_1, a_2, a_3, a_4, a_n, a_56;
sF32 duration, rank;
};
#pragma pack (pop)
// { 490, 60, 1480, 90, 2500, 150, 270, 0, 0, 0,-16,-16,-16,-16,-16,-16,-16, 0, 5, 31}, // 18: end
// { 280, 60, 1720, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 38, 38, 50,-16,-16, 0, 4, 20}, // 68: zz
// f1f: /10
// f1b: /10
// f2f: /20
// f2b: /10
// f3f: /20
// f3b: /10
// fnf: /10
#define NPHONEMES 69
#define PTABSIZE 1311
static const sU8 multipliers[PTABSIZE/NPHONEMES] = { 10,10,20,10,20,10,10,1,1,1,1,1,1,1,1,1,1,1,1};
// CHANGES: a_f56 + 15 (-> duration -15)
// a_bypass -3 (-> a_f1 +3)
static const sU8 rawphonemes[PTABSIZE] =
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
// f1f (Hz*1/10)
49, 30,241, 0, 15,226,226, 0, 0, 0, 21,235, 9, 0,247, 0, 45,217, 24, 9,238,235, 0, 0, 30,247,247, 18, 30,196, 9,247, 0, 0, 27, 0, 2, 0, 0, 13,244, 0,244, 0, 12, 30,214,238, 0, 0, 30,235, 21, 0,247, 0,235, 21,235, 0, 51,211, 3,247, 0, 6, 3, 0, 0,
// f1b (Hz*1/10)
234, 7,249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,254, 0, 12,246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// f2f (Hz*1/20)
68, 15,247, 21,199,253,253, 0, 0, 51, 12,244,247, 0, 9, 0, 12, 15,214,253, 0, 3, 0, 0, 0, 30, 6,220,226, 45, 12,229, 0, 0, 0,229, 3, 39,208, 3, 30,223, 9, 0,247, 24,241,244, 0, 0, 36,253,244, 0, 27, 24,235, 0, 0, 0,235,232, 27,223, 36, 51,217, 15,241,
// f2b (Hz*1/10)
179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 13,241,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// f3f (Hz*1/20)
116, 0, 0, 0, 0, 0, 0, 0, 0, 9,250, 6,250, 0, 6, 0,247, 35,221, 0, 3, 3, 0, 0,250, 3, 18,235, 0, 9,250, 3, 0, 0,250, 0,241, 21, 9,241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,208, 0, 51,253, 6, 0, 0, 0,247,241, 18,229, 30, 18,235, 0, 0,
// f3b (Hz*1/10)
143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,253, 14,240, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 15,249, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// fnf (Hz*1/10)
12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,247,247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// a_voicing (dB)
35, 0, 0, 0, 0, 0, 0, 0, 0,194, 0, 62,230, 26, 0, 0, 0, 0,194, 62,194, 62, 0, 0,194, 62, 0, 0, 0, 0, 0,194, 0, 0, 62, 0, 0, 0,246, 10, 0, 0, 0, 0, 0, 0, 0,194, 0, 0, 0, 62, 0,244,206, 0, 0, 0, 0, 0, 62, 0, 0, 0,194, 62,234, 22, 0,
// a_aspiration (dB)
194, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,196, 0, 0, 0, 0, 0, 0, 0, 0, 32,224, 0, 0, 60,196, 0, 0, 0, 0, 0, 60, 0, 0,196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0,196, 0, 0, 0, 32, 28, 0, 0, 0, 0,196, 0, 0, 0, 60,196, 20,236, 0,
// a_frication (dB)
0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0,196, 60,196, 0, 0, 0, 0, 0, 0, 54,202, 0, 0, 60,196, 0, 0, 0, 0, 0, 60, 0, 0,196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0,196, 0, 0, 0, 60, 0, 0, 0, 0, 0,196, 0, 0, 0, 60,196, 60,196, 0,
// a_bypass (dB)
237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70,186, 0, 0, 0, 0, 0, 0, 70,186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// a_f1 (dB)
83, 0, 0, 0, 0, 0,230, 0,202, 0, 0, 61,254, 0, 9, 0, 12, 0,176, 80,176, 65, 0, 0, 0, 15, 0, 0, 0,237,254,197, 0, 0, 66, 0,246, 9,241, 30, 0, 0, 0, 0, 0, 0, 0,176, 54, 0,202, 59, 13, 0,184, 0, 0, 0, 0, 0, 80, 0,235, 14,183, 80,235, 0, 0,
// a_f2 (dB)
21,253,254,253, 7,252,181, 79,177, 0, 61,195, 61, 0, 7,246, 14,247,193, 75,211,226, 75,246, 1, 0,255, 15,255,177, 56,200, 80,246,242, 0, 4, 5,251, 17, 3,251,253, 0, 3, 2,251,184, 79,245,188, 70,251, 0,249, 3,195, 56,200, 0, 73,251, 2,244, 12,249,247, 2,254,
// a_f3 (dB)
9, 5,253, 3,247,249,204, 73,183, 0, 72,184, 56, 0, 9,245, 14,254,190, 63,223,226, 70,245,253, 9, 1,253,252,197, 66,190, 80,246,242, 0, 7, 2, 0,243, 11,245, 6, 0,250, 13,249,198, 73,246,193, 66,255, 0,249, 14,184, 58, 10,246, 3,242, 19,241, 19,254,242, 12,244,
// a_f4 (dB)
2, 5,254, 2,247,251,209, 68,188, 0, 61,195, 58, 0, 17,246,252, 0,195, 56,200, 0, 54,246, 8, 7, 2,251,252,204, 56,200, 59,246, 2, 0,205, 50,236, 15, 11,247, 5, 0,251, 11,250,204, 68,246,198, 63,193, 0, 70,247,195, 52, 28,246,240,242, 23,193, 49, 12, 5,246, 10,
// a_fn (dB)
190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0,184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56,200, 0, 66,246, 10,246, 0,246,210, 0, 56,200, 46,210, 66,236, 0,
// a_f56 (dB)
225, 0, 0, 0, 0, 0, 0, 0, 0, 46,246, 0, 10,236,246,240, 0, 0, 0, 0, 46,210, 0, 0, 26,230, 0, 0, 0, 26,246, 10, 0,246,240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46,236, 10,246,230, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0,
// duration (frames)
235, 1, 1, 0, 9,251, 2,245,255, 4, 4, 0,252, 0,253, 0, 3, 3,254, 11,252, 0,245, 1, 3, 1, 0, 0, 0,254,255, 5,249, 3, 4, 0, 0, 0, 0,254, 0, 0,254, 2, 0, 0, 0, 2,249, 1, 4,250, 11,255, 2, 0,250, 9,242, 1, 4, 3,251, 4, 4,251,253, 0, 0,
// rank
254, 0, 0, 0, 0, 0, 24, 3,253,253,251, 8,250, 0, 9,253,232, 0, 29,227, 16, 8, 3,253,239,249, 0, 0, 0, 24,250, 3, 6,250,244, 0, 0, 0, 0,247, 0, 0, 0, 0, 0, 0, 0, 21, 6,250, 6, 1,236, 0, 8, 0, 5,251, 11,250,235, 0, 18,246, 8,248, 10, 0, 0,
};
/*
static Phoneme orgphonemes[] =
{
{ 490, 60, 1480, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 64, 47, 40,-16,-16, 4, 2}, // 0: a
{ 790, 130, 1780, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 61, 52, 45,-16,-16, 5, 2}, // 1: aa
{ 640, 60, 1600, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 59, 49, 43,-16,-16, 6, 2}, // 2: ai
{ 640, 60, 2020, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 56, 52, 45,-16,-16, 6, 2}, // 3: air
{ 790, 60, 880, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 63, 43, 36,-16,-16, 15, 2}, // 4: ar
{ 490, 60, 820, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 59, 36, 31,-16,-16, 10, 2}, // 5: aw
{ 190, 60, 760, 90, 2500, 150, 270, 62, 0, 0,-16, 38,-16,-16,-16,-16,-16, 12, 26}, // 6: b
{ 190, 60, 760, 90, 2500, 150, 270, 62, 0, 0,-16, 38, 63, 57, 52,-16,-16, 1, 29}, // 7: by
{ 190, 60, 760, 90, 2500, 150, 270, 62, 0, 0,-16,-16,-16,-16,-16,-16,-16, 0, 26}, // 8: bz
{ 190, 60, 1780, 90, 2680, 150, 270, 0, 60, 60,-16,-16,-16,-16,-16,-16, 30, 4, 23}, // 9: ch
{ 400, 60, 2020, 90, 2560, 150, 270, 0, 60, 60,-16,-16, 45, 56, 45,-16, 20, 8, 18}, // 10: ci
{ 190, 60, 1780, 90, 2680, 150, 270, 62, 0, 0,-16, 45,-16,-16,-16,-16, 20, 8, 26}, // 11: d
{ 280, 60, 1600, 90, 2560, 150, 270, 36, 0, 60, 54, 43, 45, 40, 42,-16, 30, 4, 20}, // 12: dh
{ 280, 60, 1600, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 45, 40, 42,-16, 10, 4, 20}, // 13: di
{ 190, 60, 1780, 90, 2680, 150, 270, 62, 0, 0,-16, 52, 52, 49, 59,-16, 0, 1, 29}, // 14: dy
{ 190, 60, 1780, 90, 2680, 150, 270, 62, 0, 0,-16, 52, 42, 38, 49,-16,-16, 1, 26}, // 15: dz
{ 640, 60, 2020, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 56, 52, 45,-16,-16, 4, 2}, // 16: e
{ 250, 60, 2320, 90, 3200, 150, 270, 62, 0, 0,-16, 64, 47, 50, 45,-16,-16, 7, 2}, // 17: ee
{ 490, 60, 1480, 90, 2500, 150, 270, 0, 0, 0,-16,-16,-16,-16,-16,-16,-16, 5, 31}, // 18: end
{ 580, 60, 1420, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 59, 47, 40,-16,-16, 16, 2}, // 19: er
{ 400, 60, 1420, 90, 2560, 150, 270, 0, 32, 54, 54,-16, 14, 14,-16,-16, 30, 12, 18}, // 20: f
{ 190, 60, 1480, 90, 2620, 150, 270, 62, 0, 0,-16, 49,-16,-16,-16,-16,-16, 12, 26}, // 21: g
{ 190, 60, 1480, 90, 2620, 150, 270, 62, 0, 0,-16, 49, 59, 54, 38,-16,-16, 1, 29}, // 22: gy
{ 190, 60, 1480, 90, 2620, 150, 270, 62, 0, 0,-16, 49, 49, 43, 28,-16,-16, 2, 26}, // 23: gz
{ 490, 60, 1480, 90, 2500, 150, 270, 0, 60, 60,-16, 49, 50, 40, 36,-16, 10, 5, 9}, // 24: h
{ 400, 60, 2080, 90, 2560, 150, 270, 62, 0, 0,-16, 64, 50, 49, 43,-16,-16, 6, 2}, // 25: i
{ 310, 60, 2200, 90, 2920, 150, 270, 62, 0, 0,-16, 64, 49, 50, 45,-16,-16, 6, 2}, // 26: ia
{ 490, 60, 1480, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 64, 47, 40,-16,-16, 6, 2}, // 27: ib
{ 790, 60, 880, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 63, 43, 36,-16,-16, 6, 2}, // 28: ie
{ 190, 60, 1780, 90, 2680, 150, 270, 62, 0, 0,-16, 45,-16,-16,-16,-16, 10, 4, 26}, // 29: j
{ 280, 60, 2020, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 40, 50, 40,-16, 0, 3, 20}, // 30: jy
{ 190, 60, 1480, 90, 2620, 150, 270, 0, 60, 60,-16,-16,-16,-16,-16,-16, 10, 8, 23}, // 31: k
{ 190, 60, 1480, 90, 2620, 150, 270, 0, 60, 60,-16,-16, 64, 64, 43,-16, 10, 1, 29}, // 32: ky
{ 190, 60, 1480, 90, 2620, 150, 270, 0, 60, 60,-16,-16, 54, 54, 33,-16, 0, 4, 23}, // 33: kz
{ 460, 60, 1480, 90, 2500, 150, 270, 62, 0, 0,-16, 50, 40, 40, 35,-16,-16, 8, 11}, // 34: l
{ 460, 60, 940, 90, 2500, 150, 270, 62, 0, 0,-16, 50, 40, 40, 35,-16,-16, 8, 11}, // 35: ll
{ 480, 40, 1000, 170, 2200, 120, 360, 62, 0, 0,-16, 40, 44, 47,-16, 56,-16, 8, 11}, // 36: m
{ 480, 40, 1780, 300, 2620, 260, 450, 62, 0, 0,-16, 49, 49, 49, 34, 56,-16, 8, 11}, // 37: n
{ 480, 160, 820, 150, 2800, 100, 360, 52, 0, 0,-16, 34, 44, 49, 14, 56,-16, 8, 11}, // 38: ng
{ 610, 60, 880, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 61, 36, 29,-16,-16, 6, 2}, // 39: o
{ 490, 60, 1480, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 64, 47, 40,-16,-16, 6, 2}, // 40: oa
{ 490, 60, 820, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 59, 36, 31,-16,-16, 6, 2}, // 41: oi
{ 370, 60, 1000, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 56, 42, 36,-16,-16, 4, 2}, // 42: oo
{ 370, 60, 1000, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 56, 42, 36,-16,-16, 6, 2}, // 43: oor
{ 490, 60, 820, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 59, 36, 31,-16,-16, 6, 2}, // 44: or
{ 790, 60, 1300, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 61, 49, 42,-16,-16, 6, 2}, // 45: ou
{ 370, 60, 1000, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 56, 42, 36,-16,-16, 6, 2}, // 46: ov
{ 190, 60, 760, 90, 2500, 150, 270, 0, 60, 60,-16,-16,-16,-16,-16,-16,-16, 8, 23}, // 47: p
{ 190, 60, 760, 90, 2500, 150, 270, 0, 60, 60,-16, 38, 63, 57, 52,-16,-16, 1, 29}, // 48: py
{ 190, 60, 760, 90, 2500, 150, 270, 0, 60, 60,-16, 38, 52, 47, 42,-16,-16, 2, 23}, // 49: pz
{ 490, 60, 1480, 90, 2500, 150, 270, 0, 0, 0,-16,-16,-16,-16,-16,-16,-16, 6, 29}, // 50: q
{ 280, 60, 1420, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 54, 50, 47, 40,-16, 0, 30}, // 51: qq
{ 490, 60, 1180, 90, 1600, 150, 270, 62, 0, 0,-16, 56, 49, 49,-16,-16,-16, 11, 10}, // 52: r
{ 490, 60, 1180, 90, 1600, 70, 270, 50, 0, 0,-16, 56, 49, 49,-16,-16,-16, 10, 10}, // 53: rx
{ 400, 200, 1720, 90, 2620, 220, 270, 0, 32, 60,-16,-16, 42, 42, 54, 50, 30, 12, 18}, // 54: s
{ 400, 60, 2200, 90, 2560, 150, 270, 0, 60, 60,-16,-16, 45, 56, 45, 40, 10, 12, 18}, // 55: sh
{ 190, 60, 1780, 90, 2680, 150, 270, 0, 60, 60,-16,-16,-16,-16,-16, 50, 20, 6, 23}, // 56: t
{ 400, 60, 1780, 90, 2680, 150, 270, 0, 60, 60,-16,-16, 40, 42, 36, 40, 10, 15, 18}, // 57: th
{ 190, 60, 1780, 90, 2680, 150, 270, 0, 60, 60,-16,-16,-16, 52, 64, 40,-16, 1, 29}, // 58: ty
{ 190, 60, 1780, 90, 2680, 150, 270, 0, 60, 60,-16,-16,-16, 42, 54, 30,-16, 2, 23}, // 59: tz
{ 700, 60, 1360, 90, 2500, 150, 270, 62, 0, 0,-16, 64, 57, 45, 38,-16,-16, 6, 2}, // 60: u
{ 250, 60, 880, 90, 2200, 150, 270, 62, 0, 0,-16, 64, 52, 31, 24,-16,-16, 9, 2}, // 61: uu
{ 280, 60, 1420, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 54, 50, 47, 40,-16, 4, 20}, // 62: v
{ 190, 60, 760, 90, 2020, 150, 270, 62, 0, 0,-16, 57, 42, 35,-16,-16,-16, 8, 10}, // 63: w
{ 190, 60, 1480, 90, 2620, 150, 270, 0, 60, 60,-16,-16, 54, 54, 33, 30,-16, 12, 18}, // 64: x
{ 250, 60, 2500, 90, 2980, 150, 270, 62, 0, 0,-16, 64, 47, 52, 45,-16,-16, 7, 10}, // 65: y
{ 280, 60, 1720, 90, 2560, 150, 270, 40, 20, 60,-16, 43, 38, 38, 50, 50,-16, 4, 20}, // 66: z
{ 280, 60, 2020, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 40, 50, 40, 30, 10, 4, 20}, // 67: zh
{ 280, 60, 1720, 90, 2560, 150, 270, 62, 0, 0,-16, 43, 38, 38, 50, 30, 10, 4, 20}, // 68: zz
};
*/
/****************************************************************************
* ronan.cpp *
****************************************************************************/
// ronan heißt in wirklichkeit lisa. ich war nur zu faul zum renamen.
// !DHAX_ !kwIH_k !br4AH_UHn !fAA_ks !jAH_mps !OW!vE_R !DHAX_ !lEY!zIY_ !dAA_g
namespace Ronan
{
int mystrnicmp1(const char *a, const char *b)
{
sInt l=0;
while (*a && *b)
if ((*a++ | 0x20)!=(*b++ | 0x20))
return 0;
else
l++;
return *a?0:l;
}
#define PI (4.0f*(sF32)atan(1.0f))
#include "phonemtab.h"
static Phoneme phonemes[NPHONEMES];
static struct
{
sU32 samplerate;
sF32 fcminuspi_sr;
sF32 fc2pi_sr;
} g;
static const char *nix="";
static const struct syldef
{
char syl[4];
sS8 ptab[4];
} syls[] = {
{"sil",{50,-1,-1,-1}},
{"ng",{38,-1,-1,-1}},
{"th",{57,-1,-1,-1}},
{"sh",{55,-1,-1,-1}},
{"dh",{12,51,13,-1}},
{"zh",{67,51,67,-1}},
{"ch",{ 9,10,-1,-1}},
{"ih",{25,-1,-1,-1}},
{"eh",{16,-1,-1,-1}},
{"ae",{ 1,-1,-1,-1}},
{"ah",{60,-1,-1,-1}},
{"oh",{39,-1,-1,-1}},
{"uh",{42,-1,-1,-1}},
{"ax",{ 0,-1,-1,-1}},
{"iy",{17,-1,-1,-1}},
{"er",{19,-1,-1,-1}},
{"aa",{ 4,-1,-1,-1}},
{"ao",{ 5,-1,-1,-1}},
{"uw",{61,-1,-1,-1}},
{"ey",{ 2,25,-1,-1}},
{"ay",{28,25,-1,-1}},
{"oy",{41,25,-1,-1}},
{"aw",{45,46,-1,-1}},
{"ow",{40,46,-1,-1}},
{"ia",{26,27,-1,-1}},
{"ea",{ 3,27,-1,-1}},
{"ua",{43,27,-1,-1}},
{"ll",{35,-1,-1,-1}},
{"wh",{63,-1,-1,-1}},
{"ix",{ 0,-1,-1,-1}},
{"el",{34,-1,-1,-1}},
{"rx",{53,-1,-1,-1}},
{"h",{24,-1,-1,-1}},
{"p",{47,48,49,-1}},
{"t",{56,58,59,-1}},
{"k",{31,32,33,-1}},
{"b",{ 6, 7, 8,-1}},
{"d",{11,14,15,-1}},
{"g",{21,22,23,-1}},
{"m",{36,-1,-1,-1}},
{"n",{37,-1,-1,-1}},
{"f",{20,-1,-1,-1}},
{"s",{54,-1,-1,-1}},
{"v",{62,51,62,-1}},
{"z",{66,51,68,-1}},
{"l",{34,-1,-1,-1}},
{"r",{52,-1,-1,-1}},
{"w",{63,-1,-1,-1}},
{"q",{51,-1,-1,-1}},
{"y",{65,-1,-1,-1}},
{"j",{29,30,51,30}},
{" ",{18,-1,-1,-1}},
};
#define NSYLS (sizeof(syls)/sizeof(syldef))
// filter type 1: 2-pole resonator
struct ResDef
{
sF32 a,b,c; // coefficients
void set(sF32 f, sF32 bw, sF32 gain)
{
sF32 r=(sF32)sFExp(g.fcminuspi_sr*bw);
c=-(r*r);
b=r*(sF32)cos(g.fc2pi_sr*f)*2.0f;
a=gain*(1.0f-b-c);
}
};
struct Resonator
{
ResDef *def;
sF32 p1, p2; // delay buffers
inline void setdef(ResDef &a_def) { def=&a_def; }
sF32 tick(sF32 in)
{
sF32 x=def->a*in+def->b*p1+def->c*p2;
p2=p1;
p1=x;
return x;
}
};
static ResDef d_peq1;
static sF32 flerp(const sF32 a,const sF32 b,const sF32 x) { return a+x*(b-a); }
static sF32 db2lin(sF32 db1, sF32 db2, sF32 x) { return (sF32)sFPow(2.0,(flerp(db1,db2,x)-70)/6.0); }
static const sF32 f4=3200;
static const sF32 f5=4000;
static const sF32 f6=6000;
static const sF32 bn=100;
static const sF32 b4=200;
static const sF32 b5=500;
static const sF32 b6=800;
struct syVRonan
{
ResDef rdef[7]; // nas,f1,f2,f3,f4,f5,f6;
sF32 a_voicing;
sF32 a_aspiration;
sF32 a_frication;
sF32 a_bypass;
};
struct syWRonan : syVRonan
{
syVRonan newframe;
Resonator res[7]; // 0:nas, 1..6: 1..6
sF32 lastin2;
// settings
const char *texts[64];
sF32 pitch;
sInt framerate;
// noise
sU32 nseed;
sF32 nout;
// phonem seq
sInt framecount; // frame rate divider
sInt spos; // pos within syl definition (0..3)
sInt scounter; // syl duration divider
sInt cursyl; // current syl
sInt durfactor; // duration modifier
sF32 invdur; // 1.0 / current duration
const char *baseptr; // pointer to start of text
const char *ptr; // pointer to text
sInt curp1, curp2; // current/last phonemes
// sync
sInt wait4on;
sInt wait4off;
// post EQ
sF32 hpb1, hpb2;
Resonator peq1;
void SetFrame(const Phoneme &p1s, const Phoneme &p2s, const sF32 x, syVRonan &dest)
{
static Phoneme p1,p2;
static const sF32 * const p1f[]={&p1.fnf,&p1.f1f,&p1.f2f,&p1.f3f,&f4 ,&f5 ,&f6};
static const sF32 * const p1b[]={&bn ,&p1.f1b,&p1.f2b,&p1.f3b,&b4 ,&b5 ,&b6};
static const sF32 * const p1a[]={&p1.a_n,&p1.a_1,&p1.a_2,&p1.a_3,&p1.a_4,&p1.a_56,&p1.a_56};
static const sF32 * const p2f[]={&p2.fnf,&p2.f1f,&p2.f2f,&p2.f3f,&f4 ,&f5 ,&f6};
static const sF32 * const p2b[]={&bn ,&p2.f1b,&p2.f2b,&p2.f3b,&b4 ,&b5 ,&b6};
static const sF32 * const p2a[]={&p2.a_n,&p2.a_1,&p2.a_2,&p2.a_3,&p2.a_4,&p2.a_56,&p2.a_56};
p1=p1s;
p2=p2s;
for (sInt i=0; i<7; i++)
dest.rdef[i].set(flerp(*p1f[i],*p2f[i],x)*pitch,flerp(*p1b[i],*p2b[i],x),db2lin(*p1a[i],*p2a[i],x));
dest.a_voicing=db2lin(p1.a_voicing,p2.a_voicing,x);
dest.a_aspiration=db2lin(p1.a_aspiration,p2.a_aspiration,x);
dest.a_frication=db2lin(p1.a_frication,p2.a_frication,x);
dest.a_bypass=db2lin(p1.a_bypass,p2.a_bypass,x);
}
#define NOISEGAIN 0.25f
sF32 noise()
{
union { sU32 i; sF32 f; } val;
// random...
nseed=(nseed*196314165)+907633515;
// convert to float between 2.0 and 4.0
val.i=(nseed>>9)|0x40000000;
// slight low pass filter...
nout=(val.f-3.0f)+0.75f*nout;
return nout*NOISEGAIN;
}
void reset()
{
for (sInt i=0; i<7; i++) res[i].setdef(rdef[i]);
peq1.setdef(d_peq1);
SetFrame(phonemes[18],phonemes[18],0,*this); // off
SetFrame(phonemes[18],phonemes[18],0,newframe); // off
curp1=curp2=18;
spos=4;
}
};
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
};
using namespace Ronan;
extern "C" void __stdcall ronanCBSetSR(syWRonan *ptr,sU32 sr)
{
g.samplerate=sr;
g.fc2pi_sr=2.0f*PI/(sF32)sr;
g.fcminuspi_sr=-g.fc2pi_sr*0.5f;
}
extern "C" void __stdcall ronanCBInit(syWRonan *wsptr)
{
// convert phoneme table to a usable format
register const sS8 *ptr=(const sS8*)rawphonemes;
register sS32 val=0;
for (sInt f=0; f<(PTABSIZE/NPHONEMES); f++)
{
sF32 *dest=((sF32*)phonemes)+f;
for (sInt p=0; p<NPHONEMES; p++)
{
*dest=multipliers[f]*(sF32)(val+=*ptr++);
dest+=PTABSIZE/NPHONEMES;
}
}
wsptr->reset();
wsptr->framerate=3;
wsptr->pitch=1.0f;
if (!wsptr->texts[0])
wsptr->baseptr=wsptr->ptr=nix;
else
wsptr->baseptr=wsptr->ptr=wsptr->texts[0];
/*wsptr->lastin=*/wsptr->lastin2=/*wsptr->nval=*/0;
d_peq1.set(12000,4000,2.0f);
}
extern "C" void __stdcall ronanCBTick(syWRonan *wsptr)
{
if (wsptr->wait4off || wsptr->wait4on) return;
if (wsptr->framecount<=0)
{
wsptr->framecount=wsptr->framerate;
// let current phoneme expire
if (wsptr->scounter<=0)
{
// set to next phoneme
wsptr->spos++;
if (wsptr->spos >=4 || syls[wsptr->cursyl].ptab[wsptr->spos]==-1)
{
// go to next syllable
if (!(*wsptr->ptr)) // empty text: silence!
{
wsptr->durfactor=1;
wsptr->framecount=1;
wsptr->cursyl=NSYLS-1;
wsptr->spos=0;
wsptr->ptr=wsptr->baseptr;
}
else if (*wsptr->ptr=='!') // wait for noteon
{
wsptr->framecount=0;
wsptr->scounter=0;
wsptr->wait4on=1;
wsptr->ptr++;
return;
}
else if (*wsptr->ptr=='_') // noteoff
{
wsptr->framecount=0;
wsptr->scounter=0;
wsptr->wait4off=1;
wsptr->ptr++;
return;
}
if (*wsptr->ptr && *wsptr->ptr!='!' && *wsptr->ptr!='_')
{
wsptr->durfactor=0;
while (*wsptr->ptr>='0' && *wsptr->ptr<='9') wsptr->durfactor=10*wsptr->durfactor+(*wsptr->ptr++ - '0');
if (!wsptr->durfactor) wsptr->durfactor=1;
// printf2("'%s' -> ",wsptr->ptr);
sInt fs,len=1,len2;
for (fs=0; fs<NSYLS-1; fs++)
{
const syldef &s=syls[fs];
if (len2=mystrnicmp1(s.syl,wsptr->ptr))
{
len=len2;
// printf2("got %s\n",s.syl);
break;
}
}
wsptr->cursyl=fs;
wsptr->spos=0;
wsptr->ptr+=len;
}
}
wsptr->curp1=wsptr->curp2;
wsptr->curp2=syls[wsptr->cursyl].ptab[wsptr->spos];
wsptr->scounter=sFtol(phonemes[wsptr->curp2].duration*wsptr->durfactor);
if (!wsptr->scounter) wsptr->scounter=1;
wsptr->invdur=1.0f/((sF32)wsptr->scounter*wsptr->framerate);
}
wsptr->scounter--;
}
wsptr->framecount--;
sF32 x=(sF32)(wsptr->scounter*wsptr->framerate+wsptr->framecount)*wsptr->invdur;
const Phoneme &p1=phonemes[wsptr->curp1];
const Phoneme &p2=phonemes[wsptr->curp2];
x=(sF32)sFPow(x,(sF32)p1.rank/(sF32)p2.rank);
wsptr->SetFrame(p2,(fabs(p2.rank-p1.rank)>8.0f)?p2:p1,x,wsptr->newframe);
}
extern "C" void __stdcall ronanCBNoteOn(syWRonan *wsptr)
{
wsptr->wait4on=0;
}
extern "C" void __stdcall ronanCBNoteOff(syWRonan *wsptr)
{
wsptr->wait4off=0;
}
extern "C" void __stdcall ronanCBSetCtl(syWRonan *wsptr,sU32 ctl, sU32 val)
{
// controller 4, 0-63 : set text #
// controller 4, 64-127 : set frame rate
// controller 5 : set pitch
switch (ctl)
{
case 4:
if (val<63)
{
wsptr->reset();
if (wsptr->texts[val])
wsptr->ptr=wsptr->baseptr=wsptr->texts[val];
else
wsptr->ptr=wsptr->baseptr=nix;
}
else
wsptr->framerate=val-63;
break;
case 5:
wsptr->pitch=(sF32)sFPow(2.0f,(val-64.0f)/128.0f);
break;
}
}
extern "C" void __stdcall ronanCBProcess(syWRonan *wsptr,sF32 *buf, sU32 len)
{
static syVRonan deltaframe;
// prepare interpolation
{
sF32 *src1=(sF32*)wsptr;
sF32 *src2=(sF32*)&wsptr->newframe;
sF32 *dest=(sF32*)&deltaframe;
sF32 mul =1.0f/(sF32)len;
for (sU32 i=0; i<(sizeof(syVRonan)/sizeof(sF32)); i++)
dest[i]=(src2[i]-src1[i])*mul;
}
for (sU32 i=0; i<len; i++)
{
// interpolate all values
{
sF32 *src=(sF32*)&deltaframe;
sF32 *dest=(sF32*)wsptr;
for (sU32 i=0; i<(sizeof(syVRonan)/sizeof(sF32)); i++)
dest[i]+=src[i];
}
sF32 in=buf[2*i];
// add aspiration noise
in=in*wsptr->a_voicing+wsptr->noise()*wsptr->a_aspiration;
// process complete input signal with f1/nasal filters
sF32 out=wsptr->res[0].tick(in)+wsptr->res[1].tick(in);
// differentiate input signal, add frication noise
sF32 lin=in;
in=(wsptr->noise()*wsptr->a_frication)+in-wsptr->lastin2;
wsptr->lastin2=lin;
// process diff/fric input signal with f2..f6 and bypass (phase inverted)
for (sInt r=2; r<7; r++)
out=wsptr->res[r].tick(in)-out;
out=in*wsptr->a_bypass-out;
// high pass filter
wsptr->hpb1+=0.012f*(out=out-wsptr->hpb1);
wsptr->hpb2+=0.012f*(out=out-wsptr->hpb2);
// EQ
out=wsptr->peq1.tick(out)-out;
buf[2*i]=buf[2*i+1]=out;
}
}
extern "C" extern void* __stdcall synthGetSpeechMem(void *a_pthis);
void __stdcall synthSetLyrics(void *a_pthis,const char **a_ptr)
{
syWRonan *wsptr=(syWRonan*)synthGetSpeechMem(a_pthis);
for (sInt i=0; i<64; i++) wsptr->texts[i]=a_ptr[i];
wsptr->baseptr=wsptr->ptr=wsptr->texts[0];
}
#endif // #ifdef RONAN
/****************************************************************************
* v2mplayer.cpp *
****************************************************************************/
#define GETDELTA(p, w) ((p)[0]+((p)[w]<<8)+((p)[2*w]<<16))
#define UPDATENT(n, v, p, w) if ((n)<(w)) { (v)=m_state.time+GETDELTA((p), (w)); if ((v)<m_state.nexttime) m_state.nexttime=(v); }
#define UPDATENT2(n, v, p, w) if ((n)<(w) && GETDELTA((p), (w))) { (v)=m_state.time+GETDELTA((p), (w)); }
#define UPDATENT3(n, v, p, w) if ((n)<(w) && (v)<m_state.nexttime) m_state.nexttime=(v);
#define PUTSTAT(s) { sU8 bla=(s); if (laststat!=bla) { laststat=bla; *mptr++=(sU8)laststat; }};
namespace
{
void UpdateSampleDelta(sU32 nexttime, sU32 time, sU32 usecs, sU32 td2, sU32 *smplrem, sU32 *smpldelta)
//////////////////////////////////////////////////////////////////////////////////////////////////////
{
// performs 64bit (nexttime-time)*usecs/td2 and a 32.32bit addition to smpldelta:smplrem
__asm {
mov eax, [nexttime]
sub eax, [time]
mov ebx, [usecs]
mul ebx
mov ebx, [td2]
div ebx
mov ecx, [smplrem]
add [ecx], edx
adc eax, 0
mov ecx, [smpldelta]
mov [ecx], eax
}
}
}
sBool CV2MPlayer::InitBase(const void *a_v2m)
///////////////////////////////////////
{
const sU8 *d=(const sU8*)a_v2m;
m_base.timediv=(*((sU32*)(d)));
m_base.timediv2=10000*m_base.timediv;
m_base.maxtime=*((sU32*)(d+4));
m_base.gdnum=*((sU32*)(d+8));
d+=12;
m_base.gptr=d;
d+=10*m_base.gdnum;
for (sInt ch=0; ch<16; ch++)
{
V2MBase::Channel &c=m_base.chan[ch];
c.notenum=*((sU32*)d);
d+=4;
if (c.notenum)
{
c.noteptr=d;
d+=5*c.notenum;
c.pcnum=*((sU32*)d);
d+=4;
c.pcptr=d;
d+=4*c.pcnum;
c.pbnum=*((sU32*)d);
d+=4;
c.pbptr=d;
d+=5*c.pbnum;
for (sInt cn=0; cn<7; cn++)
{
V2MBase::Channel::CC &cc=c.ctl[cn];
cc.ccnum=*((sU32*)d);
d+=4;
cc.ccptr=d;
d+=4*cc.ccnum;
}
}
}
sInt size=*((sU32*)d);
if (size>16384 || size<0) return sFALSE;
d+=4;
m_base.globals=d;
d+=size;
size=*((sU32*)d);
if (size>1048576 || size<0) return sFALSE;
d+=4;
m_base.patchmap=d;
d+=size;
#ifdef RONAN
sU32 spsize=*((sU32*)d);
d+=4;
if (!spsize || spsize>=8192)
{
for (sU32 i=0; i<256; i++)
m_base.speechptrs[i]=" ";
}
else
{
m_base.speechdata=(const char *)d;
d+=spsize;
const sU32 *p32=(const sU32*)m_base.speechdata;
sU32 n=*(p32++);
for (sU32 i=0; i<n; i++)
{
m_base.speechptrs[i]=m_base.speechdata+*(p32++);
}
}
#endif
return sTRUE;
}
void CV2MPlayer::Reset()
////////////////////////
{
m_state.time=0;
m_state.nexttime=(sU32)-1;
m_state.gptr=m_base.gptr;
m_state.gnr=0;
UPDATENT(m_state.gnr, m_state.gnt, m_state.gptr, m_base.gdnum);
for (sInt ch=0; ch<16; ch++)
{
V2MBase::Channel &bc=m_base.chan[ch];
PlayerState::Channel &sc=m_state.chan[ch];
if (!bc.notenum) continue;
sc.noteptr=bc.noteptr;
sc.notenr=sc.lastnte=sc.lastvel=0;
UPDATENT(sc.notenr,sc.notent, sc.noteptr, bc.notenum);
sc.pcptr=bc.pcptr;
sc.pcnr=sc.lastpc=0;
UPDATENT(sc.pcnr,sc.pcnt, sc.pcptr, bc.pcnum);
sc.pbptr=bc.pbptr;
sc.pbnr=sc.lastpb0=sc.lastpb1=0;
UPDATENT(sc.pbnr,sc.pbnt, sc.pbptr, bc.pcnum);
for (sInt cn=0; cn<7; cn++)
{
V2MBase::Channel::CC &bcc=bc.ctl[cn];
PlayerState::Channel::CC &scc=sc.ctl[cn];
scc.ccptr=bcc.ccptr;
scc.ccnr=scc.lastcc=0;
UPDATENT(scc.ccnr,scc.ccnt,scc.ccptr,bcc.ccnum);
}
}
m_state.usecs=5000*m_samplerate;
m_state.num=4;
m_state.den=4;
m_state.tpq=8;
m_state.bar=0;
m_state.beat=0;
m_state.tick=0;
m_state.smplrem=0;
if (m_samplerate)
{
synthInit(m_synth,(void*)m_base.patchmap,m_samplerate);
synthSetGlobals(m_synth,(void*)m_base.globals);
#ifdef RONAN
synthSetLyrics(m_synth,m_base.speechptrs);
#endif
}
}
void CV2MPlayer::Tick()
///////////////////////
{
if (m_state.state != PlayerState::PLAYING)
return;
m_state.tick+=m_state.nexttime-m_state.time;
while (m_state.tick>=m_base.timediv)
{
m_state.tick-=m_base.timediv;
m_state.beat++;
}
sU32 qpb=(m_state.num*4/m_state.den);
while (m_state.beat>=qpb)
{
m_state.beat-=qpb;
m_state.bar++;
}
m_state.time=m_state.nexttime;
m_state.nexttime=(sU32)-1;
sU8 *mptr=m_midibuf;
sU32 laststat=-1;
if (m_state.gnr<m_base.gdnum && m_state.time==m_state.gnt) // neues global-event?
{
m_state.usecs=(*(sU32 *)(m_state.gptr+3*m_base.gdnum+4*m_state.gnr))*(m_samplerate/100);
m_state.num=m_state.gptr[7*m_base.gdnum+m_state.gnr];
m_state.den=m_state.gptr[8*m_base.gdnum+m_state.gnr];
m_state.tpq=m_state.gptr[9*m_base.gdnum+m_state.gnr];
m_state.gnr++;
UPDATENT2(m_state.gnr, m_state.gnt, m_state.gptr+m_state.gnr, m_base.gdnum);
}
UPDATENT3(m_state.gnr, m_state.gnt, m_state.gptr+m_state.gnr, m_base.gdnum);
for (sInt ch=0; ch<16; ch++)
{
V2MBase::Channel &bc=m_base.chan[ch];
PlayerState::Channel &sc=m_state.chan[ch];
if (!bc.notenum)
continue;
// 1. process pgm change events
if (sc.pcnr<bc.pcnum && m_state.time==sc.pcnt)
{
PUTSTAT(0xc0|ch)
*mptr++=(sc.lastpc+=sc.pcptr[3*bc.pcnum]);
sc.pcnr++;
sc.pcptr++;
UPDATENT2(sc.pcnr,sc.pcnt,sc.pcptr,bc.pcnum);
}
UPDATENT3(sc.pcnr,sc.pcnt,sc.pcptr,bc.pcnum);
// 2. process control changes
for (sInt cn=0; cn<7; cn++)
{
V2MBase::Channel::CC &bcc=bc.ctl[cn];
PlayerState::Channel::CC &scc=sc.ctl[cn];
if (scc.ccnr<bcc.ccnum && m_state.time==scc.ccnt)
{
PUTSTAT(0xb0|ch)
*mptr++=cn+1;
*mptr++=(scc.lastcc+=scc.ccptr[3*bcc.ccnum]);
scc.ccnr++;
scc.ccptr++;
UPDATENT2(scc.ccnr,scc.ccnt,scc.ccptr,bcc.ccnum);
}
UPDATENT3(scc.ccnr,scc.ccnt,scc.ccptr,bcc.ccnum);
}
// 3. process pitch bends
if (sc.pbnr<bc.pbnum && m_state.time==sc.pbnt)
{
PUTSTAT(0xe0|ch)
*mptr++=(sc.lastpb0+=sc.pbptr[3*bc.pcnum]);
*mptr++=(sc.lastpb1+=sc.pbptr[4*bc.pcnum]);
sc.pbnr++;
sc.pbptr++;
UPDATENT2(sc.pbnr,sc.pbnt,sc.pbptr,bc.pbnum);
}
UPDATENT3(sc.pbnr,sc.pbnt,sc.pbptr,bc.pbnum);
// 4. process notes
while (sc.notenr<bc.notenum && m_state.time==sc.notent)
{
PUTSTAT(0x90|ch)
*mptr++=(sc.lastnte+=sc.noteptr[3*bc.notenum]);
*mptr++=(sc.lastvel+=sc.noteptr[4*bc.notenum]);
sc.notenr++;
sc.noteptr++;
UPDATENT2(sc.notenr,sc.notent,sc.noteptr,bc.notenum);
}
UPDATENT3(sc.notenr,sc.notent,sc.noteptr,bc.notenum);
}
*mptr++=0xfd;
synthProcessMIDI(m_synth,m_midibuf);
if (m_state.nexttime==(sU32)-1) m_state.state=PlayerState::STOPPED;
}
sBool CV2MPlayer::Open(const void *a_v2mptr, sU32 a_samplerate)
///////////////////////////////////////////////////////////////
{
if (m_base.valid) Close();
m_samplerate=a_samplerate;
if (!InitBase(a_v2mptr)) return sFALSE;
Reset();
return m_base.valid=sTRUE;
}
void CV2MPlayer::Close()
////////////////////////
{
if (!m_base.valid) return;
if (m_state.state!=PlayerState::OFF) Stop();
m_base.valid=0;
}
void CV2MPlayer::Play(sU32 a_time)
//////////////////////////////////
{
if (!m_base.valid || !m_samplerate) return;
Stop();
Reset();
m_base.valid=sFALSE;
sU32 destsmpl, cursmpl=0;
destsmpl = sMulDiv(a_time,m_samplerate,m_tpc);
m_state.state=PlayerState::PLAYING;
m_state.smpldelta=0;
m_state.smplrem=0;
while ((cursmpl+m_state.smpldelta)<destsmpl && m_state.state==PlayerState::PLAYING)
{
cursmpl+=m_state.smpldelta;
Tick();
if (m_state.state==PlayerState::PLAYING)
{
UpdateSampleDelta(m_state.nexttime,m_state.time,m_state.usecs,m_base.timediv2,&m_state.smplrem,&m_state.smpldelta);
}
else
m_state.smpldelta=-1;
}
m_state.smpldelta-=(destsmpl-cursmpl);
m_timeoffset=cursmpl-m_state.cursmpl;
m_fadeval=1.0f;
m_fadedelta=0.0f;
m_base.valid=sTRUE;
}
void CV2MPlayer::Stop(sU32 a_fadetime)
//////////////////////////////////////
{
if (!m_base.valid) return;
if (a_fadetime)
{
sU32 ftsmpls;
__asm
{
mov ecx, this
mov eax, [a_fadetime]
mov ebx, [ecx + m_samplerate]
imul ebx
mov ebx, [ecx + m_tpc]
idiv ebx
mov [ftsmpls], eax
}
m_fadedelta=m_fadeval/ftsmpls;
}
else
m_state.state=PlayerState::OFF;
}
sBool CV2MPlayer::Render(sF32 *a_buffer, sU32 a_len, sBool a_add)
/////////////////////////////////////////////////////////////////
{
if (!a_buffer) return sFALSE;
if (m_base.valid && m_state.state==PlayerState::PLAYING)
{
sU32 todo=a_len;
while (todo)
{
sInt torender=(todo>m_state.smpldelta)?m_state.smpldelta:todo;
if (torender)
{
synthRender(m_synth,a_buffer,torender,0,a_add);
a_buffer+=2*torender;
todo-=torender;
m_state.smpldelta-=torender;
m_state.cursmpl+=torender;
}
if (!m_state.smpldelta)
{
Tick();
if (m_state.state==PlayerState::PLAYING)
UpdateSampleDelta(m_state.nexttime,m_state.time,m_state.usecs,m_base.timediv2,&m_state.smplrem,&m_state.smpldelta);
else
m_state.smpldelta=-1;
}
}
}
else if (m_state.state==PlayerState::OFF || !m_base.valid)
{
if (!a_add)
{
__asm {
mov edi, [a_buffer]
mov ecx, [a_len]
shl ecx, 1
xor eax, eax
rep stosd
}
}
}
else
{
synthRender(m_synth,a_buffer,a_len,0,a_add);
m_state.cursmpl+=a_len;
}
if (m_fadedelta)
{
for (sU32 i=0; i<a_len; i++)
{
a_buffer[2*i]*=m_fadeval;
a_buffer[2*i+1]*=m_fadeval;
m_fadeval-=m_fadedelta; if (m_fadeval<0) m_fadeval=0;
}
if (!m_fadeval) Stop();
}
return m_base.valid && m_state.state==PlayerState::PLAYING;
}
sU32 CV2MPlayer::GetTime()
//////////////////////////
{
if (!m_base.valid) return 0;
return 0;
}
#ifdef V2MPLAYER_SYNC_FUNCTIONS
sU32 CV2MPlayer::CalcPositions(sS32 **a_dest)
/////////////////////////////////////////////
{
if (!a_dest) return 0;
if (!m_base.valid)
{
*a_dest=0;
return 0;
}
// step 1: ende finden
sS32 *&dp=*a_dest;
sU32 gnr=0;
const sU8* gp=m_base.gptr;
sU32 curbar=0;
sU32 cur32th=0;
sU32 lastevtime=0;
sU32 pb32=32;
sU32 usecs=500000;
sU32 posnum=0;
sU32 ttime, td, this32;
sF64 curtimer=0;
while (gnr<m_base.gdnum)
{
ttime=lastevtime+(gp[2*m_base.gdnum]<<16)+(gp[m_base.gdnum]<<8)+gp[0];
td=ttime-lastevtime;
this32=(td*8/m_base.timediv);
posnum+=this32;
lastevtime=ttime;
pb32=gp[7*m_base.gdnum]*32/gp[8*m_base.gdnum];
gnr++;
gp++;
}
td=m_base.maxtime-lastevtime;
this32=(td*8/m_base.timediv);
posnum+=this32+1;
dp=new sS32[2*posnum];
gnr=0;
gp=m_base.gptr;
lastevtime=0;
pb32=32;
sU32 pn;
for (pn=0; pn<posnum; pn++)
{
sU32 curtime=pn*m_base.timediv/8;
if (gnr<m_base.gdnum)
{
ttime=lastevtime+(gp[2*m_base.gdnum+gnr]<<16)+(gp[m_base.gdnum+gnr]<<8)+gp[gnr];
if (curtime>=ttime)
{
pb32=gp[7*m_base.gdnum+gnr]*32/gp[8*m_base.gdnum+gnr];
usecs=*(sU32 *)(gp+3*m_base.gdnum+4*gnr);
gnr++;
lastevtime=ttime;
}
}
dp[2*pn]=(sU32)curtimer;
dp[2*pn+1]=(curbar<<16)|(cur32th<<8)|(pb32);
cur32th++;
if (cur32th==pb32)
{
cur32th=0;
curbar++;
}
curtimer+=m_tpc*usecs/8000000.0;
}
return pn;
}
#endif
/****************************************************************************/
/****************************************************************************/
#endif
/****************************************************************************
* sounddef.h *
****************************************************************************/
// no problem if this header is included multiple times
// in case you get any linker collisions, prepend
// __declspec(selectany) to the problematic declaration
#if !sPLAYER
enum V2CTLTYPES { VCTL_SKIP, VCTL_SLIDER, VCTL_MB, };
typedef struct {
int no;
char *name;
char *name2;
} V2TOPIC;
typedef struct {
int version;
char *name;
V2CTLTYPES ctltype;
int offset, min, max;
int isdest;
char *ctlstr;
} V2PARAM;
////////////////////////////////////////////
//
// V2 Patch Topics
//
////////////////////////////////////////////
const V2TOPIC v2topics[] = {
{ 2, "Voice","Vo" },
{ 6, "Osc 1","O1" },
{ 6, "Osc 2","O2" },
{ 6, "Osc 3","O3" },
{ 3, "VCF 1","F1" },
{ 3, "VCF 2","F2" },
{ 2, "Filters","Fi" },
{ 4, "Voice Dist","VD" },
{ 6, "Amp EG","E1" },
{ 6, "EG 2","E2" },
{ 7, "LFO 1","L1" },
{ 7, "LFO 2","L2" },
{ 10, "Global","Gl" },
{ 4, "Channel Dist","CD" },
{ 7, "Chorus/Flanger","CF" },
{ 9, "Compressor","CC" },
{ 1, "Polyphony","Po" },
};
const int v2ntopics = sizeof(v2topics)/sizeof(V2TOPIC);
////////////////////////////////////////////
//
// V2 Modulation Sources
//
////////////////////////////////////////////
__declspec(selectany) const char *v2sources[] = {
"Velocity",
"Modulation",
"Breath",
"Ctl #3",
"Ctl #4",
"Ctl #5",
"Ctl #6",
"Volume",
"Amp EG",
"EG 2",
"LFO 1",
"LFO 2",
"Note",
};
const int v2nsources = sizeof(v2sources)/sizeof(char *);
////////////////////////////////////////////
//
// V2 Patch Parameters
//
////////////////////////////////////////////
const V2PARAM v2parms[] = {
// Voice (2)
{ 0, "Panning", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 2, "Txpose", VCTL_SLIDER, 64, 0, 127, 1, 0 },
// Osc 1 (6)
{ 0, "Mode" , VCTL_MB , 0, 0, 7, 0, "Off|Saw/Tri|Pulse|Sin|Noise|XX|AuxA|AuxB" },
{ 2, "Ringmod", VCTL_SKIP , 0, 0, 1, 0, "" },
{ 0, "Txpose", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Detune", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Color", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Volume", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Osc 2 (6)
{ 0, "Mode" , VCTL_MB , 0, 0, 7, 0, "!Off|Tri|Pul|Sin|Noi|FM|AuxA|AuxB" },
{ 2, "RingMod", VCTL_MB , 0, 0, 1, 0, "Off|On" },
{ 0, "Txpose" , VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Detune", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Color", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Volume", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Osc 3 (6)
{ 0, "Mode" , VCTL_MB , 0, 0, 7, 0, "!Off|Tri|Pul|Sin|Noi|FM|AuxA|AuxB" },
{ 2, "RingMod", VCTL_MB , 0, 0, 1, 0, "Off|On" },
{ 0, "Txpose", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Detune", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Color", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Volume", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// VCF 1 (3)
{ 0, "Mode", VCTL_MB , 0, 0, 7, 0, "Off|Low|Band|High|Notch|All|MoogL|MoogH" },
{ 0, "Cutoff", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Reso", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// VCF 2 (3)
{ 0, "Mode", VCTL_MB , 0, 0, 7, 0, "Off|Low|Band|High|Notch|All|MoogL|MoogH" },
{ 0, "Cutoff", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Reso", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Routing (2)
{ 0, "Routing", VCTL_MB , 0, 0, 2, 0, "!single|serial|parallel" },
{ 3, "Balance", VCTL_SLIDER, 64, 0, 127, 1, 0 },
// Distortion (4)
{ 0, "Mode", VCTL_MB , 0, 0, 10, 0, "Off|OD|Clip|Crush|Dec|LPF|BPF|HPF|NoF|APF|MoL" },
{ 0, "InGain", VCTL_SLIDER, 32, 0, 127, 1, 0 },
{ 0, "Param 1", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Param 2", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Amp Envelope (6)
{ 0, "Attack", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Decay", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Sustain", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "SusTime", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Release", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Amplify", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Envelope 2 (6)
{ 0, "Attack", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Decay", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Sustain", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "SusTime", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Release", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Amplify", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// LFO 1 (7)
{ 0, "Mode" , VCTL_MB , 0, 0, 4, 0, "Saw|Tri|Pulse|Sin|S+H" },
{ 0, "KeySync", VCTL_MB , 0, 0, 2, 0, "!Off|On" },
{ 0, "EnvMode", VCTL_MB , 0, 0, 2, 0, "!Off|On" },
{ 0, "Rate", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Phase", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 5, "Polarity",VCTL_MB, 0, 0, 2, 0, "!+|-|±" },
{ 0, "Amplify", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// LFO 2 (7)
{ 0, "Mode" , VCTL_MB , 0, 0, 4, 0, "Saw|Tri|Pulse|Sin|S+H" },
{ 0, "KeySync", VCTL_MB , 0, 0, 2, 0, "!Off|On" },
{ 0, "EnvMode", VCTL_MB , 0, 0, 2, 0, "!Off|On" },
{ 0, "Rate", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Phase", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 5, "Polarity",VCTL_MB, 0, 0, 2, 0, "!+|-|±" },
{ 0, "Amplify", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Globals (10)
{ 0, "OscSync", VCTL_MB , 0, 0, 1, 0, "!Off|On" },
{ 0, "ChanVol", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 6, "AuxA Recv",VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 6, "AuxB Recv",VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 6, "AuxA Send",VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 6, "AuxB Send",VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Reverb", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Delay", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "FXRoute", VCTL_MB , 0, 0, 1, 0, "!Dis -> Cho|Cho -> Dis" },
{ 1, "Boost", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Channel Dist (4)
{ 0, "Mode", VCTL_MB , 0, 0, 10, 0, "Off|OD|Clip|Crush|Dec|LPF|BPF|HPF|NoF|APF|MoL" },
{ 0, "InGain", VCTL_SLIDER, 32, 0, 127, 1, 0 },
{ 0, "Param 1", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Param 2", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// Chorus/Flanger (7)
{ 0, "Amount", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "FeedBk", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Delay L", VCTL_SLIDER, 0, 1, 127, 1, 0 },
{ 0, "Delay R", VCTL_SLIDER, 0, 1, 127, 1, 0 },
{ 0, "M. Rate", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "M.Depth", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "M.Phase", VCTL_SLIDER, 64, 0, 127, 1, 0 },
// Compressor (9)
{ 1, "Mode", VCTL_MB , 0, 0, 2, 0, "!Off|Peak|RMS" },
{ 1, "Couple", VCTL_MB , 0, 0, 1, 0, "!Mono|Stereo" },
{ 1, "AutoGain",VCTL_MB , 0, 0, 1, 0, "!Off|On" },
{ 1, "LkAhead", VCTL_SLIDER, 0, 0, 10, 1, 0 },
{ 1, "Threshd", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Ratio", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Attack", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Release", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "OutGain", VCTL_SLIDER, 64, 0, 127, 1, 0 },
// Polyphony (1)
{ 0, "MaxPoly", VCTL_SLIDER, 0, 1, 16, 0, 0 },
};
const int v2nparms = sizeof(v2parms)/sizeof(V2PARAM);
// patch size
const int v2soundsize=v2nparms+1+255*3;
////////////////////////////////////////////
//
// V2 Initial Patch Parameter Setup
//
////////////////////////////////////////////
const unsigned char v2initsnd[v2soundsize] =
{
64, // Panning
64, // Transpose
1, 0, 64, 64, 0, 127, // osc1 : simple sawtooth
0, 0, 64, 64, 32, 127, // osc2 : off
0, 0, 64, 64, 32, 127, // osc3 : off
1, 127, 0, // vcf1 : low pass, open
0, 64, 0, // vcf2 : off
0, // routing : single
64, // filter balance: mid
0, 32, 0, 64, // VoiceDis: off
0, 64, 127, 64, 80, 0, // env1 : pling
0, 64, 127, 64, 80, 64, // env2 : pling
1, 1, 0, 64, 2, 0, 0, // lfo1 : defaultbla
1, 1, 0, 64, 2, 0, 127, // lfo2 : defaultbla
0, // oscsync
0, // chanvol
0, 0, // aux a/b recv
0, 0, // aux a/b send
0, 0, // aux 1/2 sends
0, // FXRoute
0, // Boost
0, 32, 100, 64, // ChanDist: off
64, 64, 32, 32, 0, 0, 64, // Chorus/Flanger: off
0, 0, 1, 2, 90, 32, 20, 64, 64, // Compressor: off
1, // maxpoly : 1
4, // mods : 4
0, 127, 37, // velocity -> aenv ampl
1, 127, 50, // modulation -> lfo1 ampl
10, 65, 1, // lfo1 -> txpose
7, 127, 59, // ctl7 (volume) -> chanvol
0, // rest of mods
};
////////////////////////////////////////////
//
// V2 Global Topics
//
////////////////////////////////////////////
const V2TOPIC v2gtopics[] = {
{ 4, "Reverb","Rv" },
{ 7, "Stereo Delay","SD" },
//FICKEN { 9, "Parametric EQ","EQ" },
{ 2, "Post Filters","Fi" },
{ 9, "Sum Compressor","SC" },
{ 1, "Gui Features","GF" },
};
const int v2ngtopics = sizeof(v2gtopics)/sizeof(V2TOPIC);
////////////////////////////////////////////
//
// V2 Global Parameters
//
////////////////////////////////////////////
const V2PARAM v2gparms[] = {
// 00: Reverb
{ 0, "Time" , VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "HighCut", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 4, "LowCut", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "Volume", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// 03: Delay
{ 0, "Volume", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "FeedBk", VCTL_SLIDER, 64, 0, 127, 1, 0 },
{ 0, "Delay L", VCTL_SLIDER, 0, 1, 127, 1, 0 },
{ 0, "Delay R", VCTL_SLIDER, 0, 1, 127, 1, 0 },
{ 0, "M. Rate", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "M.Depth", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "M.Phase", VCTL_SLIDER, 64, 0, 127, 1, 0 },
// EQ
//FICKEN{ 6, "Gain 1", VCTL_SLIDER, 64, 0, 127, 1, 0 },
//FICKEN{ 6, "Freq 1", VCTL_SLIDER, 0, 0, 127, 1, 0 },
//FICKEN{ 6, "Q 1", VCTL_SLIDER, 0, 1, 127, 129, 0 },
//FICKEN{ 6, "Gain 2", VCTL_SLIDER, 64, 0, 127, 1, 0 },
//FICKEN{ 6, "Freq 2", VCTL_SLIDER, 0, 0, 127, 1, 0 },
//FICKEN{ 6, "Q 2", VCTL_SLIDER, 0, 1, 127, 129, 0 },
//FICKEN{ 6, "Gain 3", VCTL_SLIDER, 64, 0, 127, 1, 0 },
//FICKEN{ 6, "Freq 3", VCTL_SLIDER, 0, 0, 127, 1, 0 },
//FICKEN{ 6, "Q 3", VCTL_SLIDER, 0, 1, 127, 129, 0 },
// 10: PostProcessing
{ 0, "Low Cut", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 0, "HighCut", VCTL_SLIDER, 0, 0, 127, 1, 0 },
// 12: Compressor
{ 1, "Mode", VCTL_MB , 0, 0, 2, 0, "!Off|Peak|RMS" },
{ 1, "Couple", VCTL_MB , 0, 0, 1, 0, "!Mono|Stereo" },
{ 1, "AutoGain",VCTL_MB , 0, 0, 1, 0, "!Off|On" },
{ 1, "LkAhead", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Threshd", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Ratio", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Attack", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "Release", VCTL_SLIDER, 0, 0, 127, 1, 0 },
{ 1, "OutGain", VCTL_SLIDER, 64, 0, 127, 1, 0 },
// gui features (deprecated)
{ 6, "",VCTL_SKIP, 0, 0, 3, 0, "" }, // mystery parameter: we dont go to ravenholm
};
const int v2ngparms = sizeof(v2gparms)/sizeof(V2PARAM);
////////////////////////////////////////////
//
// V2 Initial Global Parameter Setup
//
////////////////////////////////////////////
const unsigned char v2initglobs[v2ngparms] =
{
64, 64, 32, 127, // Reverb
100, 80, 64, 64, 0, 0, 64, // Delay
//FICKEN 64, 64,64,64,64,64,64,64,64, // EQ
0, 127, // lc/hc
0, 0, 1, 2, 90, 32, 20, 64, 64, // Compressor
0 // gui color
};
// total sound memory size
const int smsize=128*sizeof(void*) + 128*v2soundsize;
static int v2version;
static int *v2vsizes;
static int *v2gsizes;
static void sdInit()
{
/*soundmem = new unsigned char [smsize+v2soundsize];
patchoffsets = (long *)soundmem;
unsigned char *sptr=soundmem+128*4;
printf("sound size: %d\n",v2nparms);
char s[256];
for (int i=0; i<129; i++)
{
if (i<128)
{
patchoffsets[i]=(long)(sptr-soundmem);
sprintf(s,"Init Patch #%03d",i);
strcpy(patchnames[i],s);
}
else
editmem=sptr;
memcpy(sptr,v2initsnd,v2soundsize);
sptr+=v2soundsize;
}
for (int i=0; i<v2ngparms; i++)
globals[i]=v2initglobs[i];
memcpy(v2clipboard,v2initsnd,v2soundsize);
sprintf(v2clipname,"Init Patch");*/
// init version control
v2version=0;
for (int i=0; i<v2nparms; i++)
if (v2parms[i].version>v2version) v2version=v2parms[i].version;
for (int i=0; i<v2ngparms; i++)
if (v2gparms[i].version>v2version) v2version=v2gparms[i].version;
v2vsizes = new int[v2version+1];
v2gsizes = new int[v2version+1];
memset(v2vsizes,0,(v2version+1)*sizeof(int));
memset(v2gsizes,0,(v2version+1)*sizeof(int));
for (int i=0; i<v2nparms; i++)
{
const V2PARAM &p=v2parms[i];
// ATLASSERT(p.version<=v2version);
for (int j=v2version; j>=p.version; j--)
v2vsizes[j]++;
}
for (int i=0; i<v2ngparms; i++)
{
const V2PARAM &p=v2gparms[i];
//ATLASSERT(p.version<=v2version);
for (int j=v2version; j>=p.version; j--)
v2gsizes[j]++;
}
//ATLASSERT(v2vsizes[v2version]==v2nparms);
for (int i=0; i<=v2version; i++)
{
//printf("size of version %d sound bank: %d params, %d globals\n",i,v2vsizes[i],v2gsizes[i]);
v2vsizes[i]+=1+255*3;
}
}
static void sdClose()
{
//delete soundmem;
delete[] v2vsizes;
delete[] v2gsizes;
}
static const char * const v2mconv_errors[] =
{
"no error",
"V2M file contains no patch data! (forgot program changes?)",
"V2M file was made with unknown synth version!",
};
#define printf2
// nicht drüber nachdenken.
static struct _ssbase {
const sU8 *patchmap;
const sU8 *globals;
sU32 timediv;
sU32 timediv2;
sU32 maxtime;
const sU8 *gptr;
sU32 gdnum;
struct _basech {
sU32 notenum;
const sU8 *noteptr;
sU32 pcnum;
const sU8 *pcptr;
sU32 pbnum;
const sU8 *pbptr;
struct _bcctl {
sU32 ccnum;
const sU8 *ccptr;
} ctl[7];
} chan[16];
const sU8 *mididata;
sInt midisize;
sInt patchsize;
sInt globsize;
sInt maxp;
const sU8 *newpatchmap;
const sU8 *speechdata;
sInt spsize;
} base;
static void readfile(const unsigned char *inptr, const int inlen)
{
const sU8 *d=inptr;
memset(&base,0,sizeof(base));
base.timediv=(*((sU32*)(d)));
base.timediv2=10000*base.timediv;
base.maxtime=*((sU32*)(d+4));
base.gdnum=*((sU32*)(d+8));
d+=12;
base.gptr=d;
d+=10*base.gdnum;
for (sInt ch=0; ch<16; ch++)
{
_ssbase::_basech &c=base.chan[ch];
c.notenum=*((sU32*)d);
d+=4;
if (c.notenum)
{
c.noteptr=d;
d+=5*c.notenum;
c.pcnum=*((sU32*)d);
d+=4;
c.pcptr=d;
d+=4*c.pcnum;
c.pbnum=*((sU32*)d);
d+=4;
c.pbptr=d;
d+=5*c.pbnum;
for (sInt cn=0; cn<7; cn++)
{
_ssbase::_basech::_bcctl &cc=c.ctl[cn];
cc.ccnum=*((sU32*)d);
d+=4;
cc.ccptr=d;
d+=4*cc.ccnum;
}
}
}
base.midisize=d-inptr;
base.globsize=*((sU32*)d);
if (base.globsize<0 || base.globsize>131072) return;
d+=4;
base.globals=d;
d+=base.globsize;
base.patchsize=*((sU32*)d);
if (base.patchsize<0 || base.patchsize>1048576) return;
d+=4;
base.patchmap=d;
d+=base.patchsize;
if (d-inptr < inlen)
{
base.spsize=*((sU32*)d);
d+=4;
base.speechdata=d;
d+=base.spsize;
// small sanity check
if (base.spsize<0 || base.spsize > 8192)
{
base.spsize=0;
base.speechdata=0;
}
}
else
{
base.spsize=0;
base.speechdata=0;
}
printf2("after read: est %d, is %d\n",inlen,d-inptr);
printf2("midisize: %d, globs: %d, patches: %d\n",base.midisize,base.globsize,base.patchsize);
}
// gives version deltas
static int CheckV2MVersion(const unsigned char *inptr, const int inlen)
{
int i;
readfile(inptr,inlen);
if (!base.patchsize)
return -1;
// determine highest used patch from progchange commands
// (midiconv remaps the patches so that they're a
// continuous block from 0 to x)
base.maxp=0;
for (int ch=0; ch<16; ch++)
{
for (int i=0; i<(int)base.chan[ch].pcnum; i++)
{
sInt p=base.chan[ch].pcptr[3*base.chan[ch].pcnum+i];
// WORKAROUND: omit illegal patch numbers
// (bug in midiconv? bug in logic's .mid export?)
printf2("ch%d pc%d : %2x\n",ch+1,i,p);
if (p<0x80)
if (p>=base.maxp) base.maxp=p+1;
}
}
printf2("patches used: %d\n",base.maxp);
if (!base.maxp)
return -1;
// offset table to ptaches
sInt *poffsets=(sInt *)base.patchmap;
sInt matches=0, best=-1;
// for each version check...
for (i=0; i<=v2version; i++)
{
// ... if globals size is correct...
if (base.globsize==v2gsizes[i])
{
printf2("globsize match: %d\n",i);
// ... and if the size of all patches makes sense
int p;
for (p=0; p<base.maxp-1; p++)
{
sInt d=(poffsets[p+1]-poffsets[p])-(v2vsizes[i]-3*255);
if (d%3) break;
d/=3;
if ( d != base.patchmap[poffsets[p]+v2vsizes[i]-3*255-1])
break;
}
if (p==base.maxp-1)
{
printf2("... ok!\n");
best=i;
matches++;
}
else
printf2("no match!\n");
}
}
// if we've got exactly one match, we're quite sure
sInt ret=(matches>=1)?v2version-best:-2;
printf2("found version delta: %d\n",ret);
return ret;
}
//Klicke den Narren über Dir und das Schauspiel wird beginnen...
static sInt transEnv(sInt enVal)
{
sF32 dv=(sF32)(1.0f-pow(2.0f, -enVal/128.0f*11.0f));
dv=(sF32)sqrt(dv); // square root to correct value
sInt nEnVal=(sInt)(-log(1.0f-dv)/log(2.0f)*128.0f/11.0f);
if (nEnVal<0)
{
printf2("!!clamping enval lower bound!\n");
nEnVal=0;
}
else if (nEnVal>127)
{
printf2("!!clamping enval upper bound!\n");
nEnVal=127;
}
return nEnVal;
}
static void ConvertV2M(const unsigned char *inptr, const int inlen, unsigned char **outptr, int *outlen)
{
int i,p;
// check version
sInt vdelta=CheckV2MVersion(inptr,inlen);
if (!vdelta) // if same, simply clone
{
*outptr=new sU8[inlen+4];
memset(*outptr,0,inlen+4);
*outlen=inlen+4;
memcpy(*outptr,inptr,inlen);
return;
}
else if (vdelta<0) // if invalid...
{
*outptr=0;
*outlen=0;
return;
}
vdelta=v2version-vdelta;
// fake base.maxp
int maxp2=((sInt*)base.patchmap)[0]/4;
if (maxp2!=base.maxp)
{
printf2("warning: patch count inconsistency: we:%d, they:%d\n",base.maxp,maxp2);
base.maxp=maxp2;
}
// calc new size
int gdiff=v2gsizes[v2version]-v2gsizes[vdelta];
int pdiff=v2vsizes[v2version]-v2vsizes[vdelta];
int newsize=inlen+gdiff+base.maxp*pdiff;
printf2("old size: %d, new size: %d\n",inlen,newsize);
// init new v2m
*outlen=newsize+4;
sU8 *newptr=*outptr=new sU8[newsize+4];
memset(newptr,0,newsize+4);
// copy midi data
memcpy(newptr,inptr,base.midisize);
// new globals length...
newptr+=base.midisize;
*(sInt *)newptr=v2ngparms;
printf2("glob size: old %d, new %d\n",base.globsize,*(sInt *)newptr);
newptr+=4;
// copy/remap globals
memcpy(newptr,v2initglobs,v2ngparms);
const sU8 *oldgptr=base.globals;
for (i=0; i<v2ngparms; i++)
{
if (v2gparms[i].version<=vdelta)
newptr[i]=*oldgptr++;
}
newptr+=v2ngparms;
// new patch data length
*(sInt *)newptr=base.patchsize+base.maxp*pdiff;
printf2("patch size: old %d, new %d\n",base.patchsize,*(sInt *)newptr);
newptr+=4;
base.newpatchmap=newptr;
sInt *poffsets=(sInt *)base.patchmap;
sInt *noffsets=(sInt *)newptr;
const int ros=v2vsizes[vdelta]-255*3-1;
sU8 *nptr2=newptr;
// copy patch table...
for (p=0; p<base.maxp; p++)
noffsets[p]=poffsets[p]+p*pdiff;
newptr+=4*base.maxp;
// for each patch...
for (p=0; p<base.maxp; p++)
{
const sU8 *src=base.patchmap+poffsets[p];
const sU8 *dest_soll=nptr2+noffsets[p];
printf2("p%d ist:%08x soll:%08x\n",p,newptr,dest_soll);
// fill patch with default values
memcpy(newptr,v2initsnd,v2nparms);
// copy/remap patch data
for (i=0; i<v2nparms; i++)
{
if (v2parms[i].version<=vdelta)
{
*newptr=*src++;
/*
if (vdelta<2 && (i==33 || i==36 || i==39 || i==42)) // fix envelopes
*newptr=transEnv(*newptr);
*/
}
newptr++;
}
// copy mod number
const sInt modnum=*newptr++=*src++;
// printf2("patch %d: %d mods\n",p,modnum);
// copy/remap modulations
for (i=0; i<modnum; i++)
{
newptr[0]=src[0];
newptr[1]=src[1];
newptr[2]=src[2];
for (int k=0; k<=newptr[2]; k++)
if (v2parms[k].version>vdelta) newptr[2]++;
newptr+=3;
src+=3;
}
}
// copy speech
*(sU32*)newptr=base.spsize;
newptr+=4;
memcpy(newptr,base.speechdata,base.spsize);
newptr+=base.spsize;
printf2("est size: %d, real size: %d\n",newsize,newptr-*outptr);
}
static unsigned long GetV2MPatchData(const unsigned char *inptr, const int inlen,
unsigned char **outptr, const unsigned char **patchmap)
{
int outlen;
ConvertV2M(inptr,inlen,outptr,&outlen);
sInt *poffsets=(sInt*)base.newpatchmap;
for (sInt i=0; i<base.maxp; i++)
{
patchmap[i]=base.newpatchmap+poffsets[i];
}
return base.maxp;
}
#endif
/****************************************************************************/
/*** ***/
/*** Interface ***/
/*** ***/
/****************************************************************************/
#if sLINK_VIRUZ2
#if !sINTRO
sViruz2::sViruz2()
{
Buffer = new sF32[16384];
Viruz.Init();
}
sViruz2::~sViruz2()
{
if(Buffer)
delete[] Buffer;
}
sU8 *sViruz2::ConvertV2M(const sU8 *in,sInt inlen,sInt &outlen)
{
sU8 *out=0;
#if !sPLAYER
sdInit();
::ConvertV2M(in,inlen,&out,&outlen);
sdClose();
#endif
return out;
}
sBool sViruz2::Init(sInt songnr)
{
Viruz.Open(Stream);
Viruz.Play(0);
// ssInit(Stream,0);
// ssPlay();
return sTRUE;
}
sInt sViruz2::Render(sS16 *d,sInt samples)
{
sInt result;
sInt count;
sInt i;
result = 0;
while(samples>0)
{
count = sMin(samples,4096);
Viruz.Render(Buffer,count);
for(i=0;i<count*2;i++)
{
*d++ = sFtol(sRange<sF32>(Buffer[i],1,-1)*0x7fff);
// *d++ = sFtol(sRange<sF32>(Buffer[i*2+1],1,-1)*0x7fff);
}
samples-=count;
result += count;
}
return result;
}
sInt sViruz2::GetTuneLength()
{
#if !sPLAYER
sS32 *timeline;
sInt nevents,len_ms;
nevents = Viruz.CalcPositions(&timeline);
len_ms = timeline[2*(nevents-1)] + 2000;
delete[] timeline;
return (len_ms*441)/10;
#else
return 0;
#endif
}
#endif
#endif
/****************************************************************************/
/****************************************************************************/
Jump to Line
Something went wrong with that request. Please try again.