Merge branch 'main' into 58-support-for-external-midi-clock
This commit is contained in:
@ -57,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<body class="z-0 bg-neutral-800 overflow-y-hidden">
|
<body id="all" class="z-0 bg-neutral-800 overflow-y-hidden">
|
||||||
|
|
||||||
<!-- The header is hidden on smaller devices -->
|
<!-- The header is hidden on smaller devices -->
|
||||||
<header class="py-2 block text-white bg-neutral-900">
|
<header class="py-2 block text-white bg-neutral-900">
|
||||||
@ -99,7 +99,6 @@
|
|||||||
<p class="hidden lg:block text-xl pl-2 text-white inline-block">Clear</p>
|
<p class="hidden lg:block text-xl pl-2 text-white inline-block">Clear</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
<a title="Share button" id="share-button" class="flex flex-row mr-2 hover:text-gray-900 hover:bg-gray-800 px-2 py-2 rounded-lg">
|
<a title="Share button" id="share-button" class="flex flex-row mr-2 hover:text-gray-900 hover:bg-gray-800 px-2 py-2 rounded-lg">
|
||||||
<svg class="w-7 h-7 text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 19 19">
|
<svg class="w-7 h-7 text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 19 19">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.013 7.962a3.519 3.519 0 0 0-4.975 0l-3.554 3.554a3.518 3.518 0 0 0 4.975 4.975l.461-.46m-.461-4.515a3.518 3.518 0 0 0 4.975 0l3.553-3.554a3.518 3.518 0 0 0-4.974-4.975L10.3 3.7"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.013 7.962a3.519 3.519 0 0 0-4.975 0l-3.554 3.554a3.518 3.518 0 0 0 4.975 4.975l.461-.46m-.461-4.515a3.518 3.518 0 0 0 4.975 0l3.553-3.554a3.518 3.518 0 0 0-4.974-4.975L10.3 3.7"/>
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const makeExampleFactory = (application: Editor): Function => {
|
|||||||
) => {
|
) => {
|
||||||
const codeId = `codeExample${application.exampleCounter++}`;
|
const codeId = `codeExample${application.exampleCounter++}`;
|
||||||
// Store the code snippet in the data structure
|
// Store the code snippet in the data structure
|
||||||
application.api.codeExamples[codeId] = "bpm(120);\n" + code;
|
application.api.codeExamples[codeId] = code;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<details ${open ? "open" : ""}>
|
<details ${open ? "open" : ""}>
|
||||||
|
|||||||
@ -19,9 +19,8 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
this.app.clock.tick
|
this.app.clock.tick
|
||||||
);
|
);
|
||||||
this.app.clock.time_position = futureTimeStamp;
|
this.app.clock.time_position = futureTimeStamp;
|
||||||
this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${
|
this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${futureTimeStamp.beat + 1
|
||||||
futureTimeStamp.beat + 1
|
}:${zeroPad(futureTimeStamp.pulse, 2)} / ${this.app.clock.bpm}`;
|
||||||
}:${zeroPad(futureTimeStamp.pulse, 2)}`;
|
|
||||||
if (this.app.exampleIsPlaying) {
|
if (this.app.exampleIsPlaying) {
|
||||||
tryEvaluate(this.app, this.app.example_buffer);
|
tryEvaluate(this.app, this.app.example_buffer);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -303,7 +303,8 @@ export class SoundEvent extends AudibleEvent {
|
|||||||
// Unit
|
// Unit
|
||||||
public stretch = (beat: number) => {
|
public stretch = (beat: number) => {
|
||||||
this.updateValue("unit", "c");
|
this.updateValue("unit", "c");
|
||||||
this.updateValue("speed", 2 / beat)
|
this.updateValue("speed", 1 / beat)
|
||||||
|
this.updateValue("cut", beat)
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -50,13 +50,12 @@ Let's pause for a moment and explain what is going on:
|
|||||||
- Sounds are **composed** by adding qualifiers/parameters that will modify the sound or synthesizer being played (_e.g_ <ic>sound('...').blabla(...)..something(...).out()</ic>. Think of it as _audio chains_.
|
- Sounds are **composed** by adding qualifiers/parameters that will modify the sound or synthesizer being played (_e.g_ <ic>sound('...').blabla(...)..something(...).out()</ic>. Think of it as _audio chains_.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
'"Composing" a sound or making a sound chain',
|
'"Composing" a complex sonic object by making a sound chain',
|
||||||
`
|
`
|
||||||
beat(1) :: sound('pad')
|
beat(1) :: sound('pad').n(1)
|
||||||
.begin(rand(0, 0.4))
|
.begin(rand(0, 0.4))
|
||||||
.freq([50,52].beat())
|
.freq([50,52].beat())
|
||||||
.size(0.9)
|
.size(0.9).room(0.9)
|
||||||
.room(0.9)
|
|
||||||
.velocity(0.25)
|
.velocity(0.25)
|
||||||
.pan(usine()).release(2).out()`,
|
.pan(usine()).release(2).out()`,
|
||||||
true
|
true
|
||||||
@ -110,10 +109,9 @@ ${makeExample(
|
|||||||
"Let's make something more complex",
|
"Let's make something more complex",
|
||||||
`
|
`
|
||||||
beat(0.25) && sound('jvbass')
|
beat(0.25) && sound('jvbass')
|
||||||
.sometimes(s=>s.speed([1,5,10].pick()))
|
.sometimes(s=>s.speed([2, 0.5].pick()))
|
||||||
.room(0.5)
|
.room(0.9).size(0.9).gain(1)
|
||||||
.gain(1)
|
.cutoff(usine(1/2) * 5000)
|
||||||
.cutoff(usine(2) * 5000)
|
|
||||||
.out()`,
|
.out()`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
@ -131,7 +129,7 @@ There is a special method to choose the _orbit_ that your sound is going to use:
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|----------|-------|------------------------------------------------------------|
|
|----------|-------|------------------------------------------------------------|
|
||||||
| orbit | o | Orbit number |
|
| <ic>orbit</ic> | o | Orbit number |
|
||||||
|
|
||||||
|
|
||||||
## Amplitude
|
## Amplitude
|
||||||
@ -140,9 +138,9 @@ Simple controls over the amplitude (volume) of a given sound.
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|----------|-------|------------------------------------------------------------------------------------|
|
|----------|-------|------------------------------------------------------------------------------------|
|
||||||
| gain | | Volume of the synth/sample (exponential) |
|
| <ic>gain</ic> | | Volume of the synth/sample (exponential) |
|
||||||
| velocity | vel | Velocity (amplitude) from <ic>0</ic> to <ic>1</ic>. Multipled with gain |
|
| <ic>velocity</ic> | vel | Velocity (amplitude) from <ic>0</ic> to <ic>1</ic>. Multipled with gain |
|
||||||
| dbgain | db | Attenuation in dB from <ic>-inf</ic> to <ic>+10</ic> (acts as a sound mixer fader) |
|
| <ic>dbgain</ic> | db | Attenuation in dB from <ic>-inf</ic> to <ic>+10</ic> (acts as a sound mixer fader) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Velocity manipulated by a counter",
|
"Velocity manipulated by a counter",
|
||||||
@ -157,21 +155,24 @@ beat(.5)::snd('cp').vel($(1)%10 / 10).out()`,
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|---------|-------|-----------------------------------------------|
|
|---------|-------|-----------------------------------------------|
|
||||||
| attack | atk | Attack value (time to maximum volume) |
|
| <ic>attack</ic> | atk | Attack value (time to maximum volume) |
|
||||||
| decay | dec | Decay value (time to decay to sustain level) |
|
| <ic>decay</ic> | dec | Decay value (time to decay to sustain level) |
|
||||||
| sustain | sus | Sustain value (gain when sound is held) |
|
| <ic>sustain</ic> | sus | Sustain value (gain when sound is held) |
|
||||||
| release | rel | Release value (time for the sound to die off) |
|
| <ic>release</ic> | rel | Release value (time for the sound to die off) |
|
||||||
|
|
||||||
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.
|
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(
|
${makeExample(
|
||||||
"Simple synthesizer",
|
"Simple synthesizer",
|
||||||
`
|
`
|
||||||
beat(4)::sound('sawtooth').note(50).decay(0.5).sustain(0.5).release(2).gain(0.25).out();
|
let smooth = (sound) => {
|
||||||
beat(2)::sound('sawtooth').note(50+7).decay(0.5).sustain(0.6).release(2).gain(0.25).out();
|
return sound.cutoff(r(100,500))
|
||||||
beat(1)::sound('sawtooth').note(50+12).decay(0.5).sustain(0.7).release(2).gain(0.25).out();
|
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
|
||||||
beat(.25)::sound('sawtooth').note([50,57,62].pick() + [12, 24, 0].beat(2))
|
.gain(r(0.25, 0.4)).adsr(0, r(.2,.4), r(0,0.5), 0)
|
||||||
.cutoff(5000).sustain(0.5).release(0.1).gain(0.25).out()
|
.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();
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)};
|
)};
|
||||||
@ -182,17 +183,17 @@ There are some basic controls over the playback of each sample. This allows you
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|---------|-------|--------------------------------------------------------|
|
|---------|-------|--------------------------------------------------------|
|
||||||
| n | | Select a sample in the current folder (from <ic>0</ic> to infinity) |
|
| <ic>n</ic> | | Select a sample in the current folder (from <ic>0</ic> to infinity) |
|
||||||
| begin | | Beginning of the sample playback (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>begin</ic> | | Beginning of the sample playback (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
| end | | End of the sample (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>end</ic> | | End of the sample (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
| loopBegin | | Beginning of the loop section (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>loopBegin</ic> | | Beginning of the loop section (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
| loopEnd | | End 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>) |
|
||||||
| loop | | Whether to loop or not the audio sample |
|
| <ic>loop</ic> | | Whether to loop or not the audio sample |
|
||||||
| stretch | | Stretches the audio playback rate of a sample over <ic>n</ic> beats |
|
| <ic>stretch</ic> | | Stretches the audio playback rate of a sample over <ic>n</ic> beats |
|
||||||
| speed | | Playback speed (<ic>2</ic> = twice as fast) |
|
| <ic>speed</ic> | | Playback speed (<ic>2</ic> = twice as fast) |
|
||||||
| cut | | 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>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 |
|
||||||
| clip | | Multiply the duration of the sample with the given number |
|
| <ic>clip</ic> | | Multiply the duration of the sample with the given number |
|
||||||
| pan | | Stereo position of the audio playback (<ic>0</ic> = left, <ic>1</ic> = right)|
|
| <ic>pan</ic> | | Stereo position of the audio playback (<ic>0</ic> = left, <ic>1</ic> = right)|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Complex sampling duties",
|
"Complex sampling duties",
|
||||||
@ -200,7 +201,7 @@ ${makeExample(
|
|||||||
// Using some of the modifiers described above :)
|
// Using some of the modifiers described above :)
|
||||||
beat(.5)::snd('pad').begin(0.2)
|
beat(.5)::snd('pad').begin(0.2)
|
||||||
.speed([1, 0.9, 0.8].beat(4))
|
.speed([1, 0.9, 0.8].beat(4))
|
||||||
.n([0, 0, 2, 4].beat(4)).pan(usine(.5))
|
.n(2).pan(usine(.5))
|
||||||
.end(rand(0.3,0.8))
|
.end(rand(0.3,0.8))
|
||||||
.room(0.8).size(0.5)
|
.room(0.8).size(0.5)
|
||||||
.clip(1).out()
|
.clip(1).out()
|
||||||
@ -212,11 +213,11 @@ ${makeExample(
|
|||||||
"Playing an amen break",
|
"Playing an amen break",
|
||||||
`
|
`
|
||||||
// Note that stretch has the same value as beat
|
// Note that stretch has the same value as beat
|
||||||
beat(4) :: sound('breaks165').stretch(4).out()
|
beat(4) :: sound('amen1').n(11).stretch(4).out()
|
||||||
beat(0.25) :: sound('hh').out()
|
beat(1) :: sound('kick').shape(0.35).out()`,
|
||||||
beat(1, 4, 8) :: sound('bd').out()`,
|
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
|
|
||||||
@ -224,13 +225,13 @@ There are three basic filters: a _lowpass_, _highpass_ and _bandpass_ filters wi
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|------------|-------|-----------------------------------------|
|
|------------|-------|-----------------------------------------|
|
||||||
| cutoff | lpf | Cutoff frequency of the lowpass filter |
|
| <ic>cutoff</ic> | lpf | Cutoff frequency of the lowpass filter |
|
||||||
| resonance | lpq | Resonance of the lowpass filter |
|
| <ic>resonance</ic> | lpq | Resonance of the lowpass filter |
|
||||||
| hcutoff | hpf | Cutoff frequency of the highpass filter |
|
| <ic>hcutoff</ic> | hpf | Cutoff frequency of the highpass filter |
|
||||||
| hresonance | hpq | Resonance of the highpass filter |
|
| <ic>hresonance</ic> | hpq | Resonance of the highpass filter |
|
||||||
| bandf | bpf | Cutoff frequency of the bandpass filter |
|
| <ic>bandf</ic> | bpf | Cutoff frequency of the bandpass filter |
|
||||||
| bandq | bpq | Resonance of the bandpass filter |
|
| <ic>bandq</ic> | bpq | Resonance of the bandpass filter |
|
||||||
| vowel | | Formant filter with (vocal quality) |
|
| <ic>vowel</ic> | | Formant filter with (vocal quality) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Filter sweep using a low frequency oscillator",
|
"Filter sweep using a low frequency oscillator",
|
||||||
@ -249,8 +250,8 @@ A basic reverberator that you can use to give some depth to your sounds. This si
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|------------|-------|---------------------------------|
|
|------------|-------|---------------------------------|
|
||||||
| room | | The more, the bigger the reverb (between <ic>0</ic> and <ic>1</ic>.|
|
| <ic>room</ic> | | The more, the bigger the reverb (between <ic>0</ic> and <ic>1</ic>.|
|
||||||
| size | | Reverberation amount |
|
| <ic>size</ic> | | Reverberation amount |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Clapping in the cavern",
|
"Clapping in the cavern",
|
||||||
@ -267,9 +268,9 @@ A good sounding delay unit that can go into feedback territory. Use it without m
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|------------|-----------|---------------------------------|
|
|------------|-----------|---------------------------------|
|
||||||
| delay | | Delay _wet/dry_ (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>delay</ic> | | Delay _wet/dry_ (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
| delaytime | delayt | Delay time (in milliseconds) |
|
| <ic>delaytime</ic> | delayt | Delay time (in milliseconds) |
|
||||||
| delayfeedback| delayfb | Delay feedback (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>delayfeedback</ic> | delayfb | Delay feedback (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Who doesn't like delay?",
|
"Who doesn't like delay?",
|
||||||
@ -285,9 +286,9 @@ beat(1)::snd('kick').out()
|
|||||||
|
|
||||||
| Method | Alias | Description |
|
| Method | Alias | Description |
|
||||||
|------------|-----------|---------------------------------|
|
|------------|-----------|---------------------------------|
|
||||||
| coarse | | Artificial sample-rate lowering |
|
| <ic>coarse</ic> | | Artificial sample-rate lowering |
|
||||||
| crush | | bitcrushing. <ic>1</ic> is extreme, the more you go up, the less it takes effect. |
|
| <ic>crush</ic> | | bitcrushing. <ic>1</ic> is extreme, the more you go up, the less it takes effect. |
|
||||||
| shape | | Waveshaping distortion (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>shape</ic> | | Waveshaping distortion (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
|
|||||||
@ -12,43 +12,44 @@ Welcome to the Topos documentation. These pages are offering you an introduction
|
|||||||
)}. Press again to make the documentation disappear. All your contributions are welcome!
|
)}. Press again to make the documentation disappear. All your contributions are welcome!
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Welcome! Eval to get started",
|
"Welcome! Eval to get started",
|
||||||
examples[Math.floor(Math.random() * examples.length)],
|
examples[Math.floor(Math.random() * examples.length)],
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## What is Topos?
|
## What is Topos?
|
||||||
|
|
||||||
Topos is an _algorithmic_ sequencer. Topos uses small algorithms to represent musical sequences and processes. These can be written in just a few lines of code. Topos is made to be _live-coded_. The _live coder_ strives for the constant interaction with algorithms and sound during a musical performance. Topos is aiming to be a digital playground for live algorithmic music.
|
Topos is an _algorithmic_ sequencer. Topos uses small algorithms to represent musical sequences and processes. These can be written in just a few lines of code. Topos is made to be _live-coded_. The _live coder_ strives for the constant interaction with algorithms and sound during a musical performance. Topos is aiming to be a digital playground for live algorithmic music.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Small algorithms for direct musical expression",
|
"Small algorithms for direct musical expression",
|
||||||
`
|
`
|
||||||
beat(1) :: sound(['kick', 'hat', 'snare', 'hat'].beat(1)).out()
|
beat(1) :: sound(['kick', 'hat', 'snare', 'hat'].beat(1)).out()
|
||||||
beat(.5) :: sound('jvbass').note(35 + [0,12].beat()).out()
|
beat(.5) :: sound('jvbass').note(35 + [0,12].beat()).out()
|
||||||
beat([0.5, 0.25, 1, 2].beat(1)) :: sound('east')
|
beat([0.5, 0.25].beat(1)) :: sound('east')
|
||||||
.room(.5).size(0.5).n(irand(1,5)).out()`,
|
.room(.9).speed(flip(4) ? 1 : 0.95).size(0.9).o(2).n($(1)).out()`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Computer music should be immediate and intuitive",
|
"Computer music should be immediate and intuitive",
|
||||||
`beat(.5)::snd('sine')
|
`beat(.5)::snd('sine')
|
||||||
.delay(0.5).delayt(0.25).delayfb(0.7)
|
.delay(0.5).delayt(0.25).delayfb(0.7)
|
||||||
.room(0.8).size(0.8)
|
.room(0.8).size(0.8)
|
||||||
.freq(mouseX()).out()`,
|
.freq(mouseX()).out()`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Making the web less dreadful, one beep at at time",
|
"Making the web less dreadful, one beep at at time",
|
||||||
`
|
`
|
||||||
beat(.5) :: sound('sid').n($(2)).out()
|
beat(.5) :: sound('sid').n($(2))
|
||||||
|
.room(1).speed([1,2].pick()).out()
|
||||||
beat(.25) :: sound('sid').note(
|
beat(.25) :: sound('sid').note(
|
||||||
[34, 36, 41].beat(.25) + [[0,-24].pick(),12].beat())
|
[34, 36, 41].beat(.25) + [[0,-24].pick(),12].beat())
|
||||||
.room(0.9).size(0.9).n(4).out()`,
|
.room(0.9).size(0.9).n(4).out()`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Teletype is/was an open source hardware module for Eurorack synthesizers. While the Teletype was initially born as an hardware module, Topos aims to be a web-browser based software sequencer from the same family! It is a sequencer, a scriptable interface, a companion for algorithmic music-making. Topos wishes to fullfill the same goal than the Teletype, keeping the same spirit alive on the web. It is free, open-source, and made to be shared and used by everyone.
|
Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Teletype is/was an open source hardware module for Eurorack synthesizers. While the Teletype was initially born as an hardware module, Topos aims to be a web-browser based software sequencer from the same family! It is a sequencer, a scriptable interface, a companion for algorithmic music-making. Topos wishes to fullfill the same goal than the Teletype, keeping the same spirit alive on the web. It is free, open-source, and made to be shared and used by everyone.
|
||||||
|
|
||||||
|
|||||||
@ -69,7 +69,7 @@ ${makeExample(
|
|||||||
"pulse is the OG rhythmic function in Topos",
|
"pulse is the OG rhythmic function in Topos",
|
||||||
`
|
`
|
||||||
pulse([48, 24, 16].beat(4)) :: sound('linnhats').out()
|
pulse([48, 24, 16].beat(4)) :: sound('linnhats').out()
|
||||||
beat(1)::snd('bd').out()
|
beat(1)::snd(['bd', '808oh'].beat(1)).out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
)};
|
)};
|
||||||
@ -80,7 +80,7 @@ ${makeExample(
|
|||||||
"Some simple yet detailed rhythms",
|
"Some simple yet detailed rhythms",
|
||||||
`
|
`
|
||||||
onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
|
onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
|
||||||
onbeat(2,4)::snd('snare').n([0,2].beat(2.5)).out() // Snare on acccentuated beats
|
onbeat(2,4)::snd('snare').n([8,4].beat(4)).out() // Snare on acccentuated beats
|
||||||
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
@ -103,13 +103,12 @@ beat([.25, 1/8].beat(1.5))::snd('hat').n(2)
|
|||||||
${makeExample(
|
${makeExample(
|
||||||
"Using oncount to create more variation in the rhythm",
|
"Using oncount to create more variation in the rhythm",
|
||||||
`
|
`
|
||||||
bpm(120)
|
z1('1/16 (0 2 3 4)+(0 2 4 6)').scale('pentatonic').sound('sawtooth')
|
||||||
z1('0.125 (0 2 3 4)+(0 2 4 6)').sound('sawtooth')
|
.cutoff([400,500,1000,2000].beat(1))
|
||||||
.cutoff([400,500,1000,2000].beat(1))
|
.lpadsr(2, 0, .2, 0, 0)
|
||||||
.lpadsr(2, 0, .2, 0, 0)
|
.delay(0.5).delayt(0.25).room(0.9).size(0.9).out()
|
||||||
.delay(0.5).delayt(0.25).room(0.9).size(0.9).out()
|
onbeat(1,1.5,2,3,4) :: sound('bd').gain(2.0).out()
|
||||||
onbeat(1,1.5,2,3,4) :: sound('bd').gain(2.0).out()
|
oncount([1,3,5.5,7,7.5,8],8) :: sound('hh').gain(irand(1.0,4.0)).out()
|
||||||
oncount([1,3,5.5,7,7.5,8],8) :: sound('hh').gain(irand(1.0,4.0)).out()
|
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
@ -117,12 +116,11 @@ ${makeExample(
|
|||||||
${makeExample(
|
${makeExample(
|
||||||
"Using oncount to create rhythms with a custom meter",
|
"Using oncount to create rhythms with a custom meter",
|
||||||
`
|
`
|
||||||
bpm(200)
|
bpm(200)
|
||||||
oncount([1, 5, 9, 13],16) :: sound('bd').gain(1.0).out()
|
oncount([1, 5, 9, 13],16) :: sound('808bd').n(4).shape(0.5).gain(1.0).out()
|
||||||
oncount([5, 6, 13],16) :: sound('cp').gain(0.9).out()
|
oncount([5, 6, 13],16) :: sound('shaker').room(0.25).gain(0.9).out()
|
||||||
oncount([2, 3, 3.5, 6, 7, 10, 15],16) :: sound('hh').n(8).gain(0.8).out()
|
oncount([2, 3, 3.5, 6, 7, 10, 15],16) :: sound('hh').n(8).gain(0.8).out()
|
||||||
oncount([1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16],16) ::
|
oncount([1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16],16) :: sound('hh').out()
|
||||||
sound('hh').out()
|
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
@ -136,9 +134,14 @@ We included a bunch of popular rhythm generators in Topos such as the euclidian
|
|||||||
${makeExample(
|
${makeExample(
|
||||||
"Classic euclidian club music patterns",
|
"Classic euclidian club music patterns",
|
||||||
`
|
`
|
||||||
beat(.5) && euclid($(1), 5, 8) && snd('kick').out()
|
beat(.5) && euclid($(1), 4, 8) && snd('kick').n(4).out()
|
||||||
beat(.5) && euclid($(2), 2, 8) && snd('sd').out()
|
beat(.25) && euclid($(2), 5, 8) && snd('dr').n(21).out()
|
||||||
beat(4) :: sound('cp').out()
|
beat(.25) && euclid($(3), 3, 8) && snd('shaker')
|
||||||
|
.gain(r(0.7, 1)).cutoff(1000 + usine(1/8) * 3000)
|
||||||
|
.n(11).out()
|
||||||
|
beat(.25) && euclid($(3), 6, 8) && snd('shaker')
|
||||||
|
.gain(r(0.7, 1)).cutoff(1000 + usine(1/4) * 4000)
|
||||||
|
.speed(2).n(11).out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
@ -149,7 +152,7 @@ ${makeExample(
|
|||||||
bpm(145); // Setting a faster BPM
|
bpm(145); // Setting a faster BPM
|
||||||
beat(.5) && euclid($(1), 5, 8) :: sound('bd').out()
|
beat(.5) && euclid($(1), 5, 8) :: sound('bd').out()
|
||||||
beat(.5) && euclid($(2), [1,0].beat(8), 8)
|
beat(.5) && euclid($(2), [1,0].beat(8), 8)
|
||||||
:: sound('ST03').n(3).room(1).size(1).o(1).out()
|
:: sound('ST03').n(5).room(1).size(1).o(1).out()
|
||||||
beat(.5) && euclid($(6), [6,7].beat(8), 8) :: sound('hh').out()
|
beat(.5) && euclid($(6), [6,7].beat(8), 8) :: sound('hh').out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
@ -158,9 +161,11 @@ beat(.5) && euclid($(6), [6,7].beat(8), 8) :: sound('hh').out()
|
|||||||
${makeExample(
|
${makeExample(
|
||||||
"Adding more rhythmic density",
|
"Adding more rhythmic density",
|
||||||
`
|
`
|
||||||
beat(.5) && euclid($(1), 5, 9) && snd('kick').out()
|
beat(.5) && euclid($(1), 5, 9) && snd('kick').shape(r(0.2,0.5)).out()
|
||||||
beat(.5) && euclid($(2), 2, 3, 1) && snd('east').end(0.5).n(5).speed([1,2].beat(2)).out()
|
beat(.5) && euclid($(2), 2, 3, 1) && snd('dr').end(0.5).n([8,9,13].beat(0.25))
|
||||||
beat(.5) && euclid($(3), 6, 9, 1) && snd('east').end(0.5).n(5).freq(200).speed([2,1].beat(2)).out()
|
.gain(r(0.5,1)).speed(1).out()
|
||||||
|
beat(.5) && euclid($(3), 6, 9, 1) && snd('dr').end(0.5).n(2).freq(200).speed(1)
|
||||||
|
.gain(r(0.5,1)).out()
|
||||||
beat(.25) && euclid($(4), 7, 9, 1) && snd('hh').out()
|
beat(.25) && euclid($(4), 7, 9, 1) && snd('hh').out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
@ -200,8 +205,8 @@ ${makeExample(
|
|||||||
"Change the integers for a surprise rhythm!",
|
"Change the integers for a surprise rhythm!",
|
||||||
`
|
`
|
||||||
bpm(135);
|
bpm(135);
|
||||||
beat(.5) && bin($(1), 34) && snd('kick').n([1,3].beat(1)).out()
|
beat(.5) && bin($(1), 12) && snd('kick').n([4,9].beat(1.5)).out()
|
||||||
beat(.5) && bin($(2), 48) && snd('snare').n([1,4].beat(1)).out()
|
beat(.5) && bin($(2), 34) && snd('snare').n([3,5].beat(1)).out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
@ -372,8 +377,16 @@ beat(.5)::snd(flip(4) ? 'kick' : 'hat').out()
|
|||||||
${makeExample(
|
${makeExample(
|
||||||
"Thinking music over bars",
|
"Thinking music over bars",
|
||||||
`
|
`
|
||||||
flipbar(2) :: beat(1):: snd('kick').out()
|
let roomy = (n) => n.room(1).size(1).cutoff(500 + usaw(1/8) * 5000);
|
||||||
flipbar(3) :: beat(.5):: snd('hat').out()
|
function a() {
|
||||||
|
beat(1) && roomy(sound('kick')).out()
|
||||||
|
beat(.5) && roomy(sound('hat')).out()
|
||||||
|
}
|
||||||
|
function b() {
|
||||||
|
beat(1/4) && roomy(sound('shaker')).out()
|
||||||
|
}
|
||||||
|
flipbar(2) && a()
|
||||||
|
flipbar(3) && b()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|||||||
18
src/main.ts
18
src/main.ts
@ -32,6 +32,21 @@ import showdown from "showdown";
|
|||||||
showdown.setFlavor("github");
|
showdown.setFlavor("github");
|
||||||
import showdownHighlight from "showdown-highlight";
|
import showdownHighlight from "showdown-highlight";
|
||||||
import { makeStringExtensions } from "./StringExtensions";
|
import { makeStringExtensions } from "./StringExtensions";
|
||||||
|
|
||||||
|
|
||||||
|
// Broadcast that you're opening a page.
|
||||||
|
localStorage.openpages = Date.now();
|
||||||
|
window.addEventListener('storage', function(e) {
|
||||||
|
if (e.key == "openpages") {
|
||||||
|
// Listen if anybody else is opening the same page!
|
||||||
|
localStorage.page_available = Date.now();
|
||||||
|
}
|
||||||
|
if (e.key == "page_available") {
|
||||||
|
document.getElementById("all")!.classList.add("invisible")
|
||||||
|
alert("Topos is already opened in another tab. Close this tab now to prevent data loss.");
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
const classMap = {
|
const classMap = {
|
||||||
h1: "text-white lg:text-4xl text-xl lg:ml-4 lg:mx-4 mx-2 lg:my-4 my-2 lg:mb-4 mb-4 bg-neutral-900 rounded-lg py-2 px-2",
|
h1: "text-white lg:text-4xl text-xl lg:ml-4 lg:mx-4 mx-2 lg:my-4 my-2 lg:mb-4 mb-4 bg-neutral-900 rounded-lg py-2 px-2",
|
||||||
h2: "text-white lg:text-3xl text-xl lg:ml-4 lg:mx-4 mx-2 lg:my-4 my-2 lg:mb-4 mb-4 bg-neutral-900 rounded-lg py-2 px-2",
|
h2: "text-white lg:text-3xl text-xl lg:ml-4 lg:mx-4 mx-2 lg:my-4 my-2 lg:mb-4 mb-4 bg-neutral-900 rounded-lg py-2 px-2",
|
||||||
@ -1182,7 +1197,7 @@ export class Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = new Editor();
|
let app = new Editor();
|
||||||
|
|
||||||
window.addEventListener("beforeunload", () => {
|
window.addEventListener("beforeunload", () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -1194,3 +1209,4 @@ window.addEventListener("beforeunload", () => {
|
|||||||
app.clock.stop();
|
app.clock.stop();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user