MidiShare: Tutorials inicials

De Wikijoan
Dreceres ràpides: navegació, cerca

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: Javatutorial fluidsynth.png


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());
Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
Institut Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines