UNPKG

node-red-contrib-music

Version:

Synthesise music with node-red. The beat node creates regular beats at a rate you can control, and which can be sunchronised with other machines. The divider node adds information to beat events, dividing beats into bars, bars into phrases, phrases into s

165 lines (126 loc) 5.68 kB
<script type="text/javascript"> const fxtypesURL = "node-red-contrib-music/fxtypes"; let fxtypes; $.getJSON(fxtypesURL, function (data) { fxtypes = data; }); RED.nodes.registerType('soundfx',{ category: 'music', color: '#a6bbcf', defaults: { fxtype: {value: "reverb", required: "true"}, volume: {value: 100}, fxcontrols: {value: {}} }, inputs:1, inputLabels:"supercollider instructions, fxcontrol:", outputs:1, outputLabels:["supercollider instructions"], icon: "effect.png", label: function() { return this.name || this.fxtype || "soundfx"; }, oneditprepare: function(){ node = this; function setFXDescription(){ let fxdescription = fxtypes[node.fxtype].description || " "; $('#node-input-fxtype-description').html(fxdescription); } function populateFxtypeSelect(){ let fxtypeList = [] for(let fxtype in fxtypes){ fxtypeList.push(fxtype); } fxtypeList.sort(); const select = $("#node-input-fxtype"); select.empty(); for(let fxtype of fxtypeList){ let row = $("<option value='" + fxtype + "'>" + fxtype + "</option>"); if(node.fxtype === fxtype){ row.attr("selected", "selected"); } select.append(row); } setFXDescription(); select.change(function () { const option = $(this).find('option:selected').val(); if (option !== node.fxtype) { node.fxtype = option; setFXDescription(); node.fxcontrols = {}; $('#node-input-fxcontrol-container').empty(); populateFxcontrols(); } } ); } function populateFxcontrols(){ const fxcontrolSpecs = fxtypes[node.fxtype].fxcontrols || {}; const container = $('#node-input-fxcontrol-container'); let noControls = true; for(let fxcontrol in fxcontrolSpecs){ let row = $('<div/>', {class: 'form-row'}).appendTo(container); let id = 'node-input-fxcontrol-' + fxcontrol; let fxdetails = fxcontrolSpecs[fxcontrol] || {}; let max = fxdetails.max || 1; let min = fxdetails.min || 0; let default_ = fxdetails.default; let description = fxdetails.description?(fxdetails.description + '. '):''; let info = `${description}min: ${min}, max: ${max}, default: ${default_}`; let value = node.fxcontrols[fxcontrol] || default_; let labelElement = $(`<label>${fxcontrol}</label>`, {'for': id}).appendTo(row); let step = Math.pow(10, Math.floor(Math.log10(max - min)) - 2); let valueField = $('<input/>',{id: id, class: "node-input-fxcontrol", width: "7em", type:"number", min:min, max: max, step: step}).appendTo(row); valueField.val(value); let infoElement = $(`<div><small>${info}</small></div>`, {style: 'float:right'}).appendTo(row); noControls = false; } if (noControls) { $("<div><i>None</i></div>div").appendTo(container); } } populateFxtypeSelect(); populateFxcontrols(); }, oneditsave: function(){ let fxcontrols = $('.node-input-fxcontrol'); fxcontrols.each(function(){ const control_id = $(this).attr('id'); const control = control_id.split('-').pop(); const value =$(this).val(); node.fxcontrols[control] = value; } ); } }); </script> <script type="text/x-red" data-template-name="soundfx"> <div class="form-row"> <label for="node-input-fxtype" width="25em">Effect Type</label> <select id="node-input-fxtype"> </select> </div> <div class="form-row" id="node-input-fxtype-description"></div> <div class="form-row" width="25em"><b>Effect controls (fxcontrol)</b></div> <div id="node-input-fxcontrol-container"> </div> </script> <script type="text/x-red" data-help-name="soundfx"> <p>Add a SuperCollider sound effect to a synth sound</p> <h3>Inputs</h3> <p>A <code>soundfx</code> node gets its input from a <code>synth</code> node.</p> <dl class='message-properties'> <dt class="optional">topic <span class="property-type">string</span></dt> <dd> <p>If <code>msg.topic</code> starts with <code>fxcontrol:</code> then the rest of the <code>msg.topic</code> is interpreted as a SuperCollider sound effect parameter name, and the <code>msg.payload</code> is used as its value. The parameters (fxcontrol) that can be changed vary from effect to effect, and their details can be seen in the configuration.</p></dd> </dl> <h3>Outputs</h3> <p>A <code>soundfx</code> node sends its output to a <code>osc</code> node.</p> <h3>Configuration</h3> <dl class='message-properties'> <dt><span class='optional'>Effect type</span> <span class='property-type'>string</span></dt> <dd>The name of the sound effect type to use.</dd> <dt><span class='optional'>Effect controls (fxcontrol)</span> <span class='property-type'>number</span></dt> <dd>Each sound effect has its own set of parameters that control its operation.</dd> </dl> </script>