Added scientific pitch notation and named chords for sound

This commit is contained in:
2023-09-22 02:13:39 +03:00
parent 0816356dc7
commit eb2b82e363
3 changed files with 71 additions and 6 deletions

View File

@ -1,3 +1,4 @@
import { noteNameToMidi } from "zifferjs";
import { type UserAPI } from "./API"; import { type UserAPI } from "./API";
import { Player } from "./classes/ZPlayer"; import { Player } from "./classes/ZPlayer";
export {}; export {};
@ -30,6 +31,7 @@ declare global {
z14(): Player; z14(): Player;
z15(): Player; z15(): Player;
z16(): Player; z16(): Player;
note(): number;
} }
} }
@ -79,7 +81,7 @@ export const makeStringExtensions = (api: UserAPI) => {
String.prototype.z = function (options: {[key: string]: any} = {}) { String.prototype.z = function (options: {[key: string]: any} = {}) {
return api.z(this.valueOf(), options); return api.z(this.valueOf(), options);
}; };
String.prototype.z0 = function (options: {[key: string]: any} = {}) { String.prototype.z0 = function (options: {[key: string]: any} = {}) {
return api.z0(this.valueOf(), options); return api.z0(this.valueOf(), options);
}; };
@ -148,6 +150,13 @@ export const makeStringExtensions = (api: UserAPI) => {
return api.z16(this.valueOf(), options); return api.z16(this.valueOf(), options);
}; };
String.prototype.note = function () {
try {
return parseInt(this.valueOf());
} catch (e) {
return noteNameToMidi(this.valueOf());
}
};
} }
type SpeechOptions = { type SpeechOptions = {

View File

@ -1,6 +1,6 @@
import { type Editor } from "../main"; import { type Editor } from "../main";
import { AudibleEvent } from "./AbstractEvents"; import { AudibleEvent } from "./AbstractEvents";
import { midiToFreq, noteFromPc } from "zifferjs"; import { chord as parseChord, midiToFreq, noteFromPc, noteNameToMidi } from "zifferjs";
import { import {
superdough, superdough,
@ -230,13 +230,42 @@ export class SoundEvent extends AudibleEvent {
// Frequency management // Frequency management
public sound = (value: string) => this.updateValue("s", value); 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 snd = this.sound;
public nudge = (value: number) => this.updateValue("nudge", value); public nudge = (value: number) => this.updateValue("nudge", value);
public cut = (value: number) => this.updateValue("cut", value); public cut = (value: number) => this.updateValue("cut", value);
public clip = (value: number) => this.updateValue("clip", value); public clip = (value: number) => this.updateValue("clip", value);
public n = (value: number) => this.updateValue("n", 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 speed = (value: number) => this.updateValue("speed", value);
public spd = this.speed; public spd = this.speed;

View File

@ -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: Two functions are primarily used to control the frequency of the synthesizer:
- <ic>freq(hz: number)</ic>: sets the frequency of the oscillator. - <ic>freq(hz: number)</ic>: sets the frequency of the oscillator.
- <ic>note(note: number)</ic>: sets the MIDI note of the oscillator (MIDI note converted to hertz). - <ic>note(note: number|string)</ic>: sets the MIDI note of the oscillator (MIDI note converted to hertz).
${makeExample( ${makeExample(
"Selecting a pitch or note", "Selecting a pitch",
` `
beat(.5) && snd('triangle').freq([100,200,400].beat(2)).out() beat(.5) && snd('triangle').freq([100,200,400].beat(2)).out()
`, `,
true true
)} )}
${makeExample(
"Selecting a note",
`
beat(.5) && snd('triangle').note([60,"F4"].pick()).out()
`,
true
)}
Chords can also played using different parameters:
-<ic>chord(string||number[]|...number)</ic>: 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 ## 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. 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.