channel splitting and channels parameter

This commit is contained in:
Jade Rowland 2023-11-23 01:04:53 -05:00
parent f0b458cd17
commit e419733716
2 changed files with 42 additions and 34 deletions

View File

@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Pattern, register, sequence } from './pattern.mjs'; import { Pattern, register, reify, sequence } from './pattern.mjs';
import { zipWith } from './util.mjs'; import { zipWith } from './util.mjs';
const controls = {}; const controls = {};
@ -381,18 +381,18 @@ const generic_params = [
*/ */
['coarse'], ['coarse'],
/** // /**
* Allows you to set the output channels on the interface // * Allows you to set the output channels on the interface
* // *
* @name channels // * @name channels
* @synonyms ch // * @synonyms ch
* // *
* @param {!Float32Array} channels Array<int> // * @param {!Float32Array} channels Array<int>
* @example // * @example
* note("e a d b g").channels([2, 3]).room(1) // * note("e a d b g").channels([2, 3]).room(1)
* // *
*/ // */
['channels', 'ch'], // ['channels', 'ch'],
['phaserrate', 'phasr'], // superdirt only ['phaserrate', 'phasr'], // superdirt only
@ -1390,4 +1390,13 @@ controls.ds = register('ds', (ds, pat) => {
return pat.set({ decay, sustain }); return pat.set({ decay, sustain });
}); });
controls.ch = register(['channels', 'ch'], (channels, pat) => {
channels = !Array.isArray(channels) ? [channels] : channels;
// channels = channels.map(reify).map((channelPat) => {
// // How do I return the current value of the channel pattern here?
// });
return pat.set({ channels });
});
export default controls; export default controls;

View File

@ -31,38 +31,33 @@ let audioContext;
export const getAudioContext = () => { export const getAudioContext = () => {
if (!audioContext) { if (!audioContext) {
audioContext = new AudioContext(); audioContext = new AudioContext();
var maxChannelCount = audioContext.destination.maxChannelCount; const maxChannelCount = audioContext.destination.maxChannelCount;
audioContext.destination.channelCount = maxChannelCount; audioContext.destination.channelCount = maxChannelCount;
} }
//console.log(audioContext.destination.maxChannelCount);
return audioContext; return audioContext;
}; };
// outputs: Map<int, audiGainNode> // outputs: Map<int, GainNode>
const outputs = new Map(); const outputs = new Map();
let channelMerger; let channelMerger;
// channels: Array<int> // channels: Array<int>
const getDestinations = (channels) => { const getDestinations = (channels) => {
const ctx = getAudioContext(); const ctx = getAudioContext();
if (channelMerger == null) { if (channelMerger == null) {
channelMerger = ctx.createChannelMerger(ctx.destination.channelCount); channelMerger = new ChannelMergerNode(ctx, { numberOfInputs: ctx.destination.channelCount });
channelMerger.connect(ctx.destination); channelMerger.connect(ctx.destination);
} }
channels.forEach((ch) => { channels.forEach((ch) => {
if (!outputs.has(ch)) { if (!outputs.has(ch)) {
const gain = ctx.createGain(); const gain = new GainNode(ctx, {
gain.channelInterpretation = 'discrete'; channelInterpretation: 'discrete',
channelCount: 1,
channelCountMode: 'explicit',
});
gain.connect(channelMerger, 0, ch); gain.connect(channelMerger, 0, ch);
outputs.set(ch, gain); outputs.set(ch, gain);
} }
}); });
// if (!destination) {
// destination = ctx.createGain();
// channelMerger = ctx.createChannelMerger(ctx.destination.channelCount);
// channelMerger.connect(ctx.destination);
// destination.connect(channelMerger, 0, 4);
// destination.connect(channelMerger, 0, 5);
// }
return channels.map((ch) => outputs.get(ch)); return channels.map((ch) => outputs.get(ch));
}; };
@ -121,10 +116,15 @@ const maxfeedback = 0.98;
//input: audioNode, channels: Array<int> //input: audioNode, channels: Array<int>
const connectToOutputs = (input, channels = [0, 1]) => { const connectToOutputs = (input, channels = [0, 1]) => {
const outputs = getDestinations(channels); const outputs = getDestinations(channels);
console.log(input); const ctx = getAudioContext();
const center = new StereoPannerNode(ctx);
input.connect(center);
const splitter = new ChannelSplitterNode(ctx, {
numberOfOutputs: input.channelCount,
});
center.connect(splitter);
outputs.forEach((output, i) => { outputs.forEach((output, i) => {
input.connect(output, 0); splitter.connect(output, i % input.channelCount, 0);
}); });
}; };
@ -333,6 +333,7 @@ export const superdough = async (value, deadline, hapDuration) => {
compressorAttack, compressorAttack,
compressorRelease, compressorRelease,
} = value; } = value;
gain *= velocity; // legacy fix for velocity gain *= velocity; // legacy fix for velocity
let toDisconnect = []; // audio nodes that will be disconnected when the source has ended let toDisconnect = []; // audio nodes that will be disconnected when the source has ended
const onended = () => { const onended = () => {
@ -466,11 +467,9 @@ export const superdough = async (value, deadline, hapDuration) => {
} }
// last gain // last gain
const post = gainNode(postgain); const post = new GainNode(ac, { gain: postgain });
chain.push(post); chain.push(post);
console.log(channels); connectToOutputs(post, channels);
// this should be an array but is getting interpreted as an int for some reason...
connectToOutputs(post, [channels]);
// delay // delay
let delaySend; let delaySend;