diff --git a/src/StringExtensions.ts b/src/StringExtensions.ts
index b1a3261..ba85df0 100644
--- a/src/StringExtensions.ts
+++ b/src/StringExtensions.ts
@@ -1,3 +1,4 @@
+import { noteNameToMidi } from "zifferjs";
import { type UserAPI } from "./API";
import { Player } from "./classes/ZPlayer";
export {};
@@ -30,6 +31,7 @@ declare global {
z14(): Player;
z15(): Player;
z16(): Player;
+ note(): number;
}
}
@@ -79,7 +81,7 @@ export const makeStringExtensions = (api: UserAPI) => {
String.prototype.z = function (options: {[key: string]: any} = {}) {
return api.z(this.valueOf(), options);
};
-
+
String.prototype.z0 = function (options: {[key: string]: any} = {}) {
return api.z0(this.valueOf(), options);
};
@@ -148,6 +150,13 @@ export const makeStringExtensions = (api: UserAPI) => {
return api.z16(this.valueOf(), options);
};
+ String.prototype.note = function () {
+ try {
+ return parseInt(this.valueOf());
+ } catch (e) {
+ return noteNameToMidi(this.valueOf());
+ }
+ };
}
type SpeechOptions = {
diff --git a/src/classes/SoundEvent.ts b/src/classes/SoundEvent.ts
index ccacdba..60ed0d9 100644
--- a/src/classes/SoundEvent.ts
+++ b/src/classes/SoundEvent.ts
@@ -1,6 +1,6 @@
import { type Editor } from "../main";
import { AudibleEvent } from "./AbstractEvents";
-import { midiToFreq, noteFromPc } from "zifferjs";
+import { chord as parseChord, midiToFreq, noteFromPc, noteNameToMidi } from "zifferjs";
import {
superdough,
@@ -230,13 +230,42 @@ export class SoundEvent extends AudibleEvent {
// Frequency management
public sound = (value: string) => this.updateValue("s", value);
- public chord = (value: object[]) => this.updateValue("chord", value);
+ public chord = (value: string|object[]|number[]|number,...kwargs: number[]) => {
+ if(typeof value === "string") {
+ const chord = parseChord(value);
+ value = chord.map((note: number) => { return {note: note, freq: midiToFreq(note) } });
+ } else if(value instanceof Array && typeof value[0] === "number") {
+ value = (value as number[]).map((note: number) => { return {note: note, freq: midiToFreq(note) } });
+ } else if (typeof value === "number" && kwargs.length > 0) {
+ value = [value, ...kwargs].map((note: number) => { return {note: note, freq: midiToFreq(note) } });
+ }
+ return this.updateValue("chord", value);
+ }
+ public invert = (howMany: number = 0) => {
+ if(this.values.chord) {
+ let notes = this.values.chord.map((obj: { [key: string]: number }) => obj.note);
+ notes = howMany < 0 ? [...notes].reverse() : notes;
+ for (let i = 0; i < Math.abs(howMany); i++) {
+ notes[i % notes.length] += howMany <= 0 ? -12 : 12;
+ }
+ const chord = notes.map((note: number) => { return {note: note, freq: midiToFreq(note) } });
+ return this.updateValue("chord", chord);
+ } else {
+ return this;
+ }
+ }
public snd = this.sound;
public nudge = (value: number) => this.updateValue("nudge", value);
public cut = (value: number) => this.updateValue("cut", value);
public clip = (value: number) => this.updateValue("clip", value);
public n = (value: number) => this.updateValue("n", value);
- public note = (value: number) => this.updateValue("note", value);
+ public note = (value: number|string) => {
+ if(typeof value === "string") {
+ return this.updateValue("note", noteNameToMidi(value));
+ } else {
+ return this.updateValue("note", value);
+ }
+ };
public speed = (value: number) => this.updateValue("speed", value);
public spd = this.speed;
diff --git a/src/documentation/synths.ts b/src/documentation/synths.ts
index 63c0702..88c6241 100644
--- a/src/documentation/synths.ts
+++ b/src/documentation/synths.ts
@@ -22,16 +22,43 @@ beat(.5) && snd(['sine', 'triangle', 'sawtooth', 'square'].beat()).freq(100).out
Two functions are primarily used to control the frequency of the synthesizer:
- freq(hz: number): sets the frequency of the oscillator.
-- note(note: number): sets the MIDI note of the oscillator (MIDI note converted to hertz).
+- note(note: number|string): sets the MIDI note of the oscillator (MIDI note converted to hertz).
${makeExample(
- "Selecting a pitch or note",
+ "Selecting a pitch",
`
beat(.5) && snd('triangle').freq([100,200,400].beat(2)).out()
`,
true
)}
+ ${makeExample(
+ "Selecting a note",
+ `
+beat(.5) && snd('triangle').note([60,"F4"].pick()).out()
+`,
+ true
+ )}
+
+Chords can also played using different parameters:
+-chord(string||number[]|...number): parses and sets notes for the chord
+
+${makeExample(
+ "Playing a named chord",
+ `
+ beat(1) && snd('triangle').chord(["C","Em7","Fmaj7","Emin"].beat(2)).out()
+`,
+ true
+ )}
+
+${makeExample(
+ "Playing a chord from a list of notes and doing inversions",
+ `
+ beat(.5) && snd('triangle').chord(60,64,67,72).invert([1,-3,4,-5].pick()).out()
+`,
+ true
+ )}
+
## Vibrato
You can also add some amount of vibrato to the sound using the vib and vibmod methods. These can turn any oscillator into something more lively and/or into a sound effect when used with a high amount of modulation.