Skip to content

Commit

Permalink
pre-release 0.2.0
Browse files Browse the repository at this point in the history
Automatic release versioning by reading package.json and generating
files.

Checks for instrument version, errors if there is a mismatch.

Changelog updated.

Release is ready to be tested.
  • Loading branch information
44100hertz committed Mar 6, 2023
1 parent 1b741da commit 6aa6d2a
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 18 deletions.
31 changes: 29 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
# Version 0.2
New waveforms!

In this second release of Fazeoid, we have added 5 new waveforms in addition to the sine wave. The six waveforms now include:
- Sine
- Absolute Sine
- Half Sine Wave
- Quarter Sine
- Pulse sine
- Square wave

Try them out by clicking on one of the 6 wave buttons!

These waves are made using additive synthesis, resulting in smooth, organic sound. Thep open up lots of bright new possibilities, with 36 possible waveform combinations, and thousands of new sounds.

Each wave has a unique harmonic profile, carefully selected and tuned by ear. The sine wave is of course, a pure tone with no harmonics. The absolute sine, which looks like letter W, is full of even harmonics which sound pleasant and warm. The half sine, or "camel sine", is similar to the absolute sine, but with a deeper or fuller tone beneath it. The quarter sine, which looks like a shark fin, has a thick sound similar to a sawtooth wave. The pulse sine, which looks like a full sine wave switching on and off, has an organic sound. And finally, the square wave is full of odd harmonics, which give it a unique power, loudness, and retro sound.

These wave shapes were inspired by the iconic OPL3 chip from the DOS era, which has 8 types of waveform. I created similar waves, but chose to pursue a more modern sound by using additive synthesis and a gentle roll off. Also, unlike the phase-modulated OPL3, this is a frequency modulated synth, meaning that all waveforms have their center of mass at 0. I originally included a triangle wave and a more mathematically perfect square, but didn't like how the triangle was too soft and similar to the sine, and how the square was too harsh. Observing that both waves rely on odd harmonics, I created a rounded square wave with a harmonic profile somewhat in between. With the sawtooth, I observed that the quarter sine has the same harmonic profile, but varying phase with a more useful shape for an FM synth, and that it was more recognizable. After selecting 6 unique waves, I realized that mathematically perfect waves don't play nicely with modulation, and I opted to make them less perfect for the sake of smoothing things out.

# Version 0.1
TODO: add 0.1 features here
Initial release.

# Version 0.2
Base features:
- Sine wave generators
- Phase modulation matrix
- Responsive DJ knob UI
- Oscilloscope visualization
- Piano
- ADSR envelopes
- Instrument saving and loading
- Sleek, futuristic look
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fmsite-svkit",
"version": "0.1.0",
"version": "0.2.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",
Expand Down
9 changes: 5 additions & 4 deletions src/lib/App.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script lang="ts">
import { defaultInstrument } from "$lib/audio/instrument"
import AudioController from "$lib/audio/Controller"
import InstrumentPanel from "$lib/InstrumentPanel.svelte"
import { defaultInstrument } from "$lib/audio/instrument";
import VERSION from "$lib/version";
import AudioController from "$lib/audio/Controller";
import InstrumentPanel from "$lib/InstrumentPanel.svelte";
import Piano from "$lib/piano/Piano.svelte";
import { onDestroy } from 'svelte'
Expand Down Expand Up @@ -44,7 +45,7 @@
<InstrumentPanel bind:params="{$instrument}" {portrait} />
<Piano on:noteUp="{noteUp}" on:noteDown="{noteDown}" {portrait} />
<footer>
<div>Fazeoid 0.1</div>
<div>Fazeoid {VERSION}</div>
<div>Copyright © 2022 BismuthSoft</div>
</footer>
</div>
Expand Down
9 changes: 8 additions & 1 deletion src/lib/audio/Mixer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import VERSION from '../version';
import type {Note, Instrument} from './instrument'
import Voice from './Voice.js'

Expand All @@ -11,7 +12,8 @@ export class Mixer {

writeWave (channels: Float32Array[]) {
channels.forEach((c) => c.fill(0));
this.voices.map((voice) => voice.addWave(channels));
this.voices.forEach((voice) => voice.addWave(channels));

// Deallocate stopped notes. Doesn't need to run often.
this.voices = this.voices.filter((v) => !v.isStopped());
}
Expand Down Expand Up @@ -39,6 +41,11 @@ export class Mixer {
}

setInstrument (index: number, instrument: Instrument) {
if (instrument.version !== VERSION) {
throw new Error(`Incompatible instrument version:
got: ${instrument.version}
expected: ${VERSION}`);
}
this.instruments[index] = instrument;
this.voices.forEach(v => {
// Live update
Expand Down
9 changes: 5 additions & 4 deletions src/lib/audio/instrument.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type {EnvelopeParams} from './envelope';
import defaultInstrumentData from './instruments/Synth Bass.json';
import VERSION from "../version";
import type {EnvelopeParams} from "./envelope";
import defaultInstrumentData from "./instruments/Synth Bass.json";

export const MIN_VOLUME = -72; // Volume at which things will be zeroed

export type Instrument = {
version: '0.0.4-dev1';
version: typeof VERSION;
title: string; // Name of instrument
basePitch: number; // Base pitch in Hz
oscs: OscillatorParams[]; // Oscillator config
Expand All @@ -31,7 +32,7 @@ export type Note = {
export function sineWave (numOscs = 4) : Instrument {
return {
title: 'Sine Wave',
version: '0.0.4-dev1',
version: VERSION,
basePitch: 440,
oscs: Array(numOscs).fill(0).map((_, i) => ({
modulation: Array(i).fill(0),
Expand Down
2 changes: 1 addition & 1 deletion src/lib/audio/instruments/Synth Bass.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.0.4-dev1",
"version": "0.2.0",
"basePitch": 440,
"oscs": [
{
Expand Down
11 changes: 7 additions & 4 deletions src/lib/audio/migration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Instrument, OscillatorParams } from './instrument';
import VERSION from '../version';

export function migrateInstrument (instrument: any): Instrument {
switch (instrument.version) {
Expand All @@ -14,17 +15,19 @@ export function migrateInstrument (instrument: any): Instrument {
}))
case '0.0.2':
instrument.title = instrument.title ?? 'Instrument';
case '0.0.3': // Latest version
case '0.0.3':
instrument.oscs = instrument.oscs.map((osc: OscillatorParams) => ({
...osc,
wave: 'sine',
}))
instrument.version = '0.0.4-dev1';
case '0.0.4-dev1':
instrument.version = '0.2.0';
case '0.2.0':
break;
default:
throw new Error('UNRECOGNIZED VERSION: ' + instrument.version);
}
console.log(instrument);
if (instrument.version !== VERSION) {
throw new Error('Migration has failed to set correct instrument version.')
}
return instrument;
}
18 changes: 17 additions & 1 deletion vite.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { readFileSync, writeFileSync } from 'fs';
import { fileURLToPath } from 'url';

const file = fileURLToPath(new URL('package.json', import.meta.url));
const json = readFileSync(file, 'utf8');
const pkg = JSON.parse(json);

/** @type {import('vite').UserConfig} */
const config = {
plugins: [sveltekit()]
plugins: [sveltekit()],
define: {
__version__ : JSON.stringify(pkg.version),
}
};

const versionFile = `
// AUTO GENERATED -- DO NOT MODIFY
const VERSION: "${pkg.version}" = "${pkg.version}";
export default VERSION;`;

writeFileSync('src/lib/version.ts', versionFile);

export default config;

0 comments on commit 6aa6d2a

Please sign in to comment.