Merge remote-tracking branch 'origin/main' into phaser
This commit is contained in:
commit
b7dd9b7d35
10 changed files with 164 additions and 74 deletions
|
|
@ -923,7 +923,12 @@ const generic_params = [
|
|||
*
|
||||
*/
|
||||
['lsize'],
|
||||
// label for pianoroll
|
||||
/**
|
||||
* Sets the displayed text for an event on the pianoroll
|
||||
*
|
||||
* @name label
|
||||
* @param {string} label text to display
|
||||
*/
|
||||
['activeLabel'],
|
||||
[['label', 'activeLabel']],
|
||||
// ['lfo'],
|
||||
|
|
|
|||
|
|
@ -2191,6 +2191,9 @@ export const duration = register('duration', function (value, pat) {
|
|||
|
||||
/**
|
||||
* Sets the color of the hap in visualizations like pianoroll or highlighting.
|
||||
* @name color
|
||||
* @synonyms colour
|
||||
* @param {string} color Hexadecimal or CSS color name
|
||||
*/
|
||||
// TODO: move this to controls https://github.com/tidalcycles/strudel/issues/288
|
||||
export const { color, colour } = register(['color', 'colour'], function (color, pat) {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,40 @@ Pattern.prototype.pianoroll = function (options = {}) {
|
|||
|
||||
// this function allows drawing a pianoroll without ties to Pattern.prototype
|
||||
// it will probably replace the above in the future
|
||||
|
||||
/**
|
||||
* Displays a midi-style piano roll
|
||||
*
|
||||
* @name pianoroll
|
||||
* @param {Object} options Object containing all the optional following parameters as key value pairs:
|
||||
* @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4
|
||||
* @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5
|
||||
* @param {boolean} vertical displays the roll vertically - 0 by default
|
||||
* @param {boolean} labels displays labels on individual notes (see the label function) - 0 by default
|
||||
* @param {boolean} flipTime reverse the direction of the roll - 0 by default
|
||||
* @param {boolean} flipValues reverse the relative location of notes on the value axis - 0 by default
|
||||
* @param {number} overscan lookup X cycles outside of the cycles window to display notes in advance - 1 by default
|
||||
* @param {boolean} hideNegative hide notes with negative time (before starting playing the pattern) - 0 by default
|
||||
* @param {boolean} smear notes leave a solid trace - 0 by default
|
||||
* @param {boolean} fold notes takes the full value axis width - 0 by default
|
||||
* @param {string} active hexadecimal or CSS color of the active notes - defaults to #FFCA28
|
||||
* @param {string} inactive hexadecimal or CSS color of the inactive notes - defaults to #7491D2
|
||||
* @param {string} background hexadecimal or CSS color of the background - defaults to transparent
|
||||
* @param {string} playheadColor hexadecimal or CSS color of the line representing the play head - defaults to white
|
||||
* @param {boolean} fill notes are filled with color (otherwise only the label is displayed) - 0 by default
|
||||
* @param {boolean} fillActive active notes are filled with color - 0 by default
|
||||
* @param {boolean} stroke notes are shown with colored borders - 0 by default
|
||||
* @param {boolean} strokeActive active notes are shown with colored borders - 0 by default
|
||||
* @param {boolean} hideInactive only active notes are shown - 0 by default
|
||||
* @param {boolean} colorizeInactive use note color for inactive notes - 1 by default
|
||||
* @param {string} fontFamily define the font used by notes labels - defaults to 'monospace'
|
||||
* @param {integer} minMidi minimum note value to display on the value axis - defaults to 10
|
||||
* @param {integer} maxMidi maximum note value to display on the value axis - defaults to 90
|
||||
* @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default
|
||||
*
|
||||
* @example
|
||||
* note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1})
|
||||
*/
|
||||
export function pianoroll({
|
||||
time,
|
||||
haps,
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ export async function loadOrc(url) {
|
|||
export const csoundm = register('csoundm', (instrument, pat) => {
|
||||
let p1 = instrument;
|
||||
if (typeof instrument === 'string') {
|
||||
p1 = `"{instrument}"`;
|
||||
p1 = `"${instrument}"`;
|
||||
}
|
||||
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
|
||||
return pat.onTrigger((tidal_time, hap) => {
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||
|
||||
import { Pattern, isPattern } from '@strudel.cycles/core';
|
||||
|
||||
var writeMessage;
|
||||
var writeMessagers = {};
|
||||
var choosing = false;
|
||||
|
||||
export async function getWriter(br = 38400) {
|
||||
export async function getWriter(name, br) {
|
||||
if (choosing) {
|
||||
return;
|
||||
}
|
||||
choosing = true;
|
||||
if (writeMessage) {
|
||||
return writeMessage;
|
||||
if (name in writeMessagers) {
|
||||
return writeMessagers[name];
|
||||
}
|
||||
if ('serial' in navigator) {
|
||||
const port = await navigator.serial.requestPort();
|
||||
await port.open({ baudRate: br });
|
||||
const encoder = new TextEncoder();
|
||||
const writer = port.writable.getWriter();
|
||||
writeMessage = function (message, chk) {
|
||||
writeMessagers[name] = function (message, chk) {
|
||||
const encoded = encoder.encode(message);
|
||||
if (!chk) {
|
||||
writer.write(encoded);
|
||||
|
|
@ -63,10 +63,10 @@ function crc16(data) {
|
|||
return crc & 0xffff;
|
||||
}
|
||||
|
||||
Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids = false) {
|
||||
Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids = false, name = 'default') {
|
||||
return this.withHap((hap) => {
|
||||
if (!writeMessage) {
|
||||
getWriter(br);
|
||||
if (!(name in writeMessagers)) {
|
||||
getWriter(name, br);
|
||||
}
|
||||
const onTrigger = (time, hap, currentTime) => {
|
||||
var message = '';
|
||||
|
|
@ -108,7 +108,7 @@ Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids
|
|||
const offset = (time - currentTime + latency) * 1000;
|
||||
|
||||
window.setTimeout(function () {
|
||||
writeMessage(message, chk);
|
||||
writeMessagers[name](message, chk);
|
||||
}, offset);
|
||||
};
|
||||
return hap.setContext({ ...hap.context, onTrigger, dominantTrigger: true });
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol
|
|||
const bufferSource = ac.createBufferSource();
|
||||
bufferSource.buffer = buffer;
|
||||
const playbackRate = 1.0 * Math.pow(2, transpose / 12);
|
||||
// bufferSource.playbackRate.value = Math.pow(2, transpose / 12);
|
||||
bufferSource.playbackRate.value = playbackRate;
|
||||
return bufferSource;
|
||||
};
|
||||
|
|
@ -240,6 +239,8 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
|||
begin = 0,
|
||||
loopEnd = 1,
|
||||
end = 1,
|
||||
vib,
|
||||
vibmod = 0.5,
|
||||
} = value;
|
||||
// load sample
|
||||
if (speed === 0) {
|
||||
|
|
@ -255,6 +256,19 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
|||
|
||||
const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl);
|
||||
|
||||
// vibrato
|
||||
let vibratoOscillator;
|
||||
if (vib > 0) {
|
||||
vibratoOscillator = getAudioContext().createOscillator();
|
||||
vibratoOscillator.frequency.value = vib;
|
||||
const gain = getAudioContext().createGain();
|
||||
// Vibmod is the amount of vibrato, in semitones
|
||||
gain.gain.value = vibmod * 100;
|
||||
vibratoOscillator.connect(gain);
|
||||
gain.connect(bufferSource.detune);
|
||||
vibratoOscillator.start(0);
|
||||
}
|
||||
|
||||
// asny stuff above took too long?
|
||||
if (ac.currentTime > t) {
|
||||
logger(`[sampler] still loading sound "${s}:${n}"`, 'highlight');
|
||||
|
|
@ -286,6 +300,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
|||
envelope.connect(out);
|
||||
bufferSource.onended = function () {
|
||||
bufferSource.disconnect();
|
||||
vibratoOscillator?.stop();
|
||||
envelope.disconnect();
|
||||
out.disconnect();
|
||||
onended();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue