Skip to main content

nord_format/formats/ns3/
synth.rs

1//! The Stage 3 synth preset body (`.ns3y`): 58 bytes.
2//!
3//! The program's synth block under its own tag. ⚠️ The community docs call it a
4//! subset at program `0x0080..0x00AC`; the corpus puts it at program **body**
5//! `0x4f`, found by locating preset content inside programs and confirmed by the
6//! selector check. Panel B's copy sits 263 bytes further on, which is how the
7//! program's two panels were found.
8//!
9//! Field names match [`super::panel::Panel`]'s, so the same parameter reads the
10//! same either side of the tag.
11
12use super::program::{
13    SynthAmpEnvVelocity, SynthArpPattern, SynthArpRange, SynthFilterDrive, SynthFilterKbTrack,
14    SynthFilterType, SynthLfoWave, SynthOscillatorConfig, SynthOscillatorType, SynthUnison,
15    SynthVibrato, SynthVoice,
16};
17use crate::cbin::{self, Cbin};
18use crate::components::{
19    Frequency, Interval, Level, MorphTarget, Rate, SampleRef, Time, WideSelector,
20};
21use crate::error::Error;
22use std::io::{Read, Seek};
23
24pub const FORMAT: &str = "ns3y";
25/// Stored ×100; every corpus specimen holds 3.00.
26pub const KNOWN_VERSIONS: &[u32] = &[300];
27pub const BODY_LEN: usize = 58;
28
29/// The 58-byte preset body: the program's synth block under its own tag.
30///
31/// Reads and writes byte-exactly. A read verifies the container checksum, gates
32/// on [`KNOWN_VERSIONS`], and range-checks every field; unclaimed bits survive a
33/// re-encode verbatim. Placement located in the corpus (see the [module
34/// docs](self)). Inferred from specimens; not confirmed on hardware.
35#[nord_bits_derive::bitbody(58)]
36pub struct SynthPreset {
37    #[bits(40..=40)]
38    pub synth_kb_hold: bool,
39    #[bits(41..=41)]
40    pub synth_arp_on: bool,
41    #[bits(42..=42)]
42    pub synth_arp_kb_sync: bool,
43    #[bits(43..=44)]
44    pub synth_arp_range: SynthArpRange,
45    #[bits(45..=46)]
46    pub synth_arp_pattern: SynthArpPattern,
47    #[bits(47..=47)]
48    pub synth_arp_master_clock: bool,
49    #[bits(48..=54)]
50    pub synth_arp_rate: Time,
51    #[bits(55..=62)]
52    pub synth_arp_rate_wheel: MorphTarget,
53    #[bits(63..=70)]
54    pub synth_arp_rate_aftertouch: MorphTarget,
55    #[bits(71..=78)]
56    pub synth_arp_rate_ctrl_pedal: MorphTarget,
57    #[bits(79..=80)]
58    pub synth_voice: SynthVoice,
59    #[bits(81..=87)]
60    pub synth_glide: Time,
61    #[bits(88..=89)]
62    pub synth_unison: SynthUnison,
63    #[bits(90..=92)]
64    pub synth_vibrato: SynthVibrato,
65    #[bits(93..=95)]
66    pub synth_lfo_wave: SynthLfoWave,
67    #[bits(96..=96)]
68    pub synth_lfo_master_clock: bool,
69    #[bits(97..=103)]
70    pub synth_lfo_rate: Rate,
71    #[bits(104..=111)]
72    pub synth_lfo_rate_wheel: MorphTarget,
73    #[bits(112..=119)]
74    pub synth_lfo_rate_aftertouch: MorphTarget,
75    #[bits(120..=127)]
76    pub synth_lfo_rate_ctrl_pedal: MorphTarget,
77    #[bits(128..=134)]
78    pub synth_mod_env_attack: Time,
79    #[bits(135..=141)]
80    pub synth_mod_env_decay: Time,
81    #[bits(142..=148)]
82    pub synth_mod_env_release: Time,
83    #[bits(149..=149)]
84    pub synth_mod_env_velocity: bool,
85    #[bits(150..=152)]
86    pub synth_oscillator_type: SynthOscillatorType,
87    #[bits(153..=161)]
88    pub synth_oscillator_1_wave_form: WideSelector<9>,
89    #[bits(163..=166)]
90    pub synth_oscillator_config: SynthOscillatorConfig,
91    #[bits(167..=172)]
92    pub synth_pitch: Interval,
93    #[bits(173..=179)]
94    pub synth_oscillator_control: Level,
95    #[bits(180..=187)]
96    pub synth_oscillator_control_wheel: MorphTarget,
97    #[bits(188..=195)]
98    pub synth_oscillator_control_aftertouch: MorphTarget,
99    #[bits(196..=203)]
100    pub synth_oscillator_control_ctrl_pedal: MorphTarget,
101    #[bits(204..=210)]
102    pub synth_oscillator_mod: Level,
103    #[bits(211..=218)]
104    pub synth_oscillator_mod_wheel: MorphTarget,
105    #[bits(219..=226)]
106    pub synth_oscillator_mod_aftertouch: MorphTarget,
107    #[bits(227..=234)]
108    pub synth_oscillator_mod_ctrl_pedal: MorphTarget,
109    #[bits(235..=237)]
110    pub synth_filter_type: SynthFilterType,
111    #[bits(238..=244)]
112    pub synth_filter_freq: Frequency,
113    #[bits(245..=252)]
114    pub synth_filter_freq_wheel: MorphTarget,
115    #[bits(253..=260)]
116    pub synth_filter_freq_aftertouch: MorphTarget,
117    #[bits(261..=268)]
118    pub synth_filter_freq_ctrl_pedal: MorphTarget,
119    #[bits(269..=275)]
120    pub synth_filter_hp_freq_res: Level,
121    #[bits(276..=283)]
122    pub synth_filter_hp_freq_res_wheel: MorphTarget,
123    #[bits(284..=291)]
124    pub synth_filter_hp_freq_res_aftertouch: MorphTarget,
125    #[bits(292..=299)]
126    pub synth_filter_hp_freq_res_ctrl_pedal: MorphTarget,
127    #[bits(300..=306)]
128    pub synth_filter_lfo_amount: Level,
129    #[bits(307..=314)]
130    pub synth_filter_lfo_amount_wheel: MorphTarget,
131    #[bits(315..=322)]
132    pub synth_filter_lfo_amount_aftertouch: MorphTarget,
133    #[bits(323..=330)]
134    pub synth_filter_lfo_amount_ctrl_pedal: MorphTarget,
135    #[bits(331..=337)]
136    pub synth_filter_vel_mod_env_amount: Level,
137    #[bits(338..=339)]
138    pub synth_filter_kb_track: SynthFilterKbTrack,
139    #[bits(340..=341)]
140    pub synth_filter_drive: SynthFilterDrive,
141    #[bits(342..=348)]
142    pub synth_amp_env_attack: Time,
143    #[bits(349..=355)]
144    pub synth_amp_env_decay: Time,
145    #[bits(356..=362)]
146    pub synth_amp_env_release: Time,
147    #[bits(363..=364)]
148    pub synth_amp_env_velocity: SynthAmpEnvVelocity,
149    #[bits(365..=396)]
150    pub synth_sample_id: SampleRef,
151    #[bits(397..=397)]
152    pub synth_fast_attack: bool,
153}
154
155pub fn read_from(reader: &mut (impl Read + Seek)) -> Result<Cbin<SynthPreset>, Error> {
156    let file: Cbin<SynthPreset> = cbin::read(reader, FORMAT)?;
157    crate::formats::known_version(FORMAT, file.header.version, KNOWN_VERSIONS)?;
158    Ok(file)
159}