Skip to main content

treble_lang/ast/
instrument.rs

1//! Instrument definition AST — the contents of a `def` block.
2//!
3//! These types mirror the shape of an instrument without naming the engine's
4//! own types: this crate has no dependency on the audio engine, so the consumer
5//! lowers a definition onto whatever it builds instruments from. Every field is
6//! optional so a definition can be terse; the consumer supplies the defaults
7//! documented in `LANGUAGE.md` §6.
8
9use super::program::FxCall;
10
11/// A `def <name> { ... }` block.
12#[derive(Debug, Clone, PartialEq, Default)]
13pub struct InstrumentDef {
14    pub name: String,
15    pub voice: Option<VoiceDef>,
16    pub lifecycle: Option<Lifecycle>,
17    /// Oscillators, in mix order.
18    pub tones: Vec<ToneDef>,
19    pub mix: Option<MixMode>,
20    /// The amplitude envelope (`env`).
21    pub amplitude: Option<EnvelopeDef>,
22    /// The optional pitch envelope (`pitchenv`).
23    pub pitch: Option<EnvelopeDef>,
24    pub sample: Option<SampleDef>,
25    /// Ordered effect chain; the same call shape as a pattern's `fx` transform.
26    pub fx: Vec<FxCall>,
27    pub gain: Option<f64>,
28    pub velocity_sensitivity: Option<f64>,
29    pub base_frequency: Option<f64>,
30}
31
32/// `voice mono [notrack] [alloc]` or `voice poly <n> [alloc]`.
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum VoiceDef {
35    Mono {
36        track_pitch: bool,
37        allocation: MonoAllocation,
38    },
39    Poly {
40        voices: u32,
41        allocation: PolyAllocation,
42    },
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
46pub enum MonoAllocation {
47    #[default]
48    Replace,
49    Drop,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
53pub enum PolyAllocation {
54    #[default]
55    ReplaceOldest,
56    ReplaceYoungest,
57    ReplaceLoudest,
58    ReplaceQuietest,
59    ReplaceRandom,
60    Drop,
61}
62
63/// What a note-off does.
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
65pub enum Lifecycle {
66    OneShot,
67    #[default]
68    Gated,
69    Cutoff,
70}
71
72/// How several tones combine.
73///
74/// These are the tone-mixing modes of an instrument. Note that the engine also
75/// has a separate, similarly named set for combining signals arriving at one
76/// graph input; the two are not the same list.
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
78pub enum MixMode {
79    #[default]
80    Sum,
81    Multiply,
82    Max,
83    Average,
84}
85
86/// One oscillator.
87#[derive(Debug, Clone, PartialEq, Default)]
88pub struct ToneDef {
89    pub waveform: Waveform,
90    /// Mix level, lowered to a constant amplitude envelope.
91    pub gain: Option<f64>,
92    /// A fixed frequency in hertz, ignoring the played note.
93    pub frequency: Option<f64>,
94    /// How the tone follows the played note. Mutually exclusive with `frequency`.
95    pub relation: Option<Relation>,
96    pub envelope: Option<EnvelopeDef>,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
100pub enum Waveform {
101    #[default]
102    Sine,
103    Square,
104    Saw,
105    Triangle,
106    SquareRaw,
107    SawRaw,
108    TriangleRaw,
109    Noise,
110    PinkNoise,
111    Blank,
112}
113
114/// How a tone's frequency relates to the played note.
115#[derive(Debug, Clone, Copy, PartialEq)]
116pub enum Relation {
117    Identity,
118    Harmonic(u32),
119    Ratio(f64),
120    Offset(f64),
121    Semitones(i32),
122    Constant(f64),
123}
124
125/// An envelope, in any of the three spellings of §6.5.
126#[derive(Debug, Clone, PartialEq)]
127pub enum EnvelopeDef {
128    /// `adsr <a> <d> <s> <r>`.
129    Adsr {
130        attack: f64,
131        decay: f64,
132        sustain: f64,
133        release: f64,
134    },
135    /// `segment <segment>` — one segment as the whole envelope.
136    Single(SegmentDef),
137    /// Accumulated `attack`/`decay`/`sustain`/`release` stage lines.
138    Stages {
139        attack: Option<SegmentDef>,
140        decay: Option<SegmentDef>,
141        sustain: Option<SegmentDef>,
142        release: Option<SegmentDef>,
143    },
144}
145
146#[derive(Debug, Clone, Copy, PartialEq)]
147pub enum SegmentDef {
148    Linear {
149        from: f64,
150        to: f64,
151        duration: f64,
152    },
153    Bezier {
154        from: f64,
155        to: f64,
156        duration: f64,
157        control: (f64, f64),
158    },
159    Constant {
160        value: f64,
161        duration: Option<f64>,
162    },
163}
164
165/// `sample "<path>" [root N] [start S] [end S] [loop]`.
166#[derive(Debug, Clone, PartialEq, Default)]
167pub struct SampleDef {
168    pub path: String,
169    pub root_midi: Option<u32>,
170    pub start_seconds: Option<f64>,
171    pub end_seconds: Option<f64>,
172    pub looped: bool,
173}