Moved Filters to separate page and fixed comp

This commit is contained in:
2023-12-11 00:07:05 +02:00
parent 9328a14de4
commit aef26b0811
10 changed files with 221 additions and 286 deletions

View File

@ -165,7 +165,8 @@
<p rel="noopener noreferrer" id="docs_amplitude" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Amplitude</p>
<p rel="noopener noreferrer" id="docs_sampler" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Sampler</p>
<p rel="noopener noreferrer" id="docs_synths" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Synths</p>
<p rel="noopener noreferrer" id="docs_reverb_delay" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Effects</p>
<p rel="noopener noreferrer" id="docs_filters" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Filters</p>
<p rel="noopener noreferrer" id="docs_effects" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Effects</p>
</div>
</details>
@ -174,7 +175,6 @@
<summary class="ml-2 lg:text-xl pb-1 pt-1 text-white">Samples</summary>
<div class="flex flex-col">
<p rel="noopener noreferrer" id="docs_sample_list" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">List of samples</p>
<p rel="noopener noreferrer" id="docs_sample_controls" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Controlling samples</p>
<p rel="noopener noreferrer" id="docs_loading_samples" class="ml-8 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">External samples</p>
</div>
</details>

View File

@ -3,12 +3,11 @@ import { type Editor } from "./main";
import { introduction } from "./documentation/basics/welcome";
import { loading_samples } from "./documentation/learning/samples/loading_samples";
import { amplitude } from "./documentation/learning/audio_engine/amplitude";
import { reverb } from "./documentation/learning/audio_engine/reverb_delay";
import { effects } from "./documentation/learning/audio_engine/effects";
import { sampler } from "./documentation/learning/audio_engine/sampler";
import { sample_banks } from "./documentation/learning/samples/sample_banks";
import { audio_basics } from "./documentation/learning/audio_engine/audio_basics";
import { sample_list } from "./documentation/learning/samples/sample_list";
import { sample_controls } from "./documentation/learning/samples/sample_controls";
import { software_interface } from "./documentation/basics/interface";
import { shortcuts } from "./documentation/basics/keyboard";
import { code } from "./documentation/basics/code";
@ -44,6 +43,7 @@ import { synths } from "./documentation/learning/audio_engine/synths";
import showdown from "showdown";
import showdownHighlight from "showdown-highlight";
import { createDocumentationStyle } from "./DomElements";
import { filters } from "./documentation/learning/audio_engine/filters";
showdown.setFlavor("github");
export const key_shortcut = (shortcut: string): string => {
@ -94,6 +94,7 @@ export const documentation_factory = (application: Editor) => {
cyclic: cyclical_time(application),
longform: long_forms(application),
synths: synths(application),
filters: filters(application),
chaining: chaining(application),
patterns: patterns(application),
ziffers_basics: ziffers_basics(application),
@ -109,7 +110,7 @@ export const documentation_factory = (application: Editor) => {
functions: functions(application),
shortcuts: shortcuts(application),
amplitude: amplitude(application),
reverb_delay: reverb(application),
effects: effects(application),
sampler: sampler(application),
mouse: mouse(application),
oscilloscope: oscilloscope(application),
@ -118,7 +119,6 @@ export const documentation_factory = (application: Editor) => {
bonus: bonus(application),
sample_list: sample_list(application),
sample_banks: sample_banks(application),
sample_controls: sample_controls(application),
loading_samples: loading_samples(application),
about: about(),
};

View File

@ -491,7 +491,8 @@ export const installInterfaceLogic = (app: Editor) => {
"sampler",
"amplitude",
"audio_basics",
"reverb_delay",
"filters",
"effects",
"interface",
"interaction",
"code",
@ -521,7 +522,6 @@ export const installInterfaceLogic = (app: Editor) => {
"oscilloscope",
"sample_list",
"loading_samples",
"sample_controls",
].forEach((e) => {
let name = `docs_` + e;
document.getElementById(name)!.addEventListener("click", async () => {

View File

@ -311,7 +311,7 @@ export class SoundEvent extends AudibleEvent {
self.updateValue("roomsize", value);
return self;
},
comp: ["compressor", "cmp"],
comp: ["comp","compressor", "cmp"],
ratio: function (self: SoundEvent, value: number) {
self.updateValue("compressorRatio", value);
return self;

View File

@ -898,12 +898,6 @@ const completionDatabase: CompletionDatabase = {
description: "Detects if the Alt key is pressed",
example: "fill() ? 1 : 0.5",
},
comp: {
name: "comp",
category: "synthesis",
description: "Compressor threshold (dB)",
example: "sound('sine').comp(-4).out()",
},
ratio: {
name: "ratio",
category: "synthesis",

View File

@ -33,42 +33,43 @@ beat(.5)::snd('cp').vel($(1)%10 / 10).out()`,
| <ic>decay</ic> | dec | Decay value (time to decay to sustain level) |
| <ic>sustain</ic> | sus | Sustain value (gain when sound is held) |
| <ic>release</ic> | rel | Release value (time for the sound to die off) |
| <ic>adsr</ic> | | Shortcut that combines all the parameters together |
Note that the **sustain** value is not a duration but an amplitude value (how loud). The other values are the time for each stage to take place. Here is a fairly complete example using the <ic>sawtooth</ic> basic waveform.
${makeExample(
"Simple synthesizer",
`
let smooth = (sound) => {
return sound.cutoff(r(100,500))
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
.gain(r(0.25, 0.4)).adsr(0, r(.2,.4), r(0,0.5), 0)
.room(0.9).size(2).o(2).vib(r(2,8)).vibmod(0.125)
}
beat(.25)::smooth(sound('sawtooth')
.note([50,57,55,60].beat(1))).out();
beat(.25)::smooth(sound('sawtooth')
.note([50,57,55,60].add(12).beat(1.5))).out();
register("smooth", x => x.cutoff(r(100,500))
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
.gain(r(0.25, 0.4)).adsr(0, r(.2,.4), r(0,0.5), 0)
.room(0.9).size(2).o(2).vib(r(2,8)).vibmod(0.125))
beat(.25)::sound('sawtooth')
.note([50,57,55,60].beat(1))
.smooth().out();
beat(.25)::sound('sawtooth')
.note([50,57,55,60].add(12).beat(1.5))
.smooth().out();
`,
true,
)};
Sometimes, using a full ADSR envelope is a bit overkill. There are other simpler controls to manipulate the envelope like the <ic>.ad</ic> method:
${makeExample(
"Replacing .adsr by .ad",
`
let smooth = (sound) => {
return sound.cutoff(r(100,500))
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
.gain(r(0.25, 0.4)).ad(0, .25)
.room(0.9).size(2).o(2).vib(r(2,8)).vibmod(0.125)
}
beat(.25)::smooth(sound('sawtooth')
.note([50,57,55,60].beat(1))).out();
beat(.25)::smooth(sound('sawtooth')
.note([50,57,55,60].add(12).beat(1.5))).out();
register("smooth", x => x.cutoff(r(100,500))
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
.gain(r(0.25, 0.4)).ad(0, 0.25)
.room(0.9).size(2).o(2).vib(r(2,8)).vibmod(0.125))
beat(.25)::sound('sawtooth')
.note([50,57,55,60].beat(1))
.smooth().out();
beat(.25)::sound('sawtooth')
.note([50,57,55,60].add(12).beat(1.5))
.smooth().out();
`,
true,
)};

View File

@ -1,7 +1,7 @@
import { type Editor } from "../../../main";
import { makeExampleFactory } from "../../../Documentation";
export const reverb = (application: Editor): string => {
export const effects = (application: Editor): string => {
// @ts-ignore
const makeExample = makeExampleFactory(application);
return `
@ -90,5 +90,34 @@ beat(.5)::snd('pad').crush([16, 8, 4].beat(2)).clip(.5).out()
`,
true,
)};
## Vibrato
You can also add some amount of vibrato to the sound using the <ic>vib</ic> and <ic>vibmod</ic> methods. These can turn any oscillator into something more lively and/or into a sound effect when used with a high amount of modulation.
${makeExample(
"Different vibrato settings",
`
tempo(140);
beat(1) :: sound('triangle')
.freq(400).release(0.2)
.vib([1/2, 1, 2, 4].beat())
.vibmod([1,2,4,8].beat(2))
.out()`,
true,
)}
## Compression
This effect is leveraging the basic WebAudio compressor. More information can be found about it on the [DynamicsCompressorNode](https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNode?retiredLocale=de#instance_properties) page. This can be come quite complex :)
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>comp</ic> | cmp | Compressor threshold value (dB) over which compressor operates |
| <ic>ratio</ic> | rt | Compressor ratio: input amount in dB needed for 1dB change in the output |
| <ic>knee</ic> | kn | dB value defining the range over which the signal transitions to compressed section |
| <ic>compAttack</ic> | cmpa | In seconds, time to decrease the gain by 10db |
| <ic>compRelease</ic> | cmpr | In seconds, time to increase the gain by 10db |
`;
};

View File

@ -0,0 +1,145 @@
import { type Editor } from "../../../main";
import { makeExampleFactory } from "../../../Documentation";
export const filters = (application: Editor): string => {
const makeExample = makeExampleFactory(application);
return `
# Filters
Filters can be applied to both synthesizers and samples. They are used to shape the sound by removing or emphasizing certain frequencies. They are also used to create movement in the sound by modulating the cutoff frequency of the filter over time.
- **lowpass filter**: filters the high frequencies, keeping the low frequencies.
- **highpass filter**: filtering the low frequencies, keeping the high frequencies.
- **bandpass filter**: filters the low and high frequencies around a frequency band, keeping what's in the middle.
${makeExample(
"Filtering the high frequencies of an oscillator",
`beat(.5) :: sound('sawtooth').cutoff(50 + usine(1/8) * 2000).out()`,
true,
)}
These filters all come with their own set of parameters. Note that we are describing the parameters of the three different filter types here. Choose the right parameters depending on the filter type you are using:
### Lowpass filter
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>cutoff</ic> | <ic>lpf</ic> | cutoff frequency of the lowpass filter |
| <ic>resonance</ic> | <ic>lpq</ic> | resonance of the lowpass filter (0-1) |
${makeExample(
"Filtering a bass",
`beat(.5) :: sound('jvbass').lpf([250,1000,8000].beat()).out()`,
true,
)}
### Highpass filter
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>hcutoff</ic> | <ic>hpf</ic> | cutoff frequency of the highpass filter |
| <ic>hresonance</ic> | <ic>hpq</ic> | resonance of the highpass filter (0-1) |
${makeExample(
"Filtering a noise source",
`beat(.5) :: sound('gtr').hpf([250,1000, 2000, 3000, 4000].beat()).end(0.5).out()`,
true,
)}
### Bandpass filter
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>bandf</ic> | <ic>bpf</ic> | cutoff frequency of the bandpass filter |
| <ic>bandq</ic> | <ic>bpq</ic> | resonance of the bandpass filter (0-1) |
${makeExample(
"Sweeping the filter on the same guitar sample",
`beat(.5) :: sound('gtr').bandf(100 + usine(1/8) * 4000).end(0.5).out()`,
true,
)}
Alternatively, <ic>lpf</ic>, <ic>hpf</ic> and <ic>bpf</ic> can take a second argument, the **resonance**.
## Filter order (type)
You can also use the <ic>ftype</ic> method to change the filter type (order). There are two types by default, <ic>12db</ic> for a gentle slope or <ic>24db</ic> for a really steep filtering slope. The <ic>24db</ic> type is particularly useful for substractive synthesis if you are trying to emulate some of the Moog or Prophet sounds:
- <ic>ftype(type: string)</ic>: sets the filter type (order), either <ic>12db</ic> or <ic>24db</ic>.
${makeExample(
"Filtering a bass",
`beat(.5) :: sound('jvbass').ftype(['12db', '24db'].beat(4)).lpf([250,1000,8000].beat()).out()`,
true,
)}
## Filter envelopes
The examples we have studied so far are static. They filter the sound around a fixed cutoff frequency. To make the sound more interesting, you can use the ADSR filter envelopes to shape the filter cutoff frequency over time. You will always find amplitude and filter envelopes on most commercial synthesizers. This is done using the following methods:
### Lowpass envelope
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>lpenv</ic> | <ic>lpe</ic> | lowpass frequency modulation amount (negative or positive) |
| <ic>lpattack</ic> | <ic>lpa</ic> | attack of the lowpass filter |
| <ic>lpdecay</ic> | <ic>lpd</ic> | decay of the lowpass filter |
| <ic>lpsustain</ic> | <ic>lps</ic> | sustain of the lowpass filter |
| <ic>lprelease</ic> | <ic>lpr</ic> | release of the lowpass filter |
| <ic>lpadsr</ic> | | (**takes five arguments**) set all the parameters |
${makeExample(
"Filtering a sawtooth wave dynamically",
`beat(.5) :: sound('sawtooth').note([48,60].beat())
.cutoff(5000).lpa([0.05, 0.25, 0.5].beat(2))
.lpenv(-8).lpq(10).out()`,
true,
)}
### Highpass envelope
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>hpenv</ic> | <ic>hpe</ic> | highpass frequency modulation amount (negative or positive) |
| <ic>hpattack</ic> | <ic>hpa</ic> | attack of the highpass filter |
| <ic>hpdecay</ic> | <ic>hpd</ic> | decay of the highpass filter |
| <ic>hpsustain</ic> | <ic>hps</ic> | sustain of the highpass filter |
| <ic>hprelease</ic> | <ic>hpr</ic> | release of the highpass filter |
| <ic>hpadsr</ic> | | (**takes five arguments**) set all the parameters |
${makeExample(
"Let's use another filter using the same example",
`beat(.5) :: sound('sawtooth').note([48,60].beat())
.hcutoff(1000).hpa([0.05, 0.25, 0.5].beat(2))
.hpenv(8).hpq(10).out()`,
true,
)}
### Bandpass envelope
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>bpenv</ic> | <ic>bpe</ic> | bandpass frequency modulation amount (negative or positive) |
| <ic>bpattack</ic> | <ic>bpa</ic> | attack of the bandpass filter |
| <ic>bpdecay</ic> | <ic>bpd</ic> | decay of the bandpass filter |
| <ic>bpsustain</ic> | <ic>bps</ic> | sustain of the bandpass filter |
| <ic>bprelease</ic> | <ic>bpr</ic> | release of the bandpass filter |
| <ic>bpadsr</ic> | | (**takes five arguments**) set all the parameters |
${makeExample(
"And the bandpass filter, just for fun",
`beat(.5) :: sound('sawtooth').note([48,60].beat())
.bandf([500,1000,2000].beat(2))
.bpa([0.25, 0.125, 0.5].beat(2) * 4)
.bpenv(-4).release(2).out()
`,
true,
)}
`;
};

View File

@ -22,7 +22,6 @@ beat(.5) && snd(['sine', 'triangle', 'sawtooth', 'square'].beat()).freq(100).out
Note that you can also use noise if you do not want to use a periodic oscillator:
${makeExample(
"Listening to the different types of noise",
`
@ -69,43 +68,9 @@ ${makeExample(
beat(.5) && snd('triangle').chord(60,64,67,72).invert([1,-3,4,-5].pick()).adsr(0,.2).out()
`,
true,
)}
## Vibrato
You can also add some amount of vibrato to the sound using the <ic>vib</ic> and <ic>vibmod</ic> methods. These can turn any oscillator into something more lively and/or into a sound effect when used with a high amount of modulation.
${makeExample(
"Different vibrato settings",
`
tempo(140);
beat(1) :: sound('triangle')
.freq(400).release(0.2)
.vib([1/2, 1, 2, 4].beat())
.vibmod([1,2,4,8].beat(2))
.out()`,
true,
)}
## Noise
A certain amount of brown noise can be added by using the <ic>.noise</ic> key:
${makeExample(
"Different vibrato settings",
`
tempo(140);
beat(1) :: sound('triangle')
.freq(400).release(0.2)
.noise([0.2,0.4,0.5].bar())
.vib([1/2, 1, 2, 4].beat())
.vibmod([1,2,4,8].beat(2))
.out()`,
true,
)}
## Controlling the amplitude
# Controlling amplitude
Controlling the amplitude and duration of the sound can be done using various techniques. The most important thing to learn is probably how set the amplitude (volume) of your synthesizer:
- <ic>gain(gain: number)</ic>: sets the gain of the oscillator.
@ -123,6 +88,8 @@ ${makeExample(
true,
)}
## Envelopes
<div class="mt-4 mb-4 lg:grid lg:grid-cols-4 lg:gap-4">
<img class="col-span-1 lg:ml-12 bg-gray-100 rounded-lg px-2 py-2", src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/ADSR_Envelope_Graph.svg/1280px-ADSR_Envelope_Graph.svg.png" width="400" />
<z class="pl-8 lg:text-2xl text-base text-white lg:mx-6 mx-2 my-4 leading-normal col-span-3 ">Synthesizers typically come with an amplitude envelope that can help you to shape the sound with a slow attack or long release. This is done in Topos using the amplitude envelope, composed of four parameters: <ic>attack</ic>, <ic>decay</ic>, <ic>sustain</ic> and <ic>release</ic>:</z>
@ -178,9 +145,7 @@ beat(0.5) :: sound('wt_piano')
The most basic synthesis technique used since the 1970s is called substractive synthesis. This technique is based on the use of rich sound sources (oscillators) as a base to build rich and moving timbres. Because rich sources contain a lot of different harmonics, you might want to filter some of them to obtain the timbre you are looking for. To do so, Topos comes with a set of basic filters that can be used to shape the sound exactly to your liking. There are three filter types by defaut, with more to be added in the future:
- **lowpass filter**: filters the high frequencies, keeping the low frequencies.
- **highpass filter**: filtering the low frequencies, keeping the high frequencies.
- **bandpass filter**: filters the low and high frequencies around a frequency band, keeping what's in the middle.
See the Filters page for details on lowpass, highpass and bandpass filters. I also encourage you to study these simple examples to get more familiar with the construction of basic substractive synthesizers:
${makeExample(
"Filtering the high frequencies of an oscillator",
@ -188,64 +153,6 @@ ${makeExample(
true,
)}
These filters all come with their own set of parameters. Note that we are describing the parameters of the three different filter types here. Choose the right parameters depending on the filter type you are using:
### Lowpass filter
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>cutoff</ic> | <ic>lpf</ic> | cutoff frequency of the lowpass filter |
| <ic>resonance</ic> | <ic>lpq</ic> | resonance of the lowpass filter (0-1) |
${makeExample(
"Filtering a bass",
`beat(.5) :: sound('jvbass').lpf([250,1000,8000].beat()).out()`,
true,
)}
### Highpass filter
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>hcutoff</ic> | <ic>hpf</ic> | cutoff frequency of the highpass filter |
| <ic>hresonance</ic> | <ic>hpq</ic> | resonance of the highpass filter (0-1) |
${makeExample(
"Filtering a noise source",
`beat(.5) :: sound('gtr').hpf([250,1000, 2000, 3000, 4000].beat()).end(0.5).out()`,
true,
)}
### Bandpass filter
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>bandf</ic> | <ic>bpf</ic> | cutoff frequency of the bandpass filter |
| <ic>bandq</ic> | <ic>bpq</ic> | resonance of the bandpass filter (0-1) |
${makeExample(
"Sweeping the filter on the same guitar sample",
`beat(.5) :: sound('gtr').bandf(100 + usine(1/8) * 4000).end(0.5).out()`,
true,
)}
Alternatively, <ic>lpf</ic>, <ic>hpf</ic> and <ic>bpf</ic> can take a second argument, the **resonance**.
## Filter order (type)
You can also use the <ic>ftype</ic> method to change the filter type (order). There are two types by default, <ic>12db</ic> for a gentle slope or <ic>24db</ic> for a really steep filtering slope. The <ic>24db</ic> type is particularly useful for substractive synthesis if you are trying to emulate some of the Moog or Prophet sounds:
- <ic>ftype(type: string)</ic>: sets the filter type (order), either <ic>12db</ic> or <ic>24db</ic>.
${makeExample(
"Filtering a bass",
`beat(.5) :: sound('jvbass').ftype(['12db', '24db'].beat(4)).lpf([250,1000,8000].beat()).out()`,
true,
)}
I also encourage you to study these simple examples to get more familiar with the construction of basic substractive synthesizers:
${makeExample(
"Simple synthesizer voice with filter",
`
@ -282,73 +189,23 @@ beat(1/8)::sound('sine')
false,
)}
## Filter envelopes
The examples we have studied so far are static. They filter the sound around a fixed cutoff frequency. To make the sound more interesting, you can use the ADSR filter envelopes to shape the filter cutoff frequency over time. You will always find amplitude and filter envelopes on most commercial synthesizers. This is done using the following methods:
### Lowpass envelope
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>lpenv</ic> | <ic>lpe</ic> | lowpass frequency modulation amount (negative or positive) |
| <ic>lpattack</ic> | <ic>lpa</ic> | attack of the lowpass filter |
| <ic>lpdecay</ic> | <ic>lpd</ic> | decay of the lowpass filter |
| <ic>lpsustain</ic> | <ic>lps</ic> | sustain of the lowpass filter |
| <ic>lprelease</ic> | <ic>lpr</ic> | release of the lowpass filter |
| <ic>lpadsr</ic> | | (**takes five arguments**) set all the parameters |
## Noise
A certain amount of brown noise can be added by using the <ic>.noise</ic> key:
${makeExample(
"Filtering a sawtooth wave dynamically",
`beat(.5) :: sound('sawtooth').note([48,60].beat())
.cutoff(5000).lpa([0.05, 0.25, 0.5].beat(2))
.lpenv(-8).lpq(10).out()`,
"Different vibrato settings",
`
tempo(140);
beat(1) :: sound('triangle')
.freq(400).release(0.2)
.noise([0.2,0.4,0.5].bar())
.vib([1/2, 1, 2, 4].beat())
.vibmod([1,2,4,8].beat(2))
.out()`,
true,
)}
### Highpass envelope
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>hpenv</ic> | <ic>hpe</ic> | highpass frequency modulation amount (negative or positive) |
| <ic>hpattack</ic> | <ic>hpa</ic> | attack of the highpass filter |
| <ic>hpdecay</ic> | <ic>hpd</ic> | decay of the highpass filter |
| <ic>hpsustain</ic> | <ic>hps</ic> | sustain of the highpass filter |
| <ic>hprelease</ic> | <ic>hpr</ic> | release of the highpass filter |
| <ic>hpadsr</ic> | | (**takes five arguments**) set all the parameters |
${makeExample(
"Let's use another filter using the same example",
`beat(.5) :: sound('sawtooth').note([48,60].beat())
.hcutoff(1000).hpa([0.05, 0.25, 0.5].beat(2))
.hpenv(8).hpq(10).out()`,
true,
)}
### Bandpass envelope
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>bpenv</ic> | <ic>bpe</ic> | bandpass frequency modulation amount (negative or positive) |
| <ic>bpattack</ic> | <ic>bpa</ic> | attack of the bandpass filter |
| <ic>bpdecay</ic> | <ic>bpd</ic> | decay of the bandpass filter |
| <ic>bpsustain</ic> | <ic>bps</ic> | sustain of the bandpass filter |
| <ic>bprelease</ic> | <ic>bpr</ic> | release of the bandpass filter |
| <ic>bpadsr</ic> | | (**takes five arguments**) set all the parameters |
${makeExample(
"And the bandpass filter, just for fun",
`beat(.5) :: sound('sawtooth').note([48,60].beat())
.bandf([500,1000,2000].beat(2))
.bpa([0.25, 0.125, 0.5].beat(2) * 4)
.bpenv(-4).release(2).out()
`,
true,
)}
## Wavetable synthesis
Topos can also do wavetable synthesis. Wavetable synthesis allows you to use any sound file as a source to build an oscillator. By default, Topos comes with more than 1000 waveforms thanks to the awesome [AKWF](https://www.adventurekid.se/akrt/waveforms/adventure-kid-waveforms/) pack made by Kristoffer Ekstrand. Any sample name that contains <ic>wt_</ic> as a prefix will be interpreted by the sampler as a wavetable and thus as an oscillator. See for yourself:

View File

@ -1,91 +0,0 @@
import { type Editor } from "../../../main";
import { makeExampleFactory } from "../../../Documentation";
export const sample_controls = (application: Editor): string => {
const makeExample = makeExampleFactory(application);
return `
## Sample Controls
There are some basic controls over the playback of each sample. This allows you to get into more serious sampling if you take the time to really work with your audio materials.
| Method | Alias | Description |
|---------|-------|--------------------------------------------------------|
| <ic>n</ic> | | Select a sample in the current folder (from <ic>0</ic> to infinity) |
| <ic>begin</ic> | | Beginning of the sample playback (between <ic>0</ic> and <ic>1</ic>) |
| <ic>end</ic> | | End of the sample (between <ic>0</ic> and <ic>1</ic>) |
| <ic>loopBegin</ic> | | Beginning of the loop section (between <ic>0</ic> and <ic>1</ic>) |
| <ic>loopEnd</ic> | | End of the loop section (between <ic>0</ic> and <ic>1</ic>) |
| <ic>loop</ic> | | Whether to loop or not the audio sample |
| <ic>stretch</ic> | | Stretches the audio playback rate of a sample over <ic>n</ic> beats |
| <ic>speed</ic> | | Playback speed (<ic>2</ic> = twice as fast) |
| <ic>cut</ic> | | Set with <ic>0</ic> or <ic>1</ic>. Will cut the sample as soon as another sample is played on the same bus |
| <ic>clip</ic> | | Multiply the duration of the sample with the given number |
| <ic>pan</ic> | | Stereo position of the audio playback (<ic>0</ic> = left, <ic>1</ic> = right)|
${makeExample(
"Complex sampling duties",
`
// Using some of the modifiers described above :)
beat(.5)::snd('pad').begin(0.2)
.speed([1, 0.9, 0.8].beat(4))
.n(2).pan(usine(.5))
.end(rand(0.3,0.8))
.room(0.8).size(0.5)
.clip(1).out()
`,
true,
)};
${makeExample(
"Playing an amen break",
`
// Note that stretch has the same value as beat
beat(4) :: sound('amen1').n(11).stretch(4).out()
beat(1) :: sound('kick').shape(0.35).out()`,
true,
)};
## Filters
There are three basic filters: a _lowpass_, _highpass_ and _bandpass_ filters with rather soft slope. Each of them can take up to two arguments. You can also use only the _cutoff_ frequency and the resonance will stay to its default nominal value. You will learn more about the usage of filters in the synths page!
| Method | Alias | Description |
|------------|-------|-----------------------------------------|
| <ic>cutoff</ic> | lpf | Cutoff frequency of the lowpass filter |
| <ic>resonance</ic> | lpq | Resonance of the lowpass filter |
| <ic>hcutoff</ic> | hpf | Cutoff frequency of the highpass filter |
| <ic>hresonance</ic> | hpq | Resonance of the highpass filter |
| <ic>bandf</ic> | bpf | Cutoff frequency of the bandpass filter |
| <ic>bandq</ic> | bpq | Resonance of the bandpass filter |
| <ic>vowel</ic> | | Formant filter with (vocal quality) |
${makeExample(
"Filter sweep using a low frequency oscillator",
`
beat(.5) && snd('sawtooth')
.cutoff([2000,500].pick() + usine(.5) * 4000)
.resonance(0.9).freq([100,150].pick())
.out()
`,
true,
)};
## Compression
This effect is leveraging the basic WebAudio compressor. More information can be found about it on the [DynamicsCompressorNode](https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNode?retiredLocale=de#instance_properties) page. This can be come quite complex :)
| Method | Alias | Description |
|------------|-----------|---------------------------------|
| <ic>comp</ic> | cmp | Compressor threshold value (dB) over which compressor operates |
| <ic>ratio</ic> | rt | Compressor ratio: input amount in dB needed for 1dB change in the output |
| <ic>knee</ic> | kn | dB value defining the range over which the signal transitions to compressed section |
| <ic>compAttack</ic> | cmpa | In seconds, time to decrease the gain by 10db |
| <ic>compRelease</ic> | cmpr | In seconds, time to increase the gain by 10db |
`;
};