Making a Mono Mode
-
@Casmat said in Making a Mono Mode:
GPL though
I think you mean
GPL though :party_popper: :person_raising_hand_dark_skin_tone: :person_raising_hand: :clapping_hands_medium-light_skin_tone: :1st_place_medal:
-
@d-healey definitely! I’m now debating between going for the sample switching method of legato vs going for the pitch glide method of legato.. I tried your legato script to see how it’d sound l, but after messing with the controls for a while, when it glides up/down, you can hear all the samples in between and they all play from the start, is there a way on your legato script to make it sound more “glidey” instead of that strumming sound?
-
@Casmat yeah you need to use a start offset modulator and drop in another script to control it
-
-
This post is deleted! -
@d-healey revamped mono script:
/* The MIT License (MIT) Copyright © 2017, 2018, 2019, 2020, 2021, 2022 David Healey Permission is hereby granted, free of charge, to any person obtaining a copy of this file (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ Content.setWidth(650); Content.setHeight(50); reg lastNote = -1; reg retrigger = -1; reg eventId; reg vel; reg eventIdQueue = []; reg tempId; reg retrigId; reg noteNum; reg rootNote; //GUI const var bypass = Content.addButton("Bypass", 10, 10); const var time = Content.addKnob("Time", 160, 0); time.setRange(0, 2000, 0.01); inline function onTimeControl(component, value) { eventIdQueue = []; }; Content.getComponent("Time").setControlCallback(onTimeControl); function onNoteOn() { if (!bypass.getValue()) { if (!retrigId == undefined) Synth.noteOffByEventId(retrigId); vel = Message.getVelocity(); noteNum = Message.getNoteNumber(); if(Synth.getNumPressedKeys() == 1) rootNote = Message.getNoteNumber(); if (lastNote == -1) { lastNote = Message.getNoteNumber(); eventId = Message.makeArtificial(); Console.print("Case1"); } else { if (time.getValue() > 0 && eventId != -1) { Message.ignoreEvent(true); Synth.addPitchFade(eventId, time.getValue(), Message.getNoteNumber() - rootNote, 0); Console.print("Case2"); } else { if (eventId != -1) Synth.noteOffByEventId(eventId); eventId = Message.makeArtificial(); Console.print("Case3"); } retrigger = lastNote; lastNote = Message.getNoteNumber(); } eventIdQueue.push( { "eventId": Message.getEventId(), "noteNumber": Message.getNoteNumber() }); } } function onNoteOff() { if (!bypass.getValue()) { Message.ignoreEvent(true); for (id in eventIdQueue) { if (time.getValue() == 0) { if (id["eventId"] == Message.getEventId() + 1) tempId = id; } else { if (id["noteNumber"] == Message.getNoteNumber()) tempId = id; } }; eventIdQueue.remove(tempId); if (!Synth.isKeyDown(rootNote) && time.getValue() == 0) rootNote = eventIdQueue[0]["noteNumber"]; if (!noteNum == undefined && !Synth.isKeyDown(noteNum) && time.getValue() == 0) { if (!retrigId == undefined) Synth.noteOffByEventId(retrigId); retrigId = undefined; } Console.print(Message.getNoteNumber()); Console.print(noteNum); //Console.print(rootNote); if (Message.getNoteNumber() == noteNum && eventIdQueue.length > 0 && time.getValue() == 0) { eventIdQueue.reverse(); retrigId = Synth.playNote(eventIdQueue[0]["noteNumber"], vel); noteNum = eventIdQueue[0]["noteNumber"]; Synth.noteOffByEventId(eventId); eventIdQueue.reverse(); lastNote = retrigger; retrigger = -1; Console.print("test"); } if (eventId != -1) { if (eventIdQueue.length > 0 && time.getValue() > 0) { eventIdQueue.reverse(); Synth.addPitchFade(eventId, time.getValue(), eventIdQueue[0]["noteNumber"] - rootNote, 0); noteNum = eventIdQueue[0]["noteNumber"]; eventIdQueue.reverse(); lastNote = retrigger; //retrigger = -1; --Causes wierd audio glitches since first if statement on the onNote callback is activated } else { Synth.noteOffByEventId(eventId); eventId = -1; Console.print("RAH1"); } } if (!Synth.getNumPressedKeys()) { Synth.noteOffByEventId(eventId); lastNote = -1; Console.print("RAH2"); } } else if (eventId != -1 && eventId != undefined) { Synth.noteOffByEventId(eventId); eventId = -1; lastNote = -1; eventIdQueue = []; } /*Console.print("new"); for(i in eventIdQueue) { Console.print(i); };*/ } function onController() { } function onTimer() { } function onControl(number, value) { }
I made some changes to your script to get last note retriggering working! Most everything works, except for one thing, I tried finding the cause of the issue (you may see some console print statements scattered), but unsuccessful. Basically, the problem occurs when you try to "glide" from two notes. Lets say you press C, then while holding C, you press E, E plays, but as soon as you let go of C, E stops playing.
if (Message.getNoteNumber() == noteNum && eventIdQueue.length > 0 && time.getValue() == 0) //... if (eventIdQueue.length > 0 && time.getValue() > 0)
I think i traced the problem to these if statements where the first one does what I mentioned above, but when I deleted the
Message.getNoteNumber() == noteNum
line (the second if statement), Instead of E stopping, It gets retriggered. Any ideas to fix?Edit: there's also probably a lot of unnecessary code since i didn't replace most of your existing code which may/may not be functional due to my changes... I only removed the lastTuning variable since it was the one causing the pitch issues, all to fix was just add a rootNote var
Thanks!
-
eventIdQueue.push(
{
"eventId": Message.getEventId(),
"noteNumber": Message.getNoteNumber()This kind of thing is slow/inefficient. Use a midi list:
ml.setValue(Message.getNoteNumber(), Message.getEventId());
if (!noteNum == undefined
This logic is confusing, do you want to check if noteNum is defined or if it's not defined?
You probably want to use
if (!isDefined(noteNum))
Same here
if (!retrigId == undefined)
Don't put if statements on a single line, it makes the intent of the code less clear at a glance.
-
@d-healey I’m stuck trying to figure out how I can use a midi list in my case.. I tried to read the docs but there’s little info, how can I use the midi list to replicate the array system I had? In the previous system, I had stored the event Id and note number in an object that is created for each note on and deleted on the note off. The objects could be ordered in a list such that the last value would be the next one in line to be retriggered. How could I replicate this? And would this solve notes turning off when others are released?
-
@Casmat said in Making a Mono Mode:
The objects could be ordered in a list such that the last value would be the next one in line to be retriggered. How could I replicate this?
This shouldn't be needed. In a mono system there is only ever one active note and one old note. With retrigger you have potentially two old notes. So at max you need to keep track of those three notes.
And would this solve notes turning off when others are released?
If you are making artificial notes you still need to turn them off.
A midi list is an array with 128 elements that is optimized for this kind of task.
To create a midi list use:
const eventIds = Engine.createMidiList();
To store the event triggered by note 60 (for example):
eventIds.setValue(60, eventId);
To store events as they come in to on note on you would replace 60 with
Message.getNoteNumber()
and eventId withMessage.getEventId();
But you can also store artificial events too.To the get the eventId of note 60:
local eventId = eventIds.getValue(60);
-
@d-healey ohhh, I’m trying to recreate Vital’s mono mode on the “newest” voice setting which keeps track of held notes and prioritizes the newer/latest notes. I’m guessing I wouldn’t be able to hold that much note numbers in midilists, right?
If you are making artificial notes you still need to turn them off..
I thought I took care of all the hanging notes, are there more I didn’t get? The problem is that is I’m doing a regular string of notes, when I let go of the old note while holding a new note I want to hear, the new note retriggers again when the old one is let go
-
@Casmat said in Making a Mono Mode:
I’m trying to recreate Vital’s mono mode on the “newest” voice setting
I'm not familiar with that
I’m guessing I wouldn’t be able to hold that much note numbers in midilists, right?
A MIDI list is just a fast array, so you can definitely use it for this. You just might need more than one.
I thought I took care of all the hanging notes, are there more I didn’t get?
I dunno, I didn't try it. I was responding to this question
And would this solve notes turning off when others are released?