Skip to content

Commit 308c384

Browse files
committed
Version 2.3.0
- Create synths, generate noise with Superpowered! Generator with sine wave, triangle, sawtooth, pulse wave (PWM), pink noise and white noise output. Synchronization of multiple generators, optional FM oscillator. - AdvancedAudioPlayer and Decoder can understand both compressed and raw PCM AudioInMemory formats.
1 parent eba900b commit 308c384

File tree

10 files changed

+105
-14
lines changed

10 files changed

+105
-14
lines changed

Diff for: docs.html

+97-10
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,7 @@ <h3>Filter</h3>
12241224
<pre><code class="language-js">
12251225
// Constructor. Enabled is false by default.
12261226
let filter = new Superpowered.Filter(
1227-
Superpowered.FilterType.Resonant_Lowpass, // The initial filter type.
1227+
Superpowered.Filter.Resonant_Lowpass, // The initial filter type.
12281228
44100 // The initial sample rate in Hz.
12291229
);
12301230

@@ -1240,17 +1240,17 @@ <h3>Filter</h3>
12401240
filter.octave = 1; // Width in octave for bandlimited and parametric filters. Limit: 0.05 to 5.
12411241
filter.slope = 0.5; // Slope value for shelving filters. Limit: 0.001 to 1.
12421242

1243-
filter.type = Superpowered.FilterType.Parametric; // Filter type. Changing the filter type often involves changing other parameters as well. Therefore in a real-time context change the parameters and the type in the same thread with the process() call.
1243+
filter.type = Superpowered.Filter.Parametric; // Filter type. Changing the filter type often involves changing other parameters as well. Therefore in a real-time context change the parameters and the type in the same thread with the process() call.
12441244

12451245
// Superpowered filter types and their effective parameters:
1246-
Superpowered.FilterType.Resonant_Lowpass // frequency, resonance
1247-
Superpowered.FilterType.Resonant_Highpass // frequency, resonance
1248-
Superpowered.FilterType.Bandlimited_Bandpass // frequency, octave
1249-
Superpowered.FilterType.Bandlimited_Notch // frequency, octave
1250-
Superpowered.FilterType.LowShelf // frequency, slope, decibel
1251-
Superpowered.FilterType.HighShelf // frequency, slope, decibel
1252-
Superpowered.FilterType.Parametric // frequency, octave, decibel
1253-
Superpowered.FilterType.CustomCoefficients
1246+
Superpowered.Filter.Resonant_Lowpass // frequency, resonance
1247+
Superpowered.Filter.Resonant_Highpass // frequency, resonance
1248+
Superpowered.Filter.Bandlimited_Bandpass // frequency, octave
1249+
Superpowered.Filter.Bandlimited_Notch // frequency, octave
1250+
Superpowered.Filter.LowShelf // frequency, slope, decibel
1251+
Superpowered.Filter.HighShelf // frequency, slope, decibel
1252+
Superpowered.Filter.Parametric // frequency, octave, decibel
1253+
Superpowered.Filter.CustomCoefficients
12541254

12551255
// For advanced use. Set custom coefficients for the filter. Changes will be smoothly handled to prevent audio artifacts. Do not call this concurrently with process().
12561256
filter.setCustomCoefficients(
@@ -1558,6 +1558,93 @@ <h3>TimeStretching</h3>
15581558
ts.destruct();
15591559
</code></pre>
15601560

1561+
<p>Using the time stretcher is more complex than using other effects, because it changes time and therefore buffering as well. It's fully integrated into the AdvancedAudioPlayer class, which is recommended for simple use. But if the time-stretcher has to be used alone, the logic could look like this:</p>
1562+
1563+
<pre><code class="language-js">
1564+
while (ts.getOutputLengthFrames() < numberOfFramesNeeded) {
1565+
let timestretcherNeedsThisAmountOfFramesToProduceAudio = ts.getNumberOfInputFramesNeeded();
1566+
if (timestretcherNeedsThisAmountOfFramesToProduceAudio can not be acquired) break;
1567+
acquire timestretcherNeedsThisAmountOfFramesToProduceAudio into some Superpowered.Float32Buffer;
1568+
ts.addInput(some Superpowered.Float32Buffer pointer, number_of_frames_acquired);
1569+
}
1570+
1571+
if (ts.getOutputLengthFrames() >= numberOfFramesNeeded) {
1572+
// success, get output
1573+
ts.getOutput(output buffer pointer, numberOfFramesNeeded);
1574+
} else {
1575+
// could not produce enough audio
1576+
// return with silence
1577+
}
1578+
</code></pre>
1579+
1580+
<h2>Generating Audio</h2>
1581+
1582+
<h3>Generator</h3>
1583+
1584+
<p>Generator for various waveform shapes.</p>
1585+
1586+
<pre><code class="language-js">
1587+
// Constructor.
1588+
let g = new Superpowered.Generator(
1589+
44100, // The initial sample rate in Hz.
1590+
Superpowered.Generator.Sine // The initial shape.
1591+
);
1592+
1593+
// Superpowered generator shapes
1594+
Superpowered.Generator.Sine // sine
1595+
Superpowered.Generator.Triangle // triangle
1596+
Superpowered.Generator.Sawtooth // sawtooth
1597+
Superpowered.Generator.PWM // pulse wave with adjustable width
1598+
Superpowered.Generator.PinkNoise // pink noise
1599+
Superpowered.Generator.WhiteNoise // white noise
1600+
Superpowered.Generator.SyncMaster // generates no sound, but sync data to use with generateSyncMaster
1601+
1602+
g.frequency = 1000; // Frequency of generator output in Hz. Minimum is > 0.0001, maximum is limited to sample rate / 2.
1603+
g.pulsewidth = 0.3; // Pulse Width for PWM shape. 0.5 results in a square wave. Limited between 0.0001 and 0.9999.
1604+
g.samplerate = 48000; // Sample rate in Hz.
1605+
g.shape = Superpowered.Generator.Triangle; // Shape.
1606+
1607+
// Generates (outputs) audio.
1608+
// It's never blocking for real-time usage. You can change all properties on any thread, concurrently with this function.
1609+
g.generate(
1610+
output, // Pointer to floating point numbers. 32-bit MONO output.
1611+
512 // Number of samples to produce.
1612+
);
1613+
1614+
// Generates (outputs) audio for a frequency modulated (FM) oscillator.
1615+
// It's never blocking for real-time usage. You can change all properties on any thread, concurrently with this function.
1616+
g.generateFM(
1617+
output, // Pointer to floating point numbers. 32-bit MONO output.
1618+
512, // Number of samples to produce.
1619+
fmsource, // Pointer to floating point numbers. Source for FM modulation containing numberOfSamples samples, usually from a previous call to generate().
1620+
100 // Frequency modulation depth. 0 means no modulation, 1000 is a reasonable upper limit.
1621+
);
1622+
1623+
// Generates audio for an oscillator that also serves as synchronization source for another oscillator.
1624+
// It's never blocking for real-time usage. You can change all properties on any thread, concurrently with this function.
1625+
g.generateAndCreateSync(
1626+
output, // Pointer to floating point numbers. 32-bit MONO output.
1627+
syncdata, // Pointer to a buffer to receive hard sync information for syncing oscillators. Should be numberOfSamples + 1 floats big minimum.
1628+
512, // Number of samples to produce.
1629+
);
1630+
1631+
// Generates audio for an oscillator that is hard-synced to another oscillator.
1632+
// It's never blocking for real-time usage. You can change all properties on any thread, concurrently with this function.
1633+
g.generateSynchronized(
1634+
output, // Pointer to floating point numbers. 32-bit MONO output.
1635+
syncdata, // Pointer to floating point numbers. Input sync data, previously produced by a call to generateAndCreateSync() with same numberOfSamples.
1636+
512 // Number of samples to produce.
1637+
);
1638+
1639+
// Start oscillator with given phase angle. In a synthesizer, this should be called whenever a voice starts.
1640+
g.reset(
1641+
0.5 // Start phase of the oscillator between 0.0 (0 degree) and 1.0 (180 degrees).
1642+
);
1643+
1644+
// Destructor (to free up memory).
1645+
g.destruct();
1646+
</code></pre>
1647+
15611648
<h2>Loading Audio</h2>
15621649

15631650
<p>Due to the nature of most JavaScript runtimes (such as no control over thread scheduling or no direct disk access), loading audio with Superpowered is a little bit different vs. native. <em>The entire audio file must be loaded into the WebAssembly Linear Memory memory</em> first, then the Superpowered Decoder can read and decode it.</p>

Diff for: example_effects/superpowered/SuperpoweredWebAudio.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { SuperpoweredTrackLoader } from './SuperpoweredTrackLoaderModule.js';
44
var AudioWorkletHasBrokenModuleImplementation = false;
55

66
class SuperpoweredWebAudio {
7-
constructor(minimumSamplerate, superpowered) { console.log(navigator.userAgent);
7+
constructor(minimumSamplerate, superpowered) {
88
AudioWorkletHasBrokenModuleImplementation = (navigator.userAgent.indexOf('AppleWebKit') > -1) || (navigator.userAgent.indexOf('Firefox') > -1);
9+
if (AudioWorkletHasBrokenModuleImplementation && (navigator.userAgent.indexOf('Chrome') > -1)) AudioWorkletHasBrokenModuleImplementation = false;
910
this.Superpowered = superpowered;
1011
this.audioContext = null;
1112
let AudioContext = window.AudioContext || window.webkitAudioContext || false;

Diff for: example_effects/superpowered/superpowered.wasm

399 KB
Binary file not shown.

Diff for: example_guitardistortion/superpowered/SuperpoweredWebAudio.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { SuperpoweredTrackLoader } from './SuperpoweredTrackLoaderModule.js';
44
var AudioWorkletHasBrokenModuleImplementation = false;
55

66
class SuperpoweredWebAudio {
7-
constructor(minimumSamplerate, superpowered) { console.log(navigator.userAgent);
7+
constructor(minimumSamplerate, superpowered) {
88
AudioWorkletHasBrokenModuleImplementation = (navigator.userAgent.indexOf('AppleWebKit') > -1) || (navigator.userAgent.indexOf('Firefox') > -1);
9+
if (AudioWorkletHasBrokenModuleImplementation && (navigator.userAgent.indexOf('Chrome') > -1)) AudioWorkletHasBrokenModuleImplementation = false;
910
this.Superpowered = superpowered;
1011
this.audioContext = null;
1112
let AudioContext = window.AudioContext || window.webkitAudioContext || false;
399 KB
Binary file not shown.

Diff for: example_timestretching/superpowered/SuperpoweredWebAudio.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { SuperpoweredTrackLoader } from './SuperpoweredTrackLoaderModule.js';
44
var AudioWorkletHasBrokenModuleImplementation = false;
55

66
class SuperpoweredWebAudio {
7-
constructor(minimumSamplerate, superpowered) { console.log(navigator.userAgent);
7+
constructor(minimumSamplerate, superpowered) {
88
AudioWorkletHasBrokenModuleImplementation = (navigator.userAgent.indexOf('AppleWebKit') > -1) || (navigator.userAgent.indexOf('Firefox') > -1);
9+
if (AudioWorkletHasBrokenModuleImplementation && (navigator.userAgent.indexOf('Chrome') > -1)) AudioWorkletHasBrokenModuleImplementation = false;
910
this.Superpowered = superpowered;
1011
this.audioContext = null;
1112
let AudioContext = window.AudioContext || window.webkitAudioContext || false;
399 KB
Binary file not shown.

Diff for: superpowered.bc

553 KB
Binary file not shown.

Diff for: superpowered/SuperpoweredWebAudio.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { SuperpoweredTrackLoader } from './SuperpoweredTrackLoaderModule.js';
44
var AudioWorkletHasBrokenModuleImplementation = false;
55

66
class SuperpoweredWebAudio {
7-
constructor(minimumSamplerate, superpowered) { console.log(navigator.userAgent);
7+
constructor(minimumSamplerate, superpowered) {
88
AudioWorkletHasBrokenModuleImplementation = (navigator.userAgent.indexOf('AppleWebKit') > -1) || (navigator.userAgent.indexOf('Firefox') > -1);
9+
if (AudioWorkletHasBrokenModuleImplementation && (navigator.userAgent.indexOf('Chrome') > -1)) AudioWorkletHasBrokenModuleImplementation = false;
910
this.Superpowered = superpowered;
1011
this.audioContext = null;
1112
let AudioContext = window.AudioContext || window.webkitAudioContext || false;

Diff for: superpowered/superpowered.wasm

399 KB
Binary file not shown.

0 commit comments

Comments
 (0)