1use crate::*;
2
3pub trait ParameterGatherer {
6 fn hex(self, name: &str, val: u8) -> Self;
8
9 fn bool(self, name: &str, val: bool) -> Self;
11
12 fn float(self, name: &str, val: f64) -> Self;
14
15 fn str(self, name: &str, val: &str) -> Self;
17
18 fn enumeration(self, name: &str, hex: u8, val: &str) -> Self;
21
22 fn nest_f<F>(self, name: &str, f: F) -> Self
25 where F : FnOnce (Self) -> Self, Self : Sized;
26}
27
28pub trait Describable {
31 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG;
33}
34
35pub trait DescribableWithDictionary {
37 fn describe_with_dic< PG : ParameterGatherer>(&self, pg: PG, dic: &[&'static str], ver: Version) -> PG;
38}
39
40impl Describable for InputMixerSettings {
41 fn describe<PG : ParameterGatherer>(&self, pg: PG, _ver: Version) -> PG {
42 pg
43 .hex("VOL", self.volume)
44 .hex("Chorus", self.mfx)
45 .hex("Delay", self.delay)
46 .hex("Reverb", self.reverb)
47 }
48}
49
50impl Describable for MixerSettings {
51 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
52 let pg = pg
53 .hex("MASTER_VOL", self.master_volume)
54 .nest_f("TRACK volume", |ipg| {
55 self.track_volume.iter()
56 .enumerate()
57 .fold(ipg, |iipg, (i, v)|
58 iipg.hex(&format!("VOL_{}", i), *v))
59 })
60 .hex("Chorus Vol", self.chorus_volume)
61 .hex("Delay Vol", self.delay_volume)
62 .hex("Reverb Vol", self.reverb_volume);
63
64 let pg = match &self.analog_input {
65 AnalogInputSettings::Stereo(inp) =>
66 pg.nest_f("INPUT", |ipg| inp.describe(ipg, ver)),
67 AnalogInputSettings::DualMono((l, r)) =>
68 pg.nest_f("INPUT Left", |ipg| l.describe(ipg, ver))
69 .nest_f("INPUT right", |ipg| r.describe(ipg, ver))
70 };
71
72 let pg =
73 pg.nest_f("USB input", |ipg| self.usb_input.describe(ipg, ver))
74 .nest_f("LIMITER", |ipg| {
75 let ipg = ipg.hex("LIM", self.limiter.level);
76 match &self.limiter.attack_release {
77 None => ipg,
78 Some ((at, rl, soft)) =>
79 ipg.hex("ATTACK", *at)
80 .hex("RELEASE", *rl)
81 .bool("Soft clip", *soft)
82 }
83 })
84 .hex("DJF", self.dj_filter)
85 .hex("PEAK", self.dj_peak)
86 .hex("FLTTY", self.dj_filter_type);
87
88 match self.ott_level {
89 None => pg,
90 Some(ott) => pg.hex("OTT", ott)
91 }
92 }
93}
94
95impl Describable for EffectsSettings {
96 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
97 let mfx_name = if ver.after(&FIRMWARE_6_2_SONG_VERSION) {
98 "MFX"
99 } else {
100 "Chorus"
101 };
102
103 let pg = pg
104 .nest_f(mfx_name, |ipg| {
105 let ipg =
106 match self.mfx_kind {
107 None => ipg,
108 Some(mfx) =>
109 ipg.enumeration("MFX KIND", mfx.into(), &format!("{:?}", mfx))
110 };
111
112 ipg.hex("MOD_DEPTH", self.chorus_mod_depth)
113 .hex("MOD_FREQ", self.chorus_mod_freq)
114 .hex("WIDTH", self.chorus_width)
115 .hex("REVERB_SEND", self.chorus_reverb_send)
116 })
117 .nest_f("Delay", |ipg| {
118 let ipg = match &self.delay_filter {
119 None => ipg,
120 Some(df) =>
121 ipg.hex("LP", df.low_pass)
122 .hex("HP", df.high_pass)
123 };
124
125 ipg.hex("DELAY_L", self.delay_time_l)
126 .hex("DELAY_R", self.delay_time_r)
127 .hex("FEEDBACK", self.delay_feedback)
128 .hex("WIDTH", self.delay_width)
129 .hex("REVERB_SEND", self.delay_reverb_send)
130 })
131 .nest_f("Reverb", |ipg| {
132 let ipg = match &self.delay_filter {
133 None => ipg,
134 Some(df) =>
135 ipg.hex("LP", df.low_pass)
136 .hex("HP", df.high_pass)
137 };
138
139 let ipg = ipg
140 .hex("SIZE", self.reverb_size)
141 .hex("WIDTH", self.reverb_width)
142 .hex("DECAY", self.reverb_damping)
143 .hex("MOD_DEPTH", self.reverb_mod_depth)
144 .hex("MOD_FREQ", self.reverb_mod_freq);
145
146 match self.reverb_shimmer {
147 None => ipg,
148 Some(shimmer) => ipg.hex("SHIMMER", shimmer)
149 }
150 });
151
152 match &self.ott_configuration {
153 None => pg,
154 Some(ott) => {
155 pg.nest_f("OTT", |ipg| {
156 ipg.hex("TIME", ott.time)
157 .hex("COLOR", ott.color)
158 })
159 }
160 }
161 }
162}
163
164impl Describable for EqBand {
165 fn describe<PG : ParameterGatherer>(&self, pg: PG, _ver: Version) -> PG {
166 return pg.float("GAIN", self.gain())
167 .float("FREQ", self.frequency() as f64)
168 .hex("Q", self.q)
169 .enumeration("TYPE", self.mode.eq_type_hex(), self.mode.type_str())
170 .enumeration("MODE", self.mode.eq_mode_hex(), self.mode.mode_str())
171 }
172}
173
174impl Describable for Equ {
175 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
176 return pg
177 .nest_f("LOW", |ii| self.low.describe(ii, ver))
178 .nest_f("MID", |ii| self.mid.describe(ii, ver))
179 .nest_f("HIGH", |ii| self.high.describe(ii, ver));
180 }
181}
182
183impl Describable for Operator {
184 fn describe<PG : ParameterGatherer>(&self, pg: PG, _ver: Version) -> PG{
185 return pg
186 .str("SHAPE", &format!("{:?}", self.shape))
187 .float("RATIO", (self.ratio as f64) + (self.ratio_fine as f64) / 100.0)
188 .hex("LEVEL", self.level)
189 .hex("FBK", self.feedback)
190 .hex("MOD_A", self.mod_a)
191 .hex("MOD_B", self.mod_b);
192 }
193}
194
195impl Describable for FMSynth {
196 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
197 let pg = pg
198 .str(params::NAME, &self.name)
199 .bool(params::TRANSPOSE, self.transpose)
200 .hex(params::EQ, self.synth_params.associated_eq)
201 .hex(params::TBLTIC, self.table_tick)
202 .enumeration("ALG", self.algo.0, self.algo.str())
203 .nest_f("A", |ipg| self.operators[0].describe(ipg, ver))
204 .nest_f("B", |ipg| self.operators[1].describe(ipg, ver))
205 .nest_f("C", |ipg| self.operators[2].describe(ipg, ver))
206 .nest_f("D", |ipg| self.operators[3].describe(ipg,ver));
207
208 let pg = self.synth_params.describe_with_dic(pg, self.filter_types(ver), ver);
209 return describe_modulators(&self.synth_params, pg, self.destination_names(ver), ver);
210 }
211}
212
213impl Describable for Sampler {
214 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
215 let pg = pg
216 .str(params::NAME, &self.name)
217 .bool(params::TRANSPOSE, self.transpose)
218 .hex(params::TBLTIC, self.table_tick)
219 .hex(params::EQ, self.synth_params.associated_eq)
220 .str("SAMPLE", &self.sample_path)
221 .enumeration("PLAY", self.play_mode as u8, &format!("{:?}", self.play_mode))
222 .hex("SLICE", self.slice);
223
224 let pg = match self.play_mode {
225 SamplePlayMode::FWD |
226 SamplePlayMode::REV |
227 SamplePlayMode::FWDLOOP |
228 SamplePlayMode::REVLOOP |
229 SamplePlayMode::FWD_PP |
230 SamplePlayMode::REV_PP |
231 SamplePlayMode::OSC |
232 SamplePlayMode::OSC_REV |
233 SamplePlayMode::OSC_PP => {
234 pg.hex("START", self.start)
235 .hex("LOOP ST", self.loop_start)
236 .hex("LENGTH", self.length)
237 .hex("DETUNE", self.synth_params.pitch)
238 },
239
240 SamplePlayMode::REPITCH |
241 SamplePlayMode::REP_REV |
242 SamplePlayMode::REP_PP => {
243 pg.hex("STEPS", self.synth_params.pitch)
244 .hex("START", self.start)
245 .hex("LOOP ST", self.loop_start)
246 .hex("LENGTH", self.length)
247 },
248
249 SamplePlayMode::REP_BPM |
250 SamplePlayMode::BPM_REV |
251 SamplePlayMode::BPM_PP => {
252 pg.hex("BPM", self.synth_params.pitch)
253 .hex("START", self.start)
254 .hex("LOOP ST", self.loop_start)
255 .hex("LENGTH", self.length)
256 }
257 };
258
259 let pg =
260 pg.hex("DEGRADE", self.degrade);
261
262 let pg = self.synth_params.describe_with_dic(pg, self.filter_types(ver), ver);
263 describe_modulators(&self.synth_params, pg, self.destination_names(ver), ver)
264 }
265}
266
267impl Describable for WavSynth {
268 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
269 let pg = pg
270 .str(params::NAME, &self.name)
271 .bool(params::TRANSPOSE, self.transpose)
272 .hex(params::TBLTIC, self.table_tick)
273 .hex(params::EQ, self.synth_params.associated_eq)
274 .enumeration("SHAPE", self.shape as u8, &format!("{:?}", self.shape))
275 .hex("SIZE", self.size)
276 .hex("MULT", self.mult)
277 .hex("WARP", self.warp)
278 .hex("SCAN", self.scan);
279
280 let pg =
281 self.synth_params.describe_with_dic(pg, self.filter_types(ver), ver);
282
283 describe_modulators(&self.synth_params, pg, self.destination_names(ver), ver)
284 }
285}
286
287impl Describable for Instrument {
288 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
289 match self {
290 Instrument::WavSynth(ws) =>
291 pg.nest_f("WAVSYNTH", |ipg| ws.describe(ipg, ver)),
292 Instrument::MacroSynth(ms) =>
293 pg.nest_f("MACROSYN", |ipg| ms.describe(ipg, ver)),
294 Instrument::Sampler(s) =>
295 pg.nest_f("SAMPLE", |ipg| s.describe(ipg, ver)),
296 Instrument::MIDIOut(mo) =>
297 pg.nest_f("MIDIOUT", |ipg| mo.describe(ipg, ver)),
298 Instrument::FMSynth(fs) =>
299 pg.nest_f("FMSYNTH", |ipg| fs.describe(ipg, ver)),
300 Instrument::HyperSynth(hs) =>
301 pg.nest_f("HYPERSYNTH", |ipg| hs.describe(ipg, ver)),
302 Instrument::External(ex) =>
303 pg.nest_f("EXTERNALINST", |ipg| ex.describe(ipg, ver)),
304 Instrument::None => pg
305 }
306 }
307}
308
309pub fn describe_succint<PG : ParameterGatherer>(instr: &Instrument, pg: PG, ver: Version) -> PG {
310 let (k, common) =
311 match instr {
312 Instrument::WavSynth(ws) => ("WAVSYNTH", Some(&ws.synth_params)),
313 Instrument::MacroSynth(ms) => ("MACROSYN", Some(&ms.synth_params)),
314 Instrument::Sampler(s) => ("SAMPLE", Some(&s.synth_params)),
315 Instrument::MIDIOut(_mo) => ("MIDIOUT", None),
316 Instrument::FMSynth(fs) => ("FMSYNTH", Some(&fs.synth_params)),
317 Instrument::HyperSynth(hs) => ("HYPERSYNTH", Some(&hs.synth_params)),
318 Instrument::External(ex) => ("EXTERNALINST", Some(&ex.synth_params)),
319 Instrument::None => ("NONE", None)
320 };
321
322 let pg = pg.str("KIND", k);
323 match common {
324 None => pg,
325 Some(c) => describe_succint_params(&c, pg, ver)
326 }
327}
328
329impl Describable for ExternalInst {
330 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
331 let port_str = self.human_readable_port();
332 let pg = pg
333 .str(params::NAME, &self.name)
334 .bool(params::TRANSPOSE, self.transpose)
335 .hex(params::EQ, self.synth_params.associated_eq)
336 .hex(params::TBLTIC, self.table_tick)
337
338 .enumeration("PORT", self.port, port_str)
339 .hex("CHANNEL", self.channel)
340 .hex("BANK", self.bank)
341 .hex("PROGRAM", self.program)
342 .nest_f(params::CCA, |ipg| self.cca.describe(ipg, ver))
343 .nest_f(params::CCB, |ipg| self.ccb.describe(ipg, ver))
344 .nest_f(params::CCC, |ipg| self.ccc.describe(ipg, ver))
345 .nest_f(params::CCD, |ipg| self.ccd.describe(ipg, ver));
346
347 let pg =
348 self.synth_params.describe_with_dic(pg, self.filter_types(ver), ver);
349
350 describe_modulators(&self.synth_params, pg, self.destination_names(ver), ver)
351 }
352}
353
354impl Describable for Chord {
355 fn describe<PG : ParameterGatherer>(&self, pg: PG, _ver: Version) -> PG {
356 pg.str("CHD",
357 &format!("{} {} {} {} {} {}",
358 self.offset_str(0),
359 self.offset_str(1),
360 self.offset_str(2),
361 self.offset_str(3),
362 self.offset_str(4),
363 self.offset_str(5)))
364 }
365}
366
367impl Describable for HyperSynth {
368 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
369 let dc = &self.default_chord;
370
371 let pg = pg
372 .str(params::NAME, &self.name)
373 .bool(params::TRANSPOSE, self.transpose)
374 .hex(params::EQ, self.synth_params.associated_eq)
375 .hex(params::SCALE, self.scale)
376 .str("CHORD", &format!("{:02X} | {:02X} {:02X} {:02X} {:02X} {:02X} {:02X}", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]))
377 .hex(params::TBLTIC, self.table_tick)
378 .hex("SHIFT", self.shift)
379 .hex("SWARM", self.swarm)
380 .hex("WIDTH", self.width)
381 .hex("SUBOSC", self.subosc)
382 .nest_f("CHORDS", |ipg| {
383 let mut ipg = ipg;
384
385 for chd in self.chords.iter() {
386 ipg = chd.describe(ipg, ver)
387 };
388
389 ipg
390 });
391
392 let pg =
393 self.synth_params.describe_with_dic(pg, self.filter_types(ver), ver);
394 describe_modulators(&self.synth_params, pg, self.destination_names(ver), ver)
395 }
396}
397
398impl Describable for MacroSynth {
399 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
400 let pg = pg
401 .str(params::NAME, &self.name)
402 .bool(params::TRANSPOSE, self.transpose)
403 .hex(params::EQ, self.synth_params.associated_eq)
404 .hex(params::TBLTIC, self.table_tick)
405 .enumeration("SHAPE", self.shape as u8, &format!("{:?}", self.shape))
406 .hex("TIMBRE", self.timbre)
407 .hex("COLOR", self.color)
408 .hex("DEGRADE", self.degrade)
409 .hex("REDUX", self.redux);
410
411 let pg =
412 self.synth_params.describe_with_dic(pg, self.filter_types(ver), ver);
413
414 describe_modulators(&self.synth_params, pg, self.destination_names(ver), ver)
415 }
416}
417
418impl Describable for ControlChange {
419 fn describe<PG : ParameterGatherer>(&self, pg: PG, _ver: Version) -> PG {
420 return pg
421 .hex("CC", self.number)
422 .hex("VAL", self.value);
423 }
424}
425
426impl Describable for MIDIOut {
427 fn describe<PG : ParameterGatherer>(&self, pg: PG, ver: Version) -> PG {
428 let port_str = self.human_readable_port();
429 let pg = pg
430 .str(params::NAME, &self.name)
431 .bool(params::TRANSPOSE, self.transpose)
432 .hex(params::TBLTIC, self.table_tick)
433
434 .enumeration("PORT", self.port, port_str)
435 .hex("CHANNEL", self.channel)
436 .hex("BANK", self.bank_select)
437 .hex("PROGRAM", self.program_change)
438 .nest_f("CCA", |ipg| self.custom_cc[0].describe(ipg, ver))
439 .nest_f("CCB", |ipg| self.custom_cc[1].describe(ipg, ver))
440 .nest_f("CCC", |ipg| self.custom_cc[2].describe(ipg, ver))
441 .nest_f("CCD", |ipg| self.custom_cc[3].describe(ipg, ver))
442 .nest_f("CCE", |ipg| self.custom_cc[4].describe(ipg, ver))
443 .nest_f("CCF", |ipg| self.custom_cc[5].describe(ipg, ver))
444 .nest_f("CCG", |ipg| self.custom_cc[6].describe(ipg, ver))
445 .nest_f("CCH", |ipg| self.custom_cc[7].describe(ipg, ver))
446 .nest_f("CCI", |ipg| self.custom_cc[8].describe(ipg, ver))
447 .nest_f("CCJ", |ipg| self.custom_cc[9].describe(ipg, ver));
448
449 describe_modulators(&self.mods, pg, self.destination_names(ver), ver)
450 }
451}
452
453impl DescribableWithDictionary for ADSREnv {
454 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, dests: &[&'static str], _ver: Version) -> PG {
455 let dest_str = dests.get(self.dest as usize).unwrap_or(&"??");
456 return pg
457 .enumeration(params::DEST, self.dest, dest_str)
458 .hex(params::AMOUNT, self.amount)
459 .hex(params::ATTACK, self.attack)
460 .hex(params::DECAY, self.decay)
461 .hex(params::SUSTAIN, self.sustain)
462 .hex(params::RELEASE, self.release);
463 }
464}
465
466impl DescribableWithDictionary for AHDEnv {
467 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, dests: &[&'static str], _ver: Version) -> PG{
468 let dest_str = dests.get(self.dest as usize).unwrap_or(&"??");
469 return pg
470 .enumeration(params::DEST, self.dest, dest_str)
471 .hex(params::AMOUNT, self.amount)
472 .hex(params::ATTACK, self.attack)
473 .hex(params::HOLD, self.hold)
474 .hex(params::DECAY, self.decay);
475 }
476}
477
478impl DescribableWithDictionary for DrumEnv {
479 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, dests: &[&'static str], _ver: Version) -> PG {
480 let dest_str = dests.get(self.dest as usize).unwrap_or(&"??");
481 return pg
482 .enumeration(params::DEST, self.dest, dest_str)
483 .hex(params::AMOUNT, self.amount)
484 .hex(params::PEAK, self.peak)
485 .hex(params::BODY, self.body)
486 .hex(params::DECAY, self.decay);
487 }
488}
489
490impl DescribableWithDictionary for LFO {
491 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, dests: &[&'static str], _ver: Version) -> PG {
492 let dest_str = dests.get(self.dest as usize).unwrap_or(&"??");
493 return pg
494 .enumeration(params::DEST, self.dest, dest_str)
495 .enumeration(params::LFOSHAPE, self.shape as u8, &format!("{:?}", self.shape))
496 .hex(params::AMOUNT, self.amount)
497 .hex(params::FREQ, self.freq)
498 .enumeration(params::TRIGGER, self.shape as u8, &format!("{:?}", self.trigger_mode));
499 }
500}
501
502impl DescribableWithDictionary for TrackingEnv {
503 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, dests: &[&'static str], _ver: Version) -> PG {
504 let dest_str = dests.get(self.dest as usize).unwrap_or(&"??");
505 return pg
506 .enumeration(params::DEST, self.dest, dest_str)
507 .hex(params::AMOUNT, self.amount)
508 .hex(params::SOURCE, self.src)
509 .hex("LVAL", self.lval)
510 .hex("HVAL", self.hval);
511 }
512}
513
514impl DescribableWithDictionary for TrigEnv {
515 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, dests: &[&'static str], _ver: Version) -> PG {
516 let dest_str = dests.get(self.dest as usize).unwrap_or(&"??");
517 return pg
518 .enumeration(params::DEST, self.dest, dest_str)
519 .hex(params::AMOUNT, self.amount)
520 .hex(params::ATTACK, self.attack)
521 .hex(params::HOLD, self.hold)
522 .str(params::SOURCE, &format!("{:?}", self.src));
523 }
524}
525
526fn describe_mod<PG : ParameterGatherer>(modulator: &Mod, pg: PG, ix: usize, dests:&[&'static str], ver: Version) -> PG {
527 let ix = ix + 1;
528 match modulator {
529 Mod::AHDEnv(ahd) => {
530 let pg = pg.enumeration(&format!("MOD{ix}"), 0, "AHD ENV");
531 ahd.describe_with_dic(pg, dests, ver)
532 },
533 Mod::ADSREnv(adsr) => {
534 let pg = pg.enumeration(&format!("MOD{ix}"), 1, "ADSR ENV");
535 adsr.describe_with_dic(pg, dests, ver)
536 },
537 Mod::DrumEnv(drum_env) =>{
538 let pg = pg.enumeration(&format!("MOD{ix}"), 1, "DRUM ENV");
539 drum_env.describe_with_dic(pg, dests, ver)
540 }
541 Mod::LFO(lfo) => {
542 let pg = pg.enumeration(&format!("MOD{ix}"), 1, "LFO");
543 lfo.describe_with_dic(pg, dests, ver)
544 }
545 Mod::TrigEnv(tenv) => {
546 let pg = pg.enumeration(&format!("MOD{ix}"), 1, "TRIGENV");
547 tenv.describe_with_dic(pg, dests, ver)
548 }
549 Mod::TrackingEnv(tenv) => {
550 let pg = pg.enumeration(&format!("MOD{ix}"), 1, "TRACKENV");
551 tenv.describe_with_dic(pg, dests, ver)
552 },
553 }
554}
555
556pub fn describe_modulators<PG : ParameterGatherer>(sp: &SynthParams, pg: PG, dests: &[&'static str], ver: Version) -> PG {
557 return pg
558 .nest_f("MOD1", |ipg| describe_mod(&sp.mods[0], ipg, 0, dests, ver))
559 .nest_f("MOD2", |ipg| describe_mod(&sp.mods[1], ipg, 1, dests, ver))
560 .nest_f("MOD3", |ipg| describe_mod(&sp.mods[2], ipg, 2, dests, ver))
561 .nest_f("MOD4", |ipg| describe_mod(&sp.mods[3], ipg, 3, dests, ver));
562}
563
564pub fn describe_succint_params<PG : ParameterGatherer>(sp: &SynthParams, pg: PG, ver: Version) -> PG{
565 return pg
566 .hex(params::EQ, sp.associated_eq)
567 .hex(dests::AMP, sp.amp)
568 .enumeration("LIM", sp.limit.0, sp.limit.str())
569 .hex(dests::PAN, sp.mixer_pan)
570 .hex("DRY", sp.mixer_dry)
571 .hex(if ver.after(&FIRMWARE_6_2_SONG_VERSION) { "MFX" } else { "CHORUS "},
572 sp.mixer_mfx)
573 .hex("DELAY", sp.mixer_delay)
574 .hex("REVERB", sp.mixer_reverb);
575}
576
577impl DescribableWithDictionary for SynthParams {
578 fn describe_with_dic<PG : ParameterGatherer>(&self, pg: PG, filters: &[&str], ver: Version) -> PG {
579 let pg = pg.hex("FINE", self.fine_tune);
580
581 let pg =
582 match filters.get(self.filter_type as usize) {
583 None =>
584 pg.enumeration("FILTER", self.filter_type, &format!("{:02X}", self.filter_type)),
585 Some(str) =>
586 pg.enumeration("FILTER", self.filter_type, str)
587 };
588
589 let pg = pg
590 .hex("CUT", self.filter_cutoff)
591 .hex("RES", self.filter_res);
592
593 describe_succint_params(self, pg, ver)
594 }
595}