OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
hydra.cpp
Go to the documentation of this file.
1#include "hydra.h"
2
3#include "dlscollection.h"
4
5#define TSF_IMPLEMENTATION
6#define TSF_STATIC
7
8#ifdef __GNUC__
9#pragma GCC diagnostic push
10#pragma GCC diagnostic ignored "-Wconversion"
11#pragma GCC diagnostic ignored "-Wunused-function"
12#include "tsf.h"
13#pragma GCC diagnostic pop
14#else
15#include "tsf.h"
16#endif
17
18using namespace Dx8;
19
20enum {
22 };
23
24static bool compValue(const tsf_hydra_phdr& a,const tsf_hydra_phdr& b){
25 return
26 std::memcmp(a.presetName,b.presetName,20)==0 &&
27 a.preset ==b.preset &&
28 a.bank ==b.bank &&
29 a.presetBagNdx==b.presetBagNdx &&
30 a.library ==b.library &&
31 a.genre ==b.genre &&
32 a.morphology ==b.morphology;
33 }
34
35static bool compValue(const tsf_hydra_shdr& a,const tsf_hydra_shdr& b){
36 return
37 std::memcmp(a.sampleName,b.sampleName,20)==0 &&
38 //a.start ==b.start &&
39 //a.end ==b.end &&
40 //a.startLoop ==b.startLoop &&
41 //a.endLoop ==b.endLoop &&
42 a.sampleRate ==b.sampleRate &&
43 a.originalPitch ==b.originalPitch &&
44 a.pitchCorrection==b.pitchCorrection &&
45 a.sampleLink ==b.sampleLink &&
46 a.sampleType ==b.sampleType;
47 }
48
49static bool compValue(const tsf_hydra_pbag& a,const tsf_hydra_pbag& b){
50 return
51 a.genNdx==b.genNdx &&
52 a.modNdx==b.modNdx;
53 }
54
55static bool compValue(const tsf_hydra_pmod& a,const tsf_hydra_pmod& b){
56 return
57 a.modSrcOper ==b.modSrcOper &&
58 a.modDestOper ==b.modDestOper &&
59 a.modAmount ==b.modAmount &&
60 a.modAmtSrcOper==b.modAmtSrcOper &&
61 a.modTransOper ==b.modTransOper;
62 }
63
64static bool compValue(const tsf_hydra_pgen& a,const tsf_hydra_pgen& b){
65 return std::memcmp(&a,&b,sizeof(a))==0;
66 }
67
68static bool compValue(const tsf_hydra_inst& a,const tsf_hydra_inst& b){
69 return std::memcmp(&a,&b,sizeof(a))==0;
70 }
71
72static bool compValue(const tsf_hydra_ibag& a,const tsf_hydra_ibag& b){
73 return std::memcmp(&a,&b,sizeof(a))==0;
74 }
75
76static bool compValue(const tsf_hydra_imod& a,const tsf_hydra_imod& b){
77 return std::memcmp(&a,&b,sizeof(a))==0;
78 }
79
80static bool compValue(const tsf_hydra_igen& a,const tsf_hydra_igen& b){
81 return std::memcmp(&a,&b,sizeof(a))==0;
82 }
83
84template<class T>
85static bool comp(const T* a,const T* b,int n,size_t vn){
86 if(size_t(n)!=vn)
87 return false;
88 for(int i=0;i<n;++i){
89 if(!compValue(a[i],b[i]))
90 return false;
91 }
92 return true;
93 }
94
95static tsf_hydra_phdr mkPhdr(const DlsCollection::Instrument& instr,uint16_t index){
96 tsf_hydra_phdr r={};
97 std::strncpy(r.presetName,instr.info.inam.c_str(),19);
98 r.preset = uint16_t(instr.header.Locale.ulInstrument);
99 r.bank = uint16_t(instr.header.Locale.ulBank);
100 r.presetBagNdx = index;
101 r.library = 0;
102 r.genre = 0;
103 r.morphology = 0;
104 return r;
105 }
106
107static tsf_hydra_phdr mkPhdr(const char* presetName,uint16_t index){
108 tsf_hydra_phdr r = {};
109 std::strncpy(r.presetName,presetName,19);
110 r.presetBagNdx = index;
111 return r;
112 }
113
114static tsf_hydra_pbag mkPbag(uint16_t genNdx,uint16_t modNdx){
115 tsf_hydra_pbag r={};
116 r.genNdx = genNdx;
117 r.modNdx = modNdx;
118 return r;
119 }
120
121static tsf_hydra_pgen mkPgen(uint16_t genOper,uint16_t wordAmount){
122 tsf_hydra_pgen r={};
123 r.genOper = genOper;
124 r.genAmount.wordAmount = wordAmount;
125 return r;
126 }
127
128static tsf_hydra_inst mkInst(const char* instName,uint16_t instBagNdx){
129 tsf_hydra_inst r={};
130 std::strncpy(r.instName,instName,19);
131 r.instBagNdx=instBagNdx;
132 return r;
133 }
134
135static tsf_hydra_ibag mkIbag(uint16_t instGenNdx,uint16_t instModNdx){
136 tsf_hydra_ibag r={};
137 r.instGenNdx = instGenNdx;
138 r.instModNdx = instModNdx;
139 return r;
140 }
141
142struct tsf_hydra_igen mkIgen(uint16_t op,uint16_t lo,uint16_t hi) {
143 if(lo>255 || hi>255)
144 throw std::runtime_error("hydra.igen range error");
145 tsf_hydra_igen r={};
146 r.genOper = op;
147 r.genAmount.range.lo = uint8_t(lo);
148 r.genAmount.range.hi = uint8_t(hi);
149 return r;
150 }
151
152struct tsf_hydra_igen mkIgen(uint16_t op,uint16_t u16) {
153 tsf_hydra_igen r={};
154 r.genOper = op;
155 r.genAmount.wordAmount = u16;
156 return r;
157 }
158
159uint16_t Hydra::mkGeneratorOp(uint16_t usDestination) {
160 switch(usDestination) {
161 case EG1AttachTime:
162 return kAttackVolEnv;
163 case EG1DecayTime:
164 return kDecayVolEnv;
165 case EG1ReleaseTime:
166 return kReleaseVolEnv;
167 case EG1SustainLevel:
168 return kSustainVolEnv;
169
170 case EG2AttachTime:
171 return kAttackModEnv;
172 case EG2DecayTime:
173 return kDecayModEnv;
174 case EG2ReleaseTime:
175 return kReleaseModEnv;
176 case EG2SustainLevel:
177 return kSustainModEnv;
178 default:
179 return 0;// error
180 }
181 }
182
183Hydra::Hydra(const DlsCollection &dls,const std::vector<Wave>& wave) {
184 std::vector<tsf_hydra_shdr> samples;
185 wdata = allocSamples(wave,samples,wdataSize);
186
187 const uint16_t modIndex = 0;
188 const uint16_t instModNdx = 0;
189 uint16_t instBagIndex = 0;
190
191 for(size_t idInstr=0; idInstr<dls.instrument.size(); ++idInstr) {
192 const auto& instr = dls.instrument[idInstr];
193
194 phdr.push_back(mkPhdr(instr,uint16_t(phdr.size())));
195 pbag.push_back(mkPbag(uint16_t(pbag.size()),modIndex));
196
197 pgen.push_back(mkPgen(41,uint16_t(idInstr)));
198 inst.push_back(mkInst(instr.info.inam.c_str(),instBagIndex));
199
200 instBagIndex = uint16_t(instBagIndex+instr.regions.size());
201
202 for(const auto& reg : instr.regions) {
203 const auto& hdr = reg.head;
204 const auto& wavelink = reg.wlink;
205 const auto& wavesample = reg.waveSample;
206
207 ibag.push_back(mkIbag(uint16_t(igen.size()),instModNdx));
208
209 uint16_t keyrangeLow = hdr.RangeKey.usLow;
210 uint16_t keyrangeHigh = hdr.RangeKey.usHigh;
211 uint16_t velrangeLow = 0;
212 uint16_t velrangeHigh = 0;
213 if(hdr.RangeVelocity.usHigh<=hdr.RangeVelocity.usLow) {
214 velrangeLow = 0;
215 velrangeHigh = 127;
216 } else {
217 velrangeLow = hdr.RangeVelocity.usLow;
218 velrangeHigh = hdr.RangeVelocity.usHigh;
219 }
220 igen.push_back(mkIgen(kKeyRange,keyrangeLow,keyrangeHigh));
221 igen.push_back(mkIgen(kVelRange,velrangeLow,velrangeHigh));
222
223 const uint16_t time = 61550; //FIXME
224 igen.push_back(mkIgen(kAttackVolEnv,time));
225
226 for(const auto& art : instr.articulators) {
227 for(const auto& c : art.connectionBlocks) {
228 if(c.usControl == 0 && c.usSource == 0 && c.usTransform == 0) {
229 uint16_t gen = mkGeneratorOp(c.usDestination);
230 igen.push_back(mkIgen(gen,uint16_t(c.lScale/65536)));
231 }
232 }
233 }
234
235 if(hdr.RangeKey.usHigh < hdr.RangeKey.usLow)
236 throw std::runtime_error("Invalid key range in instrument");
237
238 tsf_hydra_shdr sample={};
239 if(reg.loop.size()==0) {
240 sample = samples[wavelink.ulTableIndex];
241 sample.startLoop = 0;
242 sample.endLoop = 0;
243 igen.push_back(mkIgen(kSampleModes,0));
244 } else {
245 auto loop = reg.loop[0];
246 sample = samples[wavelink.ulTableIndex];
247 sample.startLoop = loop.ulLoopStart;
248 sample.endLoop = loop.ulLoopStart + loop.ulLoopLength;
249
250 sample.startLoop += sample.start;
251 sample.endLoop += sample.start;
252 igen.push_back(mkIgen(kSampleModes,1));
253 }
254
255 igen.push_back(mkIgen(kSampleID,uint16_t(shdr.size())));
256
257 sample.originalPitch = uint8_t(wavesample.usUnityNote);
258 sample.pitchCorrection = int8_t (wavesample.sFineTune);
259 shdr.push_back(sample);
260 }
261 }
262
263 phdr.push_back(mkPhdr("EOP",uint16_t(phdr.size())));
264 pbag.push_back(mkPbag(uint16_t(pbag.size()),modIndex));
265
266 tsf_hydra_pmod mod={};
267 pmod.push_back(mod);
268 pgen.push_back(mkPgen(0,0));
269
270 inst.push_back(mkInst("EOI",instBagIndex));
271 ibag.push_back(mkIbag(uint16_t(igen.size()),instModNdx));
272
273 tsf_hydra_imod imd={};
274 imod.push_back(imd);
275
276 tsf_hydra_igen gen={};
277 igen.push_back(gen);
278
279 tsf_hydra_shdr sampleEnd={};
280 std::strncpy(sampleEnd.sampleName,"EOS",19);
281 shdr.push_back(sampleEnd);
282 }
283
286
287void Hydra::finalize(tsf *tsf) {
288 tsf->fontSamples=nullptr;
289 tsf_close(tsf);
290 }
291
292bool Hydra::hasNotes(tsf *tsf) {
293 tsf_voice *v = tsf->voices, *vEnd = v + tsf->voiceNum;
294 for(; v!=vEnd; v++)
295 if(v->playingPreset != -1)
296 return true;
297 return false;
298 }
299
300void Hydra::noteOn(tsf* f, int presetId, int key, float vel) {
301 tsf_note_on(f, presetId, key, vel);
302 }
303
304void Hydra::noteOff(tsf* f, int presetId, int key) {
305 tsf_note_off(f, presetId, key);
306 }
307
308int Hydra::presetIndex(const tsf* f, int bank, int presetNum) {
309 return tsf_get_presetindex(f, bank, presetNum);
310 }
311
312void Hydra::renderFloat(tsf* f, float* buffer, int samples, int flag) {
313 tsf_render_float(f, buffer, samples, flag);
314 }
315
316int Hydra::channelSetPan(tsf* f, int channel, float pan) {
317 return tsf_channel_set_pan(f, channel, pan);
318 }
319
320void Hydra::setOutput(tsf* f, int samplerate, float gain) {
321 tsf_set_output(f, TSF_STEREO_INTERLEAVED, samplerate, gain);
322 }
323
325 tsf_hydra hydra={};
326 toTsf(hydra);
327
328 tsf* res = reinterpret_cast<tsf*>(TSF_MALLOC(sizeof(tsf)));
329 TSF_MEMSET(res, 0, sizeof(tsf));
330 res->outSampleRate = 44100.0f;
331 res->presetNum = hydra.phdrNum - 1;
332 res->presets = reinterpret_cast<tsf_preset*>(TSF_MALLOC(size_t(res->presetNum)*sizeof(tsf_preset)));
333
334 res->fontSamples = wdata.get();
335 tsf_load_presets(res, &hydra, unsigned(wdataSize));
336 return res;
337 }
338
339void Hydra::toTsf(tsf_hydra &out) {
340 out.phdrNum = int(phdr.size());
341 out.phdrs = phdr.data();
342
343 out.pbagNum = int(pbag.size());
344 out.pbags = pbag.data();
345
346 out.pmodNum = int(pmod.size());
347 out.pmods = pmod.data();
348
349 out.pgenNum = int(pgen.size());
350 out.pgens = pgen.data();
351
352 out.instNum = int(inst.size());
353 out.insts = inst.data();
354
355 out.ibagNum = int(ibag.size());
356 out.ibags = ibag.data();
357
358 out.imodNum = int(imod.size());
359 out.imods = imod.data();
360
361 out.igenNum = int(igen.size());
362 out.igens = igen.data();
363
364 out.shdrNum = int(shdr.size());
365 out.shdrs = shdr.data();
366 }
367
368std::unique_ptr<float[]> Hydra::allocSamples(const std::vector<Wave>& wave,std::vector<tsf_hydra_shdr>& smp,size_t& count) {
369 size_t wavStart=0;
370 for(const auto& wav : wave) {
371 if(wav.wfmt.wBitsPerSample!=16)
372 throw std::runtime_error("Unexpected DLS sample format");
373 const size_t wavSize = wav.wavedata.size()/(sizeof(int16_t));
374
375 tsf_hydra_shdr sx={};
376 std::strncpy(sx.sampleName,wav.info.inam.c_str(),19);
377 sx.start = tsf_u32(wavStart);
378 sx.end = tsf_u32(wavStart+wavSize);
379 sx.startLoop = 0; // will be overridden, later
380 sx.endLoop = 0;
381 sx.sampleRate = wav.wfmt.dwSamplesPerSec;
382 sx.originalPitch = uint8_t(wav.waveSample.usUnityNote);
383 sx.pitchCorrection = int8_t (wav.waveSample.sFineTune);
384 sx.sampleLink = 0;
385 sx.sampleType = 1; // mono
386 smp.push_back(sx);
387
388 wavStart += wavSize;
389 wavStart += kTerminatorSampleLength;
390 }
391
392 std::unique_ptr<float[]> samples(new float[wavStart]);
393 float* wr = samples.get();
394
395 // exception safe
396 for(const auto& wav : wave) {
397 wav.toFloatSamples(wr);
398 wr+=wav.wavedata.size()/sizeof(int16_t);
399
400 // terminator samples.
401 for(size_t i=0; i<kTerminatorSampleLength; i++) {
402 *wr = 0.f;
403 ++wr;
404 }
405 }
406 count = wavStart;
407 return samples;
408 }
409
410bool Hydra::validate(const tsf_hydra &tsf) const {
411 if(!comp(tsf.phdrs,phdr.data(),tsf.phdrNum,phdr.size()))
412 return false;
413 if(!comp(tsf.pbags,pbag.data(),tsf.pbagNum,pbag.size()))
414 return false;
415 if(!comp(tsf.pmods,pmod.data(),tsf.pmodNum,pmod.size()))
416 return false;
417 if(!comp(tsf.pgens,pgen.data(),tsf.pgenNum,pgen.size()))
418 return false;
419 if(!comp(tsf.insts,inst.data(),tsf.instNum,inst.size()))
420 return false;
421 if(!comp(tsf.ibags,ibag.data(),tsf.ibagNum,ibag.size()))
422 return false;
423 if(!comp(tsf.imods,imod.data(),tsf.imodNum,imod.size()))
424 return false;
425 if(!comp(tsf.igens,igen.data(),tsf.igenNum,igen.size()))
426 return false;
427 if(!comp(tsf.shdrs,shdr.data(),tsf.shdrNum,shdr.size()))
428 return false;
429 return true;
430 }
std::vector< Instrument > instrument
std::vector< tsf_hydra_igen > igen
Definition hydra.h:85
Hydra(const DlsCollection &dls, const std::vector< Wave > &wave)
Definition hydra.cpp:183
static void renderFloat(tsf *f, float *buffer, int samples, int flag)
Definition hydra.cpp:312
bool validate(const tsf_hydra &tsf) const
Definition hydra.cpp:410
tsf * toTsf()
Definition hydra.cpp:324
size_t wdataSize
Definition hydra.h:89
static void setOutput(tsf *f, int samplerate, float gain)
Definition hydra.cpp:320
std::vector< tsf_hydra_pbag > pbag
Definition hydra.h:79
std::vector< tsf_hydra_ibag > ibag
Definition hydra.h:83
std::vector< tsf_hydra_pgen > pgen
Definition hydra.h:81
std::vector< tsf_hydra_phdr > phdr
Definition hydra.h:78
static int presetIndex(const tsf *f, int bank, int presetNum)
Definition hydra.cpp:308
@ kAttackModEnv
Definition hydra.h:27
@ kVelRange
Definition hydra.h:36
@ kDecayVolEnv
Definition hydra.h:32
@ kSustainVolEnv
Definition hydra.h:33
@ kDecayModEnv
Definition hydra.h:28
@ kKeyRange
Definition hydra.h:35
@ kSustainModEnv
Definition hydra.h:29
@ kAttackVolEnv
Definition hydra.h:31
@ kReleaseVolEnv
Definition hydra.h:34
@ kSampleID
Definition hydra.h:37
@ kReleaseModEnv
Definition hydra.h:30
@ kSampleModes
Definition hydra.h:38
static bool hasNotes(tsf *tsf)
Definition hydra.cpp:292
static void noteOn(tsf *f, int presetId, int key, float vel)
Definition hydra.cpp:300
static int channelSetPan(tsf *f, int channel, float pan)
Definition hydra.cpp:316
std::vector< tsf_hydra_pmod > pmod
Definition hydra.h:80
static void finalize(tsf *tsf)
Definition hydra.cpp:287
std::vector< tsf_hydra_inst > inst
Definition hydra.h:82
std::unique_ptr< float[]> wdata
Definition hydra.h:88
static void noteOff(tsf *f, int presetId, int key)
Definition hydra.cpp:304
std::vector< tsf_hydra_shdr > shdr
Definition hydra.h:86
std::vector< tsf_hydra_imod > imod
Definition hydra.h:84
@ EG1SustainLevel
Definition hydra.h:53
@ EG2DecayTime
Definition hydra.h:56
@ EG1AttachTime
Definition hydra.h:50
@ EG1ReleaseTime
Definition hydra.h:52
@ EG2SustainLevel
Definition hydra.h:58
@ EG2ReleaseTime
Definition hydra.h:57
@ EG2AttachTime
Definition hydra.h:55
@ EG1DecayTime
Definition hydra.h:51
std::string inam
Definition info.h:12
static tsf_hydra_phdr mkPhdr(const DlsCollection::Instrument &instr, uint16_t index)
Definition hydra.cpp:95
static tsf_hydra_ibag mkIbag(uint16_t instGenNdx, uint16_t instModNdx)
Definition hydra.cpp:135
static bool compValue(const tsf_hydra_phdr &a, const tsf_hydra_phdr &b)
Definition hydra.cpp:24
struct tsf_hydra_igen mkIgen(uint16_t op, uint16_t lo, uint16_t hi)
Definition hydra.cpp:142
static bool comp(const T *a, const T *b, int n, size_t vn)
Definition hydra.cpp:85
@ kTerminatorSampleLength
Definition hydra.cpp:21
static tsf_hydra_inst mkInst(const char *instName, uint16_t instBagNdx)
Definition hydra.cpp:128
static tsf_hydra_pgen mkPgen(uint16_t genOper, uint16_t wordAmount)
Definition hydra.cpp:121
static tsf_hydra_pbag mkPbag(uint16_t genNdx, uint16_t modNdx)
Definition hydra.cpp:114
Definition band.h:10