Projecte Proj1
Salta a la navegació
Salta a la cerca
Introducció
Aquest és un projecte introductori de combinar midishare amb interfície gràfica. La idea és molt simple. Toco una nota amb un controlador midi i m'apareix, a pantalla completa, ben gros i sobre un fons de color, la nota que toco (amb el mscontrol, el vkeybd, o el WX5, per exemple). El següent projecte serà fer el mateix, però amb una nota dibuixada sobre un pentagrama.
Problemes que m'he trobat
- com fer proj1.paintWorld() des de la classe MidiShareInput (documentar)
- Tot funciona bé, excepte que no sona. Segons la propietat transitiva, l'aplicacio Proj1 està connectada al fluidsynth, i el mscontrol està connectat a l'aplicació Proj1: no cal connectar mscontrol al fluidsynth. Ara bé, per tal que soni, en el procediment public void ReceiveAlarm(int ev) he de reenviar el event en comptes de fer free: Midi.SendIm(this.refnum, ev);
- amb el vkeybd escriu bé la nota per la pantalla, però no pas el mscontrol. Lògic, perquè els events que envien els dos programes són diferents. vkeybd envia Midi.typeKeyOn i Midi.typeKeyOff, i mscontrol envia Midi.typeNote. Per tant, també s'ha de considerar el cas case Midi.typeNote :.
- com que el vkeybd envia typeKeyOn i typeKeyOff, per escoltar he de mantenir la tecla pitjada (això és especialment cert perque el so que tinc en el fluidsynth és un saxo, en el cas d'un piano no importaria). En el cas del mscontrol, s'envia typeNote.
- Necessitava un repàs del estàndard MIDI. Recordem que tenim el Status Byte, que comença per 1, i dos bytes de dades, que comencen per 0 (DATA0 i DATA1).
- Status Byte: primer bit: 1; 3 bits per al missatge; 4 bits per al canal. Per exemple: Note Off és 1000nnnn, Note On és 1001nnnn
- En el cas de Note On, el DATA0 és l'altura (0-127, 7 bits restants) i DATA1 és la velocitat (0-127)
- A l'aplicació Java, els valors de DATA0 i DATA1 els accedeixo amb Midi.GetData0(ev) i Midi.GetData1(ev). El valor del Status Byte l'accedeixo amb Midi.GetType(ev) i Midi.GetChan(ev).
Codi
La sortida de l'aplicació és:
installed = 1 version = 192 numberOfAppl = 6 MidiShare configureFilter() filter#-531275200 Connected for input? 1 Connected for output? 1 List of MidiShare client applications ------------------------------------- 1 : reference number 0 name : MidiShare 2 : reference number 1 name : msdisplay 3 : reference number 2 name : msconnect 4 : reference number 3 name : mscontrol 5 : reference number 4 name : vkeybd 6 : reference number 5 name : fluidsynth 7 : reference number 6 name : MidiShareInput -------------------------------------typeKeyOn Tipus event: 1 (0=typeNote; 1=typeKeyOn; 2=typeKeyOff) Canal: 0 Data0: 60 (altura en el cas de Note On/Off) Data1: 127 (velocitat en el cas de Note On/Off) MidiShareInput, received typeKeyOn Tipus event: 2 (0=typeNote; 1=typeKeyOn; 2=typeKeyOff) Canal: 0 Data0: 60 (altura en el cas de Note On/Off) Data1: 0 (velocitat en el cas de Note On/Off) Tipus event: 0 (0=typeNote; 1=typeKeyOn; 2=typeKeyOff) Canal: 0 Data0: 95 (altura en el cas de Note On/Off) Data1: 127 (velocitat en el cas de Note On/Off) MidiShareInput, received typeNote Closing Midi, byebye
Anem a posar el codi. Són dues classes: Proj1 conté el main() i construeix la interfície gràfica. MidiShareInput conté tota la part de MidiShare i s'ha de comunicar amb Proj1 per tal de traduir els events MIDI en accions sobre la pantalla.
Proj1.java
package v4;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Proj1 extends Canvas implements Stage, KeyListener {
private BufferStrategy strategy;
private SpriteCache spriteCache;
private BufferedImage background;
private MidiShareInput midiHandler;
public Proj1() {
spriteCache = new SpriteCache();
JFrame ventana = new JFrame("Proj1");
JPanel panel = (JPanel)ventana.getContentPane();
setBounds(0,0,Stage.WIDTH,Stage.HEIGHT);
panel.setPreferredSize(new Dimension(Stage.WIDTH,Stage.HEIGHT));
panel.setLayout(null);
panel.add(this);
ventana.setBounds(0,0,Stage.WIDTH,Stage.HEIGHT);
ventana.setUndecorated(true); //no volem els botons de les finestres
ventana.setVisible(true);
ventana.addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
ventana.setResizable(false);
createBufferStrategy(2);
strategy = getBufferStrategy();
requestFocus();
addKeyListener(this);
setIgnoreRepaint(true);
BufferedImage cursor = spriteCache.createCompatible(10,10,Transparency.BITMASK);
Toolkit t = Toolkit.getDefaultToolkit();
//Cursor c = t.createCustomCursor(cursor,new Point(5,5),"null"); //amaguem el cursor
//setCursor(c);
background = spriteCache.createCompatible(
Stage.WIDTH,
Stage.HEIGHT,
Transparency.OPAQUE);
}
public void paintWorld(String vnota) {
Graphics2D g = (Graphics2D)strategy.getDrawGraphics();
g.setColor(Color.blue);
g.fillRect(0,0,background.getWidth(),background.getHeight());
g.setFont(new Font("Arial",Font.BOLD,400));
g.setPaint(Color.LIGHT_GRAY);
g.drawString(vnota,Stage.WIDTH/2-250,Stage.HEIGHT/2+100);
strategy.show();
}
public SpriteCache getSpriteCache() {
return spriteCache;
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_Q : midiHandler.finalitzar(); System.exit(0); break; //lletra Q: quit
case KeyEvent.VK_S :System.out.println(midiHandler.inport);
case KeyEvent.VK_C : paintWorld("C"); midiHandler.playNote(60); break;
case KeyEvent.VK_D : paintWorld("D"); midiHandler.playNote(62); break;
case KeyEvent.VK_E : paintWorld("E"); midiHandler.playNote(64); break;
case KeyEvent.VK_F : paintWorld("F"); midiHandler.playNote(65); break;
case KeyEvent.VK_G : paintWorld("G"); midiHandler.playNote(67); break;
case KeyEvent.VK_A : paintWorld("A"); midiHandler.playNote(69); break;
case KeyEvent.VK_B : paintWorld("B"); midiHandler.playNote(71); break;
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void game() {
paintWorld("");
midiHandler = new MidiShareInput(this);
}
public static void main(String[] args) {
Proj1 inv = new Proj1();
inv.game();
}
}
package v4;
import java.awt.*;
import java.awt.event.*;
import grame.midishare.*;
public class MidiShareInput extends MidiAppl {
int inport;
int outport;
protected Proj1 proj1;
public MidiShareInput(Proj1 proj1) {
this.proj1 = proj1;
// set these how you want them
inport=0;
outport=1;
int installed = 0;
try {
installed = Midi.Share();
}
catch (UnsatisfiedLinkError e) {
e.printStackTrace();
System.out.println(
"\nMidiShare Java API probably not installed properly, grame.midishare.Midi.Share() barfed.\n" + e);
System.exit(0);
}
System.out.println("installed = " + installed);
int version = Midi.GetVersion();
System.out.println("version = " + version);
int numberOfAppl = Midi.CountAppls();
System.out.println("numberOfAppl = " + numberOfAppl);
try {
this.Open("MidiShareInput");
Midi.Connect(this.refnum, 0, 1);
Midi.Connect(0, this.refnum, 1);
// Check output connection
int connected = Midi.IsConnected(this.refnum, 0);
System.out.println("Connected for input? " + connected);
// Check input connection
connected = Midi.IsConnected(0, this.refnum);
System.out.println("Connected for output? " + connected);
//em connecto a fluidsynth
int ref_fluidsynth;
if ((ref_fluidsynth = Midi.GetNamedAppl("fluidsynth")) > 0) Midi.Connect (this.refnum,ref_fluidsynth, 1);
//em connecto al mscontrol
int ref_mscontrol;
if ((ref_mscontrol = Midi.GetNamedAppl("mscontrol")) > 0) Midi.Connect (ref_mscontrol,this.refnum, 1);
//em connecto al vkeybd
int ref_vkeybd;
if ((ref_vkeybd = Midi.GetNamedAppl("vkeybd")) > 0) Midi.Connect (ref_vkeybd,this.refnum, 1);
StringBuffer text = new StringBuffer();
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("-------------------------------------");
System.out.println(text.toString());
}
catch (MidiException e1) {
System.out.println("Error opening MidiShareInput: " + e1);
e1.printStackTrace();
}
}
public void Open(String name) throws MidiException {
super.Open(name);
configureFilter();
}
/* kill active sensing */
void configureFilter() {
int i;
for (i = 0; i < 256; i++) {
//Midi.AcceptPort(filter, i, 1);
Midi.AcceptPort(filter, i, 0);
Midi.AcceptType(filter, i, 1);
}
for (i = 0; i < 16; i++) {
Midi.AcceptChan(filter, i, 1);
}
Midi.AcceptPort(filter, inport, 1);
Midi.AcceptType(filter, Midi.typeActiveSens, 0);
// Midi.AcceptType(filter, Midi.typeSysEx, 0);
System.out.println("MidiShare configureFilter() filter#" + filter);
}
/** Simply notify that an input event occurred, print what kind */
public void ReceiveAlarm(int ev) {
System.out.println("\n");
System.out.println("Tipus event: " + Midi.GetType(ev) + " (0=typeNote; 1=typeKeyOn; 2=typeKeyOff)");
System.out.println("Canal: " + Midi.GetChan(ev));
System.out.println("Data0: " + Midi.GetData0(ev) + " (altura en el cas de Note On/Off)");
System.out.println("Data1: " + Midi.GetData1(ev) + " (velocitat en el cas de Note On/Off)");
switch (Midi.GetType(ev)) {
case Midi.typeNote :
System.out.println("MidiShareInput, received typeNote");
proj1.paintWorld(String.valueOf(Midi.GetData0(ev)));
break;
case Midi.typeKeyOn :
System.out.println("MidiShareInput, received typeKeyOn");
proj1.paintWorld(String.valueOf(Midi.GetData0(ev)));
break;
case Midi.typeKeyOff :
proj1.paintWorld(String.valueOf(Midi.GetData0(ev)));
break;
case Midi.typeKeyPress :
System.out.println("MidiShareInput, received typeKeyPress");
break;
case Midi.typeCtrlChange :
System.out.println("MidiShareInput, typeCtrlChange");
break;
case Midi.typeProgChange :
System.out.println("MidiShareInput, received typeProgChange");
break;
case Midi.typeChanPress :
System.out.println("MidiShareInput, received typeChanPress");
break;
case Midi.typePitchWheel :
System.out.println("MidiShareInput, received typePitchWheel");
break;
case Midi.typeSysEx :
System.out.println("MidiShareInput, received typeSysEx");
break;
default :
break;
}
Midi.SendIm(this.refnum, ev);
}
void playNote(int pitch) {
int channel = 1;
int vel = 80;
int event = Midi.NewEv(Midi.typeKeyOn); // ask for a new note event
if (event != 0) { // if the allocation was succesfull
Midi.SetChan(event, channel); // set the Midi channel
Midi.SetPort(event, outport); // set the destination port
Midi.SetField(event, 0, pitch); // set the pitch field
Midi.SetField(event, 1, vel); // set the velocity field
Midi.SendIm(refnum, event);
}
System.out.println("Sent Midi note on " + (pitch));
try {
Thread.sleep(200);
}
catch (InterruptedException e) {
}
event = Midi.NewEv(Midi.typeKeyOff);
if (event != 0) {
Midi.SetChan(event, channel);
Midi.SetPort(event, outport);
Midi.SetField(event, 0, pitch);
Midi.SetField(event, 1, vel);
Midi.SendIm(refnum, event);
}
System.out.println("Sent Midi note off " + (pitch));
try {
Thread.sleep(200);
}
catch (InterruptedException e) {
}
}
public void finalitzar() {
this.Close();
System.out.println("Closing Midi, byebye");
}
}
