UNPKG

2.82 kBPlain TextView Raw
1import { FrequencyClass } from "../core/type/Frequency.js";
2import { Frequency, Positive, Time } from "../core/type/Units.js";
3import { deepMerge, optionsFromArguments } from "../core/util/Defaults.js";
4import { readOnly, RecursivePartial } from "../core/util/Interface.js";
5import { Monophonic } from "./Monophonic.js";
6import { Synth, SynthOptions } from "./Synth.js";
7import { range, timeRange } from "../core/util/Decorator.js";
8
9export interface MembraneSynthOptions extends SynthOptions {
10 pitchDecay: Time;
11 octaves: Positive;
12}
13
14/**
15 * MembraneSynth makes kick and tom sounds using a single oscillator
16 * with an amplitude envelope and frequency ramp. A Tone.OmniOscillator
17 * is routed through a Tone.AmplitudeEnvelope to the output. The drum
18 * quality of the sound comes from the frequency envelope applied
19 * during MembraneSynth.triggerAttack(note). The frequency envelope
20 * starts at <code>note * .octaves</code> and ramps to <code>note</code>
21 * over the duration of <code>.pitchDecay</code>.
22 * @example
23 * const synth = new Tone.MembraneSynth().toDestination();
24 * synth.triggerAttackRelease("C2", "8n");
25 * @category Instrument
26 */
27export class MembraneSynth extends Synth<MembraneSynthOptions> {
28 readonly name: string = "MembraneSynth";
29
30 /**
31 * The number of octaves the pitch envelope ramps.
32 * @min 0.5
33 * @max 8
34 */
35 @range(0)
36 octaves: Positive;
37
38 /**
39 * The amount of time the frequency envelope takes.
40 * @min 0
41 * @max 0.5
42 */
43 @timeRange(0)
44 pitchDecay: Time;
45
46 /**
47 * Portamento is ignored in this synth. use pitch decay instead.
48 */
49 readonly portamento = 0;
50
51 /**
52 * @param options the options available for the synth see defaults
53 */
54 constructor(options?: RecursivePartial<MembraneSynthOptions>);
55 constructor() {
56 const options = optionsFromArguments(
57 MembraneSynth.getDefaults(),
58 arguments
59 );
60 super(options);
61
62 this.pitchDecay = options.pitchDecay;
63 this.octaves = options.octaves;
64 readOnly(this, ["oscillator", "envelope"]);
65 }
66
67 static getDefaults(): MembraneSynthOptions {
68 return deepMerge(Monophonic.getDefaults(), Synth.getDefaults(), {
69 envelope: {
70 attack: 0.001,
71 attackCurve: "exponential",
72 decay: 0.4,
73 release: 1.4,
74 sustain: 0.01,
75 },
76 octaves: 10,
77 oscillator: {
78 type: "sine",
79 },
80 pitchDecay: 0.05,
81 });
82 }
83
84 setNote(note: Frequency | FrequencyClass, time?: Time): this {
85 const seconds = this.toSeconds(time);
86 const hertz = this.toFrequency(
87 note instanceof FrequencyClass ? note.toFrequency() : note
88 );
89 const maxNote = hertz * this.octaves;
90 this.oscillator.frequency.setValueAtTime(maxNote, seconds);
91 this.oscillator.frequency.exponentialRampToValueAtTime(
92 hertz,
93 seconds + this.toSeconds(this.pitchDecay)
94 );
95 return this;
96 }
97
98 dispose(): this {
99 super.dispose();
100 return this;
101 }
102}