MidiShare: Tutorials inicials
Tots els projectes estan dins de /home/joan/workspace
Contingut
TutorialPart1
important llegir Connectant_aplicacions_MidiShare:_síntesi
Explicació
The MidiShare Java Tutorial: Part1 explains the basic MidiShare functions which can be accessed from Java. You will learn here how to open and manage MidiShare applications, manage inter-applications connections and send Midi events.
To compile the Tutorial part1 :
$ javac AppletFrame.java $ javac TutorialPart1.java
To launch the Tutorial part1 :
$ java TutorialPart1
Puc compilar el projecte amb línia de comandes com s'explica aquí, però prèviament havent configurat el classpath com s'explica en altres parts. De totes maneres, jo treballaré amb el Eclipse com a entorn de programació.
Tots els projectes es crearan dins de /home/joan/workspace. En aquest cas, /home/joan/workspace/TutorialPart1. El fitxer TutorialPart1.java i AppletFrame.java estaran dins de src/· Per accedir a la llibreria midishare, hem de fer Project > Properties > Add External Class Folder, i afegir /usr/src/midishare/lang/java
import grame.midishare.*;
AppletFrame.java
Copyright � Grame 2001
This library is free software; you can redistribute it and modify it under
the terms of the GNU Library General Public License as published by the
Free Software Foundation version 2 of the License, or any later version.
This library 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 Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
research@grame.fr
*/
import java.awt.*;
import java.util.*;
import java.applet.Applet;
import java.awt.event.*;
import java.applet.*;
// Utility classes
class AppletFrame extends Frame
implements WindowListener
{
//private static final String extraTitle = " - Applet Window";
private static final String extraTitle = "";
static Applet applet1;
public AppletFrame() {}
// Support the old calling convention.
public void startApplet(String className, String title, String[] args) {
try {
// create an instance of your applet class
applet1 = (Applet) Class.forName(className).newInstance();
} catch (ClassNotFoundException e) {
return;
} catch (InstantiationException e) {
return;
} catch (IllegalAccessException e) {
return;
}
startApplet(applet1,title,new Hashtable(),200,200);
}
// This is the real entry point.
// First, we have the name of the applet class,
// Second, the title for the window,
// Next, the Hashtable that contains the
// parameter -> parameter value mapping.
// This simulates the <param ...> tag.
// Finally the width and height of the applet.
public static void startApplet(Applet applet, String title,Hashtable params,int width,int height) {
applet1 = applet;
// setup so as getParameter, etc, will work
OurAppletContext newAppletContext
= new OurAppletContext(applet.getToolkit());
OurAppletStub newAppletStub
= new OurAppletStub(newAppletContext,params);
applet.setStub(newAppletStub);
// create new application frame window
AppletFrame f = new AppletFrame(title + extraTitle);
// add applet to frame window
f.add("Center", applet);
// add a quit menu item
MenuBar menubar = new MenuBar();
Menu file = new Menu("File", true);
MenuItem item = new MenuItem("Quit");
menubar.add(file);
file.add(item);
f.setMenuBar(menubar);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// At this point, we simply leave.
java.lang.Runtime.getRuntime().exit(0);
}
});
// resize frame window to fit applet
f.pack();
f.setSize(width,height);
applet.setSize(width,height);
// initialize the applet
applet.init();
applet.start();
// show the window
f.show();
f.repaint();
} // end startApplet()
// constructor needed to pass window title to class Frame
public AppletFrame(String name) {
// call java.awt.Frame(String) constructor
super(name);
addWindowListener(this);
}
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowClosing(WindowEvent e) {
// At this point, we simply leave.
//java.lang.Runtime.getRuntime().exit(0);
applet1.stop();
}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
} // end class AppletFrame
class OurAppletContext implements AppletContext {
private Toolkit ourToolkit;
OurAppletContext(Toolkit toolkit) {
ourToolkit = toolkit;
}
public void setStream(java.lang.String string ,java.io.InputStream in) {}
public java.io.InputStream getStream(java.lang.String string ) {return null;}
public Iterator getStreamKeys( ) {return null;}
public Image getImage(java.net.URL url) {
return ourToolkit.getImage(url);
}
// The rest are blank/void for this
// implementation of our applet viewer.
public AudioClip getAudioClip(java.net.URL url) {
// Think of silent movies...
return new OurAudioClip(url);
}
public Applet getApplet(String name) { return null; }
public Enumeration getApplets() { return null; }
public void showDocument(java.net.URL url) {}
public void showDocument(java.net.URL url,String target) {}
public void showStatus(String status) {}
}
class OurAppletStub implements AppletStub {
private Hashtable paramTable;
private AppletContext appletContext;
private java.net.URL codeBase;
private java.net.URL documentBase;
OurAppletStub(AppletContext appContext,Hashtable params) {
appletContext = appContext;
paramTable = params;
}
public boolean isActive() { return true; }
public java.net.URL getDocumentBase() {
if (documentBase == null) {
try {
java.io.File file = new java.io.File("");
documentBase = new java.net.URL("file",
"", // no host
file.getAbsolutePath().toString());
}
catch (java.net.MalformedURLException e) {
}
}
return documentBase;
}
public java.net.URL getCodeBase() {
if (codeBase == null) {
try {
java.io.File file = new java.io.File("");
codeBase = new java.net.URL("file",
"", // no host
file.getAbsolutePath().toString());
}
catch (java.net.MalformedURLException e) {
}
}
return codeBase;
}
public String getParameter(String str) {
return (String) paramTable.get(str.toUpperCase());
}
public AppletContext getAppletContext() {
return appletContext;
}
public void appletResize(int x,int y) {
// since the browser would ignore this,
// we choose to ignore it as well.
}
}
// Dummy sound class.
class OurAudioClip implements AudioClip {
public OurAudioClip(java.net.URL url) {}
public void loop() {}
public void play() {}
public void stop() {}
}
TutorialPart1.java
/*
Copyright Grame 2001
This library is free software; you can redistribute it and modify it under
the terms of the GNU Library General Public License as published by the
Free Software Foundation version 2 of the License, or any later version.
This library 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 Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
research@grame.fr
*/
import java.awt.*;
import java.util.*;
import java.applet.Applet;
import java.awt.event.*;
import java.applet.*;
import grame.midishare.*;
public class TutorialPart1 extends Applet
{
TextArea text;
Button start, go;
int testnumber ;
int ourRefNum = -1;
public void init()
{
testnumber = 0;
ourRefNum = -1;
Panel bottomPanel = new Panel();
Panel topPanel = new Panel();
go = new Button ("Next");
setLayout(new BorderLayout());
topPanel.setLayout(new GridLayout(2,1,1,1));
topPanel.add (new Label ("Tutorial Part1"));
add("North",topPanel);
text = new TextArea(1,1);
text.append( "Welcome to the MidiShare Java tutorial ! ");
add("Center",text);
bottomPanel.setLayout(new GridLayout(1,2,5,5));
bottomPanel.add (go);
add("South",bottomPanel);
text.replaceRange( "" , 0 , text.getText().indexOf( "\n" ) + 1 ) ;
text.append( "\n\nYou are now ready to follow the tutorial");
text.append( "\nUse NEXT button to execute the next test\n");
testnumber = 0;
}
public void stop()
{
if (ourRefNum > 0) Midi.Close(ourRefNum);
ourRefNum = -1;
}
void test1()
{
text.append("\n <TEST 1> : Check if MidiShare is installed : calling the Midi.Share() function is REQUIRED to properly load the JMidi native library");
text.append("\n");
text.append("MidiShare installed : ");
text.append(String.valueOf(Midi.Share()));
text.append("\n");
text.append("1 means that MidiShare is installed\n");
text.append("0 means that MidiShare is not installed");
}
void test2()
{
text.append("\n\n<TEST 2> Get MidiShare version\n");
text.append("MidiShare version : ");
text.append (String.valueOf(Midi.GetVersion()));
}
void test3()
{
text.append("\n\n<TEST 3> Count MidiShare client applications\n");
text.append("Count of MidiShare client applications : ");
text.append( String.valueOf(Midi.CountAppls()));
}
void test4()
{
text.append("\n\n<TEST 4> Register a client application\n");
ourRefNum = Midi.Open("Tutorial");
if (ourRefNum > 0){
text.append("MidiOpen succeed. Our reference number is : ");
text.append( String.valueOf(ourRefNum));
}else{
text.append("MidiOpen fail. The error code is : ");
text.append( String.valueOf(ourRefNum));
}
}
void test5()
{
text.append("\n\n<TEST 5> Count again MidiShare client applications \n");
text.append("Count of MidiShare client applications : ");
text.append(String.valueOf(Midi.CountAppls()));
}
void listOfAppl()
{
short i;
int ref, n = Midi.CountAppls();
text.append("List of MidiShare client applications\n");
text.append("-------------------------------------\n");
for (i = 1; i<= n; i++) {
ref = Midi.GetIndAppl(i); // get the refnum from the order number
text.append(String.valueOf(i));
text.append(" : reference number ");
text.append(String.valueOf(ref));
text.append(" name : ");
text.append(Midi.GetName(ref));
text.append("\n");
}
text.append("-------------------------------------");
}
void test6()
{
text.append("\n\n<TEST 6> List every MidiShare client applications\n");
listOfAppl();
}
void test7()
{
text.append("\n\n<TEST 7> search the reference number of: ");
text.append("Tutorial");
text.append("\n");
text.append("Reference number of : ");
text.append("Tutorial");
text.append(" : ");
text.append(String.valueOf (Midi.GetNamedAppl("Tutorial")));
}
void test8()
{
text.append("\n\n<TEST 8> search the reference number of 'XYZ'\n");
text.append("Reference number of XYZ: ");
text.append(String.valueOf (Midi.GetNamedAppl("XYZ")));
text.append("\n");
text.append("A negative result means that the application was not found.");
}
void test9()
{
text.append("\n\n<TEST 9> Change the name of client application Tutorial to JavaTutorial\n");
Midi.SetName (Midi.GetNamedAppl ("Tutorial"), "JavaTutorial");
listOfAppl();
}
void test10()
{
text.append("\n\n<TEST 10> Connect JavaTutorial to MidiShare\n");
Midi.Connect (ourRefNum, 0, 1);
}
void test11()
{
text.append("\n\n<TEST 11> Test if JavaTutorial is connected to MidiShare\n");
text.append("Connection to MidiShare : ");
text.append(String.valueOf(Midi.IsConnected (ourRefNum, 0)));
text.append("\n");
text.append("Connection from MidiShare : ");
text.append(String.valueOf(Midi.IsConnected (0,ourRefNum)));
}
void listDest(int ref1)
{
short i;
int ref2, n = Midi.CountAppls();
text.append("List of the destinations of ");
text.append(String.valueOf(ref1));
text.append("\n");
text.append("-------------------------------------\n");
for (i = 1; i<= n; i++) {
ref2 = Midi.GetIndAppl(i); // get the refnum from the order number
if (Midi.IsConnected( ref1, ref2) == 1) {
text.append("--> ");
text.append(Midi.GetName(ref2));
text.append(" refnum = " );
text.append(String.valueOf(ref2));
text.append("\n");
}
}
text.append("-------------------------------------");
}
void test12()
{
text.append("\n\n<TEST 12> List the destinations of an application\n");
listDest (ourRefNum);
}
void listSrc(int ref1)
{
short i;
int ref2, n = Midi.CountAppls();
text.append("List of the sources of ");
text.append(String.valueOf(ref1));
text.append("\n");
text.append("-------------------------------------\n");
for (i = 1; i<= n; i++) {
ref2 = Midi.GetIndAppl(i); // get the refnum form the order number
if (Midi.IsConnected( ref2, ref1) == 1) {
text.append("<-- ");
text.append(Midi.GetName(ref2));
text.append(" refnum = " );
text.append(String.valueOf(ref2));
text.append("\n");
}
}
text.append("-------------------------------------");
}
void test13()
{
text.append("\n\n<TEST 13> List the sources of an application\n");
listSrc (0);
}
void sendNote(int pitch)
{
int event = Midi.NewEv(Midi.typeNote); // ask for a new note event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetField(event,0,pitch); // set the pitch field
Midi.SetField(event,1,80); // set the velocity field
Midi.SetField(event,2,1000); // set the duration field
Midi.SendIm(ourRefNum, event); // send the note immediatly
}
}
void test14()
{ int ref;
text.append("\n\n<TEST 14>Send a note with pitch, velocity and duration\n");
if ((ref = Midi.GetNamedAppl("msdisplay")) > 0)
Midi.Connect(ourRefNum,ref, 1);
sendNote (72);
}
void sendMultipleNotes (int n, int pitch, int delay)
{
int event = Midi.NewEv(Midi.typeNote); // ask for a new note event
int date = Midi.GetTime(); // remember the current time
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetField(event,0,pitch); // set the pitch field
Midi.SetField(event,1,80); // set the velocity field
Midi.SetField(event,2,(delay - 1)); // set the duration field
for (int i = 0; i< n ; i++) { // ; loop for the requested number of events
Midi.SendAt(ourRefNum, Midi.CopyEv(event), (date + (i * delay))); // send a copy of the original note
}
Midi.FreeEv (event); // dispose the original note
}
}
void test15()
{
text.append("\n\n<TEST 15>Send multiple notes\n");
sendMultipleNotes (10, 72, 1000);
}
void sendLyric(String str)
{
int event = Midi.NewEv(Midi.typeLyric); // ask for a new lyric event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetText(event, str); // set the text field
Midi.SendIm(ourRefNum, event); // send the event immediatly
}
}
void test16()
{
text.append("\n\n<TEST 16>Send 'hello' lyric\n");
sendLyric("Hello");
}
void sendText(int type, String str)
{
int event = Midi.NewEv(type); // ask for a event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetText(event, str); // set the text field
Midi.SendIm(ourRefNum, event); // send the event immediatly
}
}
void test17()
{
text.append("\n\n<TEST 17>Send text events\n");
sendText (Midi.typeText, "Hello");
sendText (Midi.typeCopyright, "Mozart");
sendText (Midi.typeSeqName, "Concerto");
sendText (Midi.typeInstrName ,"Piano");
sendText (Midi.typeLyric, "Hiiiiiii");
sendText (Midi.typeMarker, "mark 1");
sendText (Midi.typeCuePoint, "Reverb here") ;
}
void listOfDrivers()
{
int ref, n = Midi.CountDrivers();
text.append("\n\nList of MidiShare drivers\n");
text.append("-------------------------------------\n");
for (int i = 1; i<= n; i++) {
ref = Midi.GetIndDriver(i); // get the refnum from the order number
printDriverInfo(ref);
text.append("-------------------------------------\n");
}
}
void printDriverInfo(int ref)
{
DriverInfos infos = new DriverInfos();
SlotInfos slot = new SlotInfos();
Midi.GetDriverInfos(ref,infos); // get info for the driver
text.append("Reference number ");
text.append(String.valueOf(ref));
text.append("\nname : ");
text.append(infos.name);
text.append("\nslots : ");
text.append(String.valueOf(infos.slots));
text.append("\nversion : ");
text.append(String.valueOf(infos.version));
text.append("\n");
for (int i = 0 ;i < infos.slots; i++) {
Midi.GetSlotInfos(Midi.GetIndSlot(ref,i+1), slot);
text.append("slot name : " );
text.append(slot.name);
text.append("\nslot direction : ");
text.append(String.valueOf(slot.direction));
text.append("\n");
}
}
void test18()
{
text.append( "\n\n<TEST 18>Display MidiShare drivers informations");
listOfDrivers();
}
void printPortInfo(int ref, int port)
{
DriverInfos infos = new DriverInfos();
SlotInfos slot = new SlotInfos();
Midi.GetDriverInfos(ref,infos); // get info for the driver
for (int i = 0 ;i < infos.slots; i++) {
int slotref = Midi.GetIndSlot(ref,i+1);
int res = Midi.IsSlotConnected(port, slotref);
if (res > 0) { // if port is connected this this slot
text.append("\n-------------------------------------\n");
Midi.GetSlotInfos(slotref, slot);
text.append("port number : " );
text.append(String.valueOf(port));
text.append("\nslot name : " );
text.append(slot.name);
text.append("\nslot direction : ");
text.append(String.valueOf(slot.direction));
text.append("\nslot connexions : ");
for (int u = 0 ; u < 32 ; u++)
for (int v = 0 ; v < 8 ; v++)
text.append((slot.cnx[u]==Math.pow(2,v))?((8*u+v)+" "):(""));
}
}
}
void test19()
{
text.append( "\n\n<TEST 19>Display port to slot connection state");
int ref, n = Midi.CountDrivers();
for (int i = 1; i<= n; i++) {
ref = Midi.GetIndDriver(i); // get the refnum from the order number
printPortInfo(ref,0); // display connection state of port 0
printPortInfo(ref,1); // display connection state of port 1
}
}
void connectPort(int ref, int port)
{
DriverInfos infos = new DriverInfos();
Midi.GetDriverInfos(ref,infos); // get info for the driver
for (int i = 0 ;i < infos.slots; i++) {
int slotref = Midi.GetIndSlot(ref,i+1);
Midi.ConnectSlot(port,slotref,1);
}
}
void test20()
{
text.append( "\n\n<TEST 20>Connect port to slot and display new connection state");
int ref, n = Midi.CountDrivers();
for (int i = 1; i<= n; i++) {
ref = Midi.GetIndDriver(i); // get the refnum from the order number
connectPort (ref,10); // connect port 10 to all slots of all drivers
}
for (int i = 1; i<= n; i++) {
ref = Midi.GetIndDriver(i); // get the refnum from the order number
printPortInfo(ref,10); // display connection state of port 10
}
}
void test21()
{
text.append("\n\n<TEST 21>Close the JavaTutorial application\n");
Midi.Close (ourRefNum);
listOfAppl ();
}
public boolean action( Event e , Object o)
{
if (e.target == go) {
testnumber++;
switch (testnumber) {
case 1 : test1(); break;
case 2 : test2(); break;
case 3 : test3(); break;
case 4 : test4(); break;
case 5 : test5(); break;
case 6 : test6(); break;
case 7 : test7(); break;
case 8 : test8(); break;
case 9 : test9(); break;
case 10 : test10(); break;
case 11 : test11(); break;
case 12 : test12(); break;
case 13 : test13(); break;
case 14 : test14(); break;
case 15 : test15(); break;
case 16 : test16(); break;
case 17 : test17(); break;
case 18 : test18(); break;
case 19 : test19(); break;
case 20 : test20(); break;
case 21 : test21(); break;
}
return true;
}
return true;
}
public static void main(String args[])
{
java.util.Hashtable params = new java.util.Hashtable();
// Create the applet.
TutorialPart1 applet = new TutorialPart1();
// And fire up the applet frame.
AppletFrame.startApplet(applet, "TutorialPart1", params, 400, 300);
}
}
Explicació
AppletFrame.java conté tota la lògica per a crear l'Applet, i la classe TutorialPart1 hereda la classe Applet, és a dir, és un applet.
public class TutorialPart1 extends Applet
En el mètode init() establim les propietats del Applet, per exemple
topPanel.add (new Label ("Tutorial Part1"))
Compte, perquè el codi original hi ha mètodes una mica deprectateds, com per exemple text.append que ho substitueixo per text.Append, i text.replaceRange que ho substitueixo per text.replaceRange.
El mètode main() és el punt d'entrada del projecte, i té dues missions: la primera, crear l'Applet, i la segona, llençar la funcionalitat del applet, que bàsicament són una sèrie de tests per comprovar si la llibreria midishare està ben instal.lada, i llençar uns events per produir unes notes, i que tindré per objectiu escoltar-les.
public static void main(String args[])
{
java.util.Hashtable params = new java.util.Hashtable();
// Create the applet.
TutorialPart1 applet = new TutorialPart1();
// And fire up the applet frame.
AppletFrame.startApplet(applet, "TutorialPart1", params, 400, 300);
}
Fer sonar TutorialPart1.java: amb el fluidsynth
La dificultat de fer sonar el TutorialPart1.java és un problema de què no acabava d'entendre el procés. La clau està en entendre en què, en tot el procés de compilació del midishare, jo el que he fet és crear un driver de midishare compatible amb ALSA: msAlsaSeq.
$ msAlsaSeq MidiShare ALSA driver anchored on "MidiShare/ALSA Bridge" is running. Type 'q' to quit.
i puc comprovar que el tinc disponible fent
$ aconnect -i -o
...
cliente 129: 'MidiShare/ALSA Bridge' [tipo=usuario]
0 'MidiShare/ALSA Bridge'
Puc tenir altres clients, com el timidity, fluidsynth, que són clients software, o el Edirol UA-25EX, que és un client hardware i em permet connectar el CASIO.
Aquest driver jo el faré servir per connectar altres clients ALSA (com el fluidsynt o la Edirol) amb midishare. Els clients podran ser per escriure o per llegir events MIDI. Per exemple, amb el fluidsynt utilitzaré l'opció -o, i amb el WX5 utilitzaré l'opció -i. La referència dels clients ALSA la sabré fent aconnect -i -o.
La primera discussió que vaig fer de tot això, i que ja ho vaig solucionar en part, està a Ubuntu_Studio:_Resum_preparació_Ubuntu_Studio_amb_MidiShare#programant_MidiShare_amb_JAVA
i el manual del msAlsaSeq està a man msAlsaSeq: MsAlsaSeq:_ALSA_driver_for_MidiShare
Nota: amb ALSA fem servir la utilitat aconnect per veure quins clients ALSA tinc disponibles i establir connexions entre els clients:
$ aconnect 129:0 130:0
D'aquesta manera puc, per exemple, redirigir l'entrada del WX5 al fluidsynth. Amb midishare, en comptes de aconnect utilitzaré msAlsaSeq, on puc establir la connexió entre els clients Alsa i midishare, donar un nom a la connexió, que això serà molt interessant quan programi amb Java:
$ msAlsaSeq -i 129:0 -o 128:0 $ msAlsaSeq tarja_so -i 129:0/0 -o 128:0/0
Compte perquè msAlsaSeq i aconnect són diferents. Amb msAlsaSeq he de tenir la imatge de què fa el msconnect. Connecta aplicacions d'entrada (129:0) amb midishare (port 0)(-i 129:0/0), i aplicacions de sortida (128:0) amb midishare (port 0) (-o 128:0/0). Per tant, en aquest exemple, estic fent dues connexions.
tarja_so és el nom que li dono a la meva aplicació client (en comptes de MidiShare/ALSA Bridge, que és el que hi ha per defecte)
En l'aplicació Java:
int ref_tarja_so;
if ((ref_tarja_so = Midi.GetNamedAppl("tarja_so")) > 0) Midi.Connect(ourRefNum,ref_tarja_so, 1);
Anem a fer sonar el TutorialPart1.java.
Primer de tot engego el fluidsynth amb el driver de midishare:
$ fluidsynth -a alsa -m midishare /home/joan/Escritorio/AltosaxJan.SF2
Arrenco les utilitats msdisplay (per veure els events MIDI) i msconnect (per veure les connexions obertes)
$ /usr/src/midishare/src/linux/applications/msdisplay/msdisplay $ /usr/src/midishare/src/linux/applications/msconnect/msconnect
Fixem-nos que amb el msconnect apareix el fluidsynth. Ara el que he de fer és, a nivell de codi, connectar amb el fluidsynth, i d'aquesta manera ja sonarà l'aplicació. En el Test14, a més de connectar-nos amb el msdisplay també em connecto amb el fluidsynth:
int ref_fluidsynth;
if ((ref_fluidsynth = Midi.GetNamedAppl("fluidsynth")) > 0) Midi.Connect(ourRefNum,ref_fluidsynth, 1);
i ja sona!!
Recordem que no cal ficar el codi anterior si faig les connexions manualment amb la utilitat del msconnect, tal com es mostra en la figura:
En aquest cas, fluidsynth és un client midishare perquè l'he engegat amb el driver de midishare. Anem a veure ara com ho puc fer si l'arrenco amb el driver d'alsa: alsa_seq.
Primer de tot engego el fluidsynth amb el driver d'alsa (no pas amb el driver de midishare):
$ fluidsynth -a alsa -m alsa_seq /home/joan/Escritorio/AltosaxJan.SF2
Nota: utilitzar l'opció -i si no vull la consola del fluidsynth
i miro quina és la seva referència com a client alsa.
$ aconnect -o
...
cliente 129: 'FLUID Synth (13737)' [tipo=usuario]
0 'Synth input port (13737:0)'
si miro msconnect, no m'apareix res de fluidsynth. Si vull que fluidsynth sigui un client midishare, ho he de fer amb msAlsaSeq:
$ msAlsaSeq fluidsynth2 -o 129:0/0 Connecting output "FLUID Synth (13737)" (129:0) to MidiShare port 0. MidiShare ALSA driver anchored on "fluidsynth2" is running. Type 'q' to quit.
I ara amb msconnect veig que ja m'apareix, en la part de la dreta (Destinations), el fluidsynth2. Compte, perquè el que he fet és que sigui un client midishare, però no està connectat amb ningú. Igual que abans, per tal de fer sonar el JavaTutorial1 s'haurà de connectar el Source Javatutorial1 amb l'Application fluidsynth2, que lo normal és fer-ho per codi, però també es podria fer manualment.
Tot el tema dels drivers i el test 18, 19 i 20 podem oblidar-nos. El tractament que es fa a Windows i a Linux dels drivers, ports i slots és molt diferent. A Windows tenia la utilitzat msdrivers.exe, que era molt útil, però no és aplicable en el cas de Linux.
Fer sonar TutorialPart1.java: amb el sintetitzador CASIO CTK-731 (connectat a través de la tarja Edirol UA-25EX)
(actualitzar...)
Per fer-ho sonar amb el sintetitzador la idea és la mateixa. Amb aconnect veig quina és la referència de l'Edirol:
$ aconnect -i -o
i ara ja puc connectar el Edirol amb el midishare, i m'apareix a msconnect
$ msAlsaSeq edirol -o 130:0/0
i ara, per codi, en el Test14, ja puc establir la connexió de l'Edirol amb el MidiShare i fer sonar el TutorialPart1
int ref_edirol;
if ((ref_edirol = Midi.GetNamedAppl("edirol")) > 0) Midi.Connect(ourRefNum,ref_edirol, 1);
TutorialPart2
important llegir Connectant_aplicacions_MidiShare:_síntesi
Explicació
The MidiShare Java Tutorial: Part2 explains more advanced features of the MidiShare Java classes. You will learn here how to use the MidiAppl class which allows to manage incoming events and applications context switches. You will also learn how to use Midi tasks.
TutorialPart2.java
/*
Copyright Grame 2001
This library is free software; you can redistribute it and modify it under
the terms of the GNU Library General Public License as published by the
Free Software Foundation version 2 of the License, or any later version.
This library 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 Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
research@grame.fr
*/
import java.awt.*;
import java.util.*;
import java.applet.Applet;
import grame.midishare.*;
public class TutorialPart2 extends Applet
{
TextArea text;
Button go;
int testnumber ;
MidiTutorial appl;
TutorialTask task;
public void init()
{
testnumber = 0;
Panel bottomPanel = new Panel();
Panel topPanel = new Panel();
go = new Button ("Next");
setLayout(new BorderLayout());
topPanel.setLayout(new GridLayout(2,1,1,1));
topPanel.add (new Label ("Tutorial Part2"));
add("North",topPanel);
text = new TextArea(1,1);
text.append( "Welcome to the MidiShare Java tutorial part2! ");
add("Center",text);
bottomPanel.setLayout(new GridLayout(1,2,5,5));
bottomPanel.add (go);
add("South",bottomPanel);
text.replaceRange( "" , 0 , text.getText().indexOf( "\n" ) + 1 ) ;
text.append( "\n\nYou are now ready to follow the tutorial");
text.append( "\nUse NEXT button to execute the next test\n");
testnumber = 0;
}
public void stop()
{
if (appl!= null) appl.Close();
appl = null;
}
void listOfAppl()
{
short i;
int ref, n = Midi.CountAppls();
text.append("\nList of MidiShare client applications\n");
text.append("-------------------------------------\n");
for (i = 1; i<= n; i++) {
ref = Midi.GetIndAppl(i); // get the refnum form the order number
text.append(String.valueOf(i));
text.append(" : reference number ");
text.append(String.valueOf(ref));
text.append(" name : ");
text.append(Midi.GetName(ref));
text.append("\n");
}
text.append("-------------------------------------");
}
void listDest(int ref1)
{
short i;
int ref2, n = Midi.CountAppls();
text.append("\nList of the destinations of ");
text.append(String.valueOf(ref1));
text.append("\n");
text.append("-------------------------------------\n");
for (i = 1; i<= n; i++) {
ref2 = Midi.GetIndAppl(i); // get the refnum form the order number
if (Midi.IsConnected( ref1, ref2) == 1) {
text.append("--> ");
text.append(Midi.GetName(ref2));
text.append(" refnum = " );
text.append(String.valueOf(ref2));
text.append("\n");
}
}
text.append("-------------------------------------");
}
void listSrc(int ref1)
{
short i;
int ref2, n = Midi.CountAppls();
text.append("\nList of the sources of ");
text.append(String.valueOf(ref1));
text.append("\n");
text.append("-------------------------------------\n");
for (i = 1; i<= n; i++) {
ref2 = Midi.GetIndAppl(i); // get the refnum form the order number
if (Midi.IsConnected( ref2, ref1) == 1) {
text.append("<-- ");
text.append(Midi.GetName(ref2));
text.append(" refnum = " );
text.append(String.valueOf(ref2));
text.append("\n");
}
}
text.append("-------------------------------------");
}
void sendText(int refnum, int type, String str)
{
int event = Midi.NewEv(type); // ask for a event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetText(event, str); // set the text field
Midi.SendIm(refnum, event); // send the event immediatly
}
}
void test1()
{
try {
text.append( "\n <TEST 1> : Allocate and open a new MidiAppl object");
appl = new MidiTutorial(this);
appl.Open("TutorialPart2");
text.append("\n");
listOfAppl();
}catch (MidiException e) {
System.out.println(e);
}
}
void test2()
{
text.append("\n\n<TEST 2>Configure the Midi filter\n");
appl.configureFilter();
}
void test3()
{
text.append("\n\n<TEST 3> Connect to Midi applications\n");
Midi.Connect(appl.refnum, 0, 1);
Midi.Connect(0,appl.refnum,1);
listSrc(appl.refnum);
listDest(appl.refnum);
}
void sendNote(int pitch)
{
int event = Midi.NewEv(Midi.typeNote); // ask for a new ctrlchange event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetField(event,0,pitch); // set the pitch field
Midi.SetField(event,1,80); // set the velocity field
Midi.SetField(event,2,1000); // set the duration field
Midi.SendIm(appl.refnum, event);// send the note immediatly
}
}
void sendCtrlChange(int ctrl, int val)
{
int event = Midi.NewEv(Midi.typeCtrlChange); // ask for a new note event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetField(event,0,ctrl); // set the ctrl number field
Midi.SetField(event,1,val); // set the value field
Midi.SendIm(appl.refnum, event);// send the note immediatly
}
}
void sendProgChange(int pgm)
{
int event = Midi.NewEv(Midi.typeProgChange); // ask for a new progchange event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event,0); // set the Midi channel
Midi.SetPort(event,0); // set the destination port
Midi.SetField(event,0,pgm); // set the prog number field
Midi.SendIm(appl.refnum, event);// send the note immediatly
}
}
void test4()
{
int ref;
text.append("\n\n<TEST 4> Send events\n");
if ((ref = Midi.GetNamedAppl("msdisplay")) > 0)
Midi.Connect (appl.refnum,ref, 1);
text.append("Send Notes \n");
text.append("Send CtrlChange \n");
text.append("Send ProgChange \n");
sendNote(60);
sendNote(64);
sendNote(67);
sendCtrlChange(7,120);
sendCtrlChange(10,120);
sendProgChange(2);
}
void test5()
{
int ref1, ref2;
text.append("\n\n<TEST 5>Delay and transpose incoming notes\n");
ref1 = Midi.GetNamedAppl("mskeyboard");
ref2 = Midi.GetNamedAppl("msdisplay");
if (ref1 > 0) Midi.Connect (ref1,appl.refnum, 1);
if (ref2 > 0) Midi.Connect (ref1,ref2, 1);
}
void test6()
{
text.append("\n\n<TEST 6> Install a Appl alarm \n");
int ref = Midi.Open("foo");
Midi.Connect(ref, 0, 1);
Midi.SetName(ref, "foo1");
Midi.Close(ref);
}
void test7 ()
{
text.append("\n\n<TEST 7>Define and schedule a new Midi task object ");
text.append("\n");
task = new TutorialTask();
appl.ScheduleTask(task, Midi.GetTime());
}
void test8()
{
text.append("\n\n<TEST 8>Forget the task");
task.Forget();
}
void test9()
{
text.append("\n\n<TEST 8>Close the MidiAppl instance");
appl.Close();
appl = null;
listOfAppl ();
}
public boolean action(Event e , Object o)
{
if (e.target == go) {
testnumber++;
switch (testnumber){
case 1 : test1(); break;
case 2 : test2(); break;
case 3 : test3(); break;
case 4 : test4(); break;
case 5 : test5(); break;
case 6 : test6(); break;
case 7 : test7(); break;
case 8 : test8(); break;
case 9 : test9(); break;
}
return true;
}
return true;
}
public static void main(String args[])
{
java.util.Hashtable params = new java.util.Hashtable();
// Create the applet.
TutorialPart2 applet = new TutorialPart2();
// And fire up the applet frame.
AppletFrame.startApplet(applet, "TutorialPart2", params, 400, 300);
}
}
class MidiTutorial extends MidiAppl
{
TutorialPart2 myUser;
public MidiTutorial (TutorialPart2 user)
{
myUser = user;
}
public void configureFilter()
{
int i;
for (i = 0 ; i<256; i++) {
Midi.AcceptPort(filter, i, 1);
Midi.AcceptType(filter, i, 1);
}
for (i = 0 ; i<16; i++) {
Midi.AcceptChan(filter, i, 1);
}
Midi.AcceptType(filter, Midi.typeActiveSens, 0);
Midi.AcceptType(filter, Midi.typeSysEx, 0);
}
public void ReceiveAlarm(int event)
{
switch (Midi.GetType(event)) {
case Midi.typeNote: // for Key event
case Midi.typeKeyOn:
case Midi.typeKeyOff:
Midi.SetField(event, 0, Midi.GetField(event,0) + 12);// change the pitch field
Midi.SetDate(event, Midi.GetDate(event) + 1000); // change the date field
Midi.Send(refnum, event); // re-send the event
break;
default:
Midi.FreeEv(event); // otherwise dispose the event
break;
}
}
public void ApplAlarm (int code)
{
int param = code & 0x0000FFFF ;
int ref = (code & 0xFFFF0000) >> 16 ;
if (myUser.testnumber == 6) {
switch (param) {
case Midi.OpenAppl :
myUser.text.append(" A new application has opened \n");
break ;
case Midi.CloseAppl :
myUser.text.append(" An application has closed \n");
break ;
case Midi.ChgConnect :
myUser.text.append(" A connection has changed \n");
break ;
case Midi.ChgName :
myUser.text.append(" A name has changed \n");
break ;
}
}
}
}
class TutorialTask extends MidiTask {
public void Execute (MidiAppl obj, int date)
{
MidiTutorial appl = (MidiTutorial) obj;
appl.myUser.text.append("Execution of the task at date: ");
appl.myUser.text.append(String.valueOf(date));
appl.myUser.text.append("\n");
appl.myUser.sendText(appl.refnum, Midi.typeText, "Hello from tutorial");
appl.ScheduleTask(this, date + 3000);
}
}
Compilació i execució
Intento executar de bones a primeres i em dóna un error a:
MidiTutorial appl; -> appl és un objecte de la classe MidiTutorial
appl = new MidiTutorial(this);
class MidiTutorial extends MidiAppl {...}
i la classe MidiTutorial ve de MidiAppl
al cap i a la fi, no sap el que és MidiAppl
dins la carpeta :/usr/src/midishare/lang/java/jni/linux tenim:
libJMidi.so.1.0 makefile makefile~ MidiAppl.o Midi.o
a /usr/lib hi ha un soft link d'aquesta llibreria: libJMidi.so
Com que la llibreria l'he instal.lat a /usr/lib, que és el directori correcte (la primera vegada ho havia fet a /usr/lib/jni, això simplificarà les coses).
la classe MidiAppl.class (i MidiAppl.java) està a:
/usr/src/midishare/lang/java/native/grame/midishare/MidiAppl.class
Si no hi és, es compila de nou
$ sudo javac -classpath /usr/src/midishare/lang/java/native:/home/joan/workspace/TutorialPart2/src /usr/src/midishare/lang/java/native/grame/midishare/MidiAppl.java
i es crea MidiAppl.class
Ens movem al directori de treball i compilem TutorialPart2.java:
$ cd /home/joan/workspace/TutorialPart2/src $ sudo javac -classpath /usr/src/midishare/lang/java/native:/home/joan/workspace/TutorialPart2/src AppletFrame.java TutorialPart2.java
es crea AppletFrame.class i TutorialPart2.class
Per executar-ho, si la llibreria libJMidi.so estigués en un directori poc comú faríem servir l'opció -Djava.library.path=/usr/lib/jni, però com que el tinc a /usr/lib no cal. El que sí que cal és que trobi la ruta de la classe MidiTutorial (class MidiTutorial extends MidiAppl), i MidiTutorial.class es troba compilat al directori de treball. Haurem d'afegir aquest directori al classpath:
$ java -classpath /usr/src/midishare/lang/java/native:/home/joan/workspace/TutorialPart2/src TutorialPart2
En el Eclipse hauré d'afegir en el Java Build Path > Libraries aquestes dues rutes, i també funciona sense problemes.
Canvis que faig
Si vull que soni, en el Test4 he d'associar l'aplicació amb el Fluidsynth, que el tinc funcionant:
int ref_fluidsynth;
if ((ref_fluidsynth = Midi.GetNamedAppl("fluidsynth")) > 0) Midi.Connect (appl.refnum,ref_fluidsynth, 1);
Fixem-nos que en el Test4 estic fent sonar un acord (3 notes), totes juntes.
En el Test5 es dóna per fet que tinc l'aplicació mskeyboard, quan no és pas veritat. Si vull un piano, puc utilitzar el vKeybd, però també puc utilitzar l'aplicació mscontrol per enviar events MIDI.
int ref1, ref2, ref3;
ref3 = Midi.GetNamedAppl("mscontrol");
if (ref3 > 0) Midi.Connect (ref3,appl.refnum, 1);
puc veure la referència dels mètodes (documentació) a: file:///usr/src/midishare/doc/html/index.html
La clau està en el mètode ReceiveAlarm (class MidiTutorial extends MidiAppl ):
public void ReceiveAlarm(int event)
{
switch (Midi.GetType(event)) {
case Midi.typeNote: // for Key event
case Midi.typeKeyOn:
case Midi.typeKeyOff:
Midi.SetField(event, 0, Midi.GetField(event,0) + 12);// change the pitch field
Midi.SetDate(event, Midi.GetDate(event)+1000); // change the date field
Midi.Send(refnum, event); // re-send the event
break;
default:
Midi.FreeEv(event); // otherwise dispose the event
break;
}
}
que el que fa és capturar qualsevol dels 3 events (typeNote, typeKeyOn, typeKeyOff) i reenviar l'event amb un canvi en el pitch i un retràs de 1 segon.
Puc afegir la línia
case Midi.typeProgChange:
A MidiAppl.java, que és la classe mare, trobem:
public void ReceiveAlarm(int event){ Midi.FreeEv(event);}
The ReceiveAlarm method is automatically called when a MidiShare context switch occurs. The default method does nothing. This method can be redefined in derived classes.
Per tant, és obligatori posar aquest mètode. Si jo el que vull és reenviar tot el que es rep he de posar:
public void ReceiveAlarm(int event)
{
Midi.Send(refnum, event); // re-send the event
}
per tal de què faci cas als events de programe Change. És a dir, ReceiveAlarm, en aquest cas, tal com està programat, fa de filtre.
En el test7 defineixo un MidiTask que em pot servir per llançar events programats.
task = new TutorialTask(); appl.ScheduleTask(task, Midi.GetTime());