-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Easier midi usage #118
base: develop
Are you sure you want to change the base?
Easier midi usage #118
Conversation
Hi @polhomarkho, I'm wondering if the specific UI that you are adding here could be done in a javascript file. So we could have a So you could do something like
Anyway thats is only an idea :) Ping me when you have an example that I can try with the new functionally and I will review the pull request with more detail! |
- added a chord parser - added a note player to avoid issue when two identical notes are played - added a new way to create notes from the js using the note name instead of midi pitch - added new midi widgets to create easily midi actions (note button, control slider...)
cb6e52f
to
96778f6
Compare
Hi @victordiaz, sorry for the delay! It took me some time to have everything working with the repo cleanup 😅 Here's an example to play with: /*
* Description simple midi controller to control a soft synth on a computer
* by Paul-Emile Sublet <[email protected]>
*/
// globals
const redColor = '#FF0000';
var buttonPositionX;
var buttonPositionY;
const buttonSize = 0.19;
const buttonSpacing = 0.01;
// start program
const midi = media.startMidiController();
const inputs = midi.findAvailableMidiInputs();
if (!inputs.length) {
ui.toast('no midi input available :(');
app.close();
} else if (inputs.length === 1) {
const selectedDeviceInputId = inputs[0].deviceInputId;
midi.setupMidi(selectedDeviceInputId);
displayUi();
} else {
// Select a midi input to send data to the computer if multiple midi inputs are found
ui.popup()
.title('Choose a midi input:')
.choice(inputs.map(function (input) {
return input.name;
}))
.onAction(function (selectedElement) {
const selectedElementIndex = selectedElement.answerId;
const selectedDeviceInputId = inputs[selectedElementIndex].deviceInputId;
midi.setupMidi(selectedDeviceInputId);
displayUi();
})
.show();
}
function displayUi() {
buttonPositionX = 0;
buttonPositionY = 0;
// chord using midi pitches
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withText('C maj from pitches')
.withNotePitches(60, 64)
.addNotePitch(67); // for the sake of the demo, could be in `withNotePitches()`
movePositionForNextButton();
// chord using note names
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withText('Dm7 from note names')
.withNoteNames('D4', 'F4', 'A4')
.addNoteName('C5'); // for the sake of the demo, could be in `withNoteNames()`
movePositionForNextButton();
// complex chord using all note parameters
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withText("E4 ch2, G4 ch2 velo 20, B4 ch1")
.withNotes(
{
name: 'E4',
channel: 1
},
{
name: 'G4',
channel: 1,
velocity: 20
})
.addNote({name: 'B4'}); // for the sake of the demo, could be in `withNotes()`
movePositionForNextButton();
// 5th degree chord from a mixolydian mode of C major
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withDegreeAndMode({rootName: 'C4', degree: 'V', mode: 'mixolydian', chordSize: 4});
movePositionForNextButton();
// F sharp major seventh sharp five Chord :-D
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withChord(
{
name: 'F#maj7s5',
octave: 4,
velocity: 100,
channel: 1 // not affected by pitch bend as it's channel 1
});
movePositionToNewlineForNextButton();
// standard major chord progression (in F here)
['I', 'V', 'VI', 'IV'].forEach(function (chordDegree) {
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withDegreeAndMode({rootName: 'F3', degree: chordDegree, mode: 'major'})
.withBackgroundColorWhenPlayed(redColor);
movePositionForNextButton();
});
movePositionToNewlineForNextButton();
// chord progression of the final part of "hey jude" from the Beetles: mixolydian mode F major scale
['VII', 'IV', 'I'].forEach(function (chordDegree) {
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withDegreeAndMode({rootName: 'F4', degree: chordDegree, mode: 'mixolydian'})
.withBackgroundColorWhenPlayed(redColor);
movePositionForNextButton();
});
movePositionToNewlineForNextButton();
// "where is my mind" from the Pixies chord progression
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withChord({name: 'E', octave: 4});
movePositionForNextButton();
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withChord({name: 'C#m', octave: 4});
movePositionForNextButton();
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withChord({name: 'G#', octave: 4});
movePositionForNextButton();
midi.ui.addNoteButton(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withChord({name: 'A', octave: 4});
movePositionToNewlineForNextButton();
// Controls
midi.ui.addModulationWheelSlider(buttonPositionX, buttonPositionY, buttonSize, buttonSize);
movePositionForNextButton();
midi.ui.addCcSlider(buttonPositionX, buttonPositionY, buttonSize, buttonSize, 74)
.withChannel(3)
.withText('filter');
movePositionForNextButton();
midi.ui.addCcSlider(buttonPositionX, buttonPositionY, buttonSize, buttonSize, 71)
.withText('timbre');
movePositionForNextButton();
midi.ui.addPitchBendSlider(buttonPositionX, buttonPositionY, buttonSize, buttonSize);
movePositionForNextButton();
midi.ui.addPitchBendSlider(buttonPositionX, buttonPositionY, buttonSize, buttonSize)
.withText('bend ch1')
.withChannel(1);
movePositionForNextButton();
}
function movePositionForNextButton() {
// Buttons are displayed from left to right and go to newline when overflowing
if (buttonPositionX + buttonSize + buttonSpacing >= 1) {
buttonPositionX = 0;
buttonPositionY += buttonSize + buttonSpacing;
} else {
buttonPositionX += buttonSize + buttonSpacing;
}
}
function movePositionToNewlineForNextButton() {
buttonPositionX = 2; // force overflow :D
movePositionForNextButton();
} It's quite verbose and many method calls are not required but they are here to show what you can do. |
@polhomarkho Thanks for this, I will review it soon. So I was thinking that this cool example that you made, could fit a new category called Demos. I'm thinking about this, because I have lots of projects that I've done in the past years that are getting lost in my hard drive. I would love to know what you think about it! |
Hi @victordiaz, that's a good idea. The midi example in this PR shows mainly the midi ui usage and it starts to be a bit big and hard to understand so it would probably fit in a demo section. |
Hi Victor!
I had some success adding the
About the first issue I had (local project To come back to your suggestion, after reading again the classes in Thanks! |
Hi @polhomarkho, Adding a require method could become handy also! Regarding the UI methods that you added, I'm not superconvinced. I think it might be a bit confusing to have UI methods for very specific needs. In PHONK "I try" to keep things a bit simple. Having specific .js files within the project with custom UI would be a better approach to keep more canonical the rest of the API. So for example if you want to reference the constants in those .js files, you could always move the constants inside the class midi, so they could be accessed like this in your .js file I will try to play with this today though :) |
hi @polhomarkho All the best! |
Hello Victor!
Here is a merge request to have an easier access to midi functions and music stuff more generally.
The code is ready (I just want to review it myself a last time tomorrow) but I'm working on adding a good example script in the
PHONK-examples
directory.I'm not sure if the code follows the "rules" of PHONK as it makes midi things quite high level and accessible but it's really midi oriented so please tell me if it's not what you want in your app 😅
Here is what I added: