Plugin access to MIDI - Sight Reader?
Can a JavaScript plugin take input from a MIDI keyboard?
I have in mind a tool to help with sight-reading. MuseScore would display the tune and at each stage the plugin would turn notes a different colour when they have been played. The plugin would not check tempo, just check that all the required notes are down, with no extras.
Comments
No. Javascript plugins don't have access to MIDI keyboard currently. You could create an independent application and call MuseScore via OSC to highlight the notes though. See osc.cpp in the source code.
In reply to No. Javascript plugins don't by [DELETED] 5
Thanks.
For your suggestion to work, I'd need to get the tune out of MuseScore into my sight-reading program, then monitor the MIDI keyboard, match up the notes and send messages to MuseScore to colour in the correct notes.
I can handle the MIDI control and note matching, but can I get the tune out of MuseScore using osc?
I usually work in Java, not C++, so would I have to compile your osc.cpp into a DLL, then generate a Java wrapper that I can call from my Java code?
Or is it easier to just send bytes to the port 5282 directly from Java, perhaps using this: http://opensoundcontrol.org/implementation/java-osc?
In reply to Thanks. For your suggestion by DonH
osc.cpp contains the list of commands that MuseScore can handle. You might need to happend some more here if you need to activate some features through OSC that are not listed yet.
You could add a command to save to MIDI in the osc command lists or call a plugin that will do so
Your java software could also be run by a MuseScore plugin. The user launches the plugin, the current score is saved as MIDI by the plugin (this is already possible), then the plugin launches your java software, your java software handle MIDI in and note matching, and it sends OSC message to MuseScore to do the coloring.
In MuseScore trunk, there is a osc command /color-notes it takes a tick,pitch argument and it will color the note in red.
In reply to osc.cpp contains the list of by [DELETED] 5
Sounds good.
For the colorNotes method there are two int arguments. How is the tick measured? Is it related to the tag in the MusicXML file? How do I work out the int for the pitch? Is it the MIDI note number?
Thanks.
In reply to Sounds good. For the by DonH
MIDI note numbers and midi ticks in the MIDI file you got by saving it in MuseScore. (nothing related with MusicXML).
The /color-notes is ugly... it's a string argument, comma separated. If I get a change, I will change it to two int...
In reply to MIDI note numbers and midi by [DELETED] 5
Thanks. This is starting to look workable.
I am working with MuseScore V1.1. Is this OK, or do I need V1.2, or the trunk from your Subversion?
I have written a short piece of test code using the Java OSC (http://opensoundcontrol.org/implementation/java-osc), but it has no effect. No errors reported. The MIDI file has the C an octave above middle C and also an E just above middle C at tick 0.
I would also like to be able to control the colour - could you add that as a parameter?
Here's my test code...
package com.dch.sightreader;
import java.net.InetAddress;
import com.illposed.osc.OSCMessage;
import com.illposed.osc.OSCPortOut;
public class SightReader
{
public static void test()
{
System.out.println("Starting...");
try
{
int museScoreOSCPort = 5282;
OSCPortOut sender = new OSCPortOut(InetAddress.getLocalHost(), museScoreOSCPort);
Object args[] = new Object[1];
int midiNote = 60+12; // C5
int midiTick = 0;
args[0] = "" + midiTick + "," + midiNote;
OSCMessage msg = new OSCMessage("/color-note", args);
sender.send(msg);
midiNote = 64; // E5
midiTick = 0;
args[0] = "" + midiTick + "," + midiNote;
msg = new OSCMessage("/color-note", args);
sender.send(msg);
}
catch (Exception e)
{
System.out.println("Couldn't send");
}
}
public static void main(String[] args)
{
test();
}
}
In reply to Thanks. This is starting to by DonH
There is no OSC in MuseScore 1.1. In MuseScore 1.2, it's hidden and MuseScore 1.2 codebase is different than the trunk. So it would be better to use a nightly build. See [[nodetitle:Comparison of stable, prerelease, and nightly builds]] .
OSC is off by default in nightlies. You need to go to Edit -> Preferences -> General to enable it and choose the OSC port. Then restart MuseScore. And of course, in your example, you need a score loaded with a C on tick 0 ;)
if you want to discuss in live chat you can join our IRC channel (#musescore on freenode.net)
In reply to There is no OSC in MuseScore by [DELETED] 5
I downloaded the latest nightly build and followed your instructions.
My test code now colours a couple of notes red as expected; I need to do some more testing on it.
If you can add another param for note colour, I'd appreciate it.
I may have to ask for more advice on the plugin bit later, but I can get most of the Java bit written now.
Thanks.
In reply to Working now by DonH
I've got a basic stand-alone sight reader working fine now.
Can I just modify osc.cpp to take a third (optional) colour parameter, or is this something you guys need to do?
In reply to Working! by DonH
If you know how to do it, go ahead ! Also, it would be cool to change the comma separated arguments to true OSC ones.
"Optional" could be an issue...
In reply to If you know how to do it, go by [DELETED] 5
I got this when I tried to commit:
Error: access to '/svnroot/mscore/!svn/act/b650aec0-796b-da47-81a1-7eb36dc24d67' forbidden
My new version of the function is below, if you have time to commit it for me:
//---------------------------------------------------------
// oscColorNote
//---------------------------------------------------------
void MuseScore::oscColorNote(QString s)
{
if(!cs)
return;
QStringList args = s.split(",");
if(args.length() >= 2) {
int tick = args[0].toInt();
int pitch = args[1].toInt();
QColor noteColour = null;
if(args.length == 3){
noteColour = QColor(args[2]);
}
else{
// Default to red for compatibility with previous version.
noteColour = QColor("red");
}
Measure* measure = cs->tick2measure(tick);
if(!measure)
return;
Segment* s = measure->findSegment(SegChordRest, tick);
if (!s)
return;
//get all chords in segment...
int n = cs->nstaves() * VOICES;
for (int i = 0; i < n; i++) {
Element* e = s->element(i);
if (e && e->isChordRest()) {
ChordRest* cr = static_cast(e);
if(cr->type() == CHORD) {
Chord* chord = static_cast(cr);
for (int idx = 0; idx < chord->notes().length(); idx++) {
Note* note = chord->notes()[idx];
if (note->pitch() == pitch) {
cs->startCmd();
cs->undo(new ChangeProperty(note, P_COLOR, noteColour));
cs->endCmd();
cs->end();
return;
}
}
}
}
}
}
}
In reply to Error committing. by DonH
You suggested earlier that a plugin could execute a Java program. Can you explain how to do this? I can't see anything in the docs.
Thanks.
In reply to Plugin - execute command line by DonH
See http://musescore.org/en/plugin-development/how-plugin-development, the 2nd part
In reply to Error committing. by DonH
Hi DonH, I added the feature of the optional color in r5657. I didn't use your patch and changed the API to something cleaner. You can now call /color-note with 2 int (tick and pitch) and a string (color) in a list.
In reply to Hi DonH, I added the feature by [DELETED] 5
Thanks.
In the C++ you have the tick parameter as an int, but in Java-land it is a long.
Is this a mistake or will a C++ int hold a Java long? I'm using 32-bit Vista.
When I pass in an Integer, it works, but when I pass in a Long it does not.
Is it possible to display a message box from the JavaScript plugin code?
In reply to Tick is a long by DonH
Any decent C++ implemetation will use 32bit ints, at least those used to compile MuseScore, which is the same as a long in Java
In reply to Any decent C++ implemetation by Jojo-Schmitz
A Java long is 64 bit signed.
I'm not compiling MuseScore, just downloading the nightly build.
Cheers.
In reply to Java long by DonH
oops.
In C/C++ you'd most probably need a long long for 64bit
In reply to oops. In C/C++ you'd most by Jojo-Schmitz
OSC doesn't define a long. At least in the most basic types. So I used a int32, as defined in the norm.
In reply to OSC doesn't define a long. At by [DELETED] 5
Hmmm. I see what you mean.
How about using a string?
Can I display a messagebox from JavaScript plugin?
In reply to String? by DonH
Sorry - I can see an example of a message box in the other plugins.
In reply to String? by DonH
Not really. I'm fine with a int. I don't see the problem? I use http://opensoundcontrol.org/implementation/python-simple-osc to test and int are fine. More than 2000 millions ticks should be ok no?
In reply to Not really. I'm fine with a by [DELETED] 5
Thanks for all your help. I have uploaded the first version of my plugin.
In reply to Plugin uploaded by DonH
Seems you copied over a mistake from one of multiple other plugins: your plugin too ignores voice 4.
In line 53:
for (var v = 0; v < 3; v++) // Iterate through the voices.
This got to be:
for (var v = 0; v < 4; v++) // Iterate through the voices.
See #16691: plugin 'MIDISightReader' does not work on voice 4
Also I guess you should mention that it only works on Windows and only with the Nightlies (and only as of r5657)?
In reply to Seems you copied over a by Jojo-Schmitz
Thanks for your comments.
Please see the bug for my response.
The next version will hopfully check the tempo and rhythm.