Hi Mike,
tx for your information.
The two values PC / CC are the values to be set if using the existing way (screenshot mobilesheet midi commands).
Here ist the code i use to fire the complete midi event (using sendmidi console app triggered by java)
The method generating the events is
When running in demo (main method) you get output for sendmidi (commandline tool)
KetronBank:1; KetronRegNr:3; CC:0; PC:2 // The Mapping
/Users/k/Downloads/sendmidi-macos-1.0.13/sendmidi dev MIDI_DEVICE_NAME ch 16 cc 00 0 cc 32 00 pc 2 // the real sendmidi code "MIDI_DEVICE" depends on the device midi is send to
Channel:16 Bank:1 RegNr:2 MidiCommand:/Users/k/Downloads/sendmidi-macos-1.0.13/sendmidi dev MIDI_DEVICE_NAME ch 16 cc 00 0 cc 32 00 pc 2
That's the command ketron understands.
KetronBank:1; KetronRegNr:3; CC:0; PC:2 // The Mapping
ch 16 cc 00 0 cc 32 00 pc 2 // corresponding Midi command using sendmidi console app
I hope, it's possible to understand my infos
If there is something to test with midi commands, let me know.
I my java-program i use sendmidi and receivemidi commandline tool because I wasn't able to send/receive midi commands on other way on mac.
tx for your information.
The two values PC / CC are the values to be set if using the existing way (screenshot mobilesheet midi commands).
Here ist the code i use to fire the complete midi event (using sendmidi console app triggered by java)
The method generating the events is
Code:
public ArrayList<String> sendRegistrationChange_SD9(String midiDevice, int registerBank, int registrierungNr){
When running in demo (main method) you get output for sendmidi (commandline tool)
KetronBank:1; KetronRegNr:3; CC:0; PC:2 // The Mapping
/Users/k/Downloads/sendmidi-macos-1.0.13/sendmidi dev MIDI_DEVICE_NAME ch 16 cc 00 0 cc 32 00 pc 2 // the real sendmidi code "MIDI_DEVICE" depends on the device midi is send to
Channel:16 Bank:1 RegNr:2 MidiCommand:/Users/k/Downloads/sendmidi-macos-1.0.13/sendmidi dev MIDI_DEVICE_NAME ch 16 cc 00 0 cc 32 00 pc 2
That's the command ketron understands.
KetronBank:1; KetronRegNr:3; CC:0; PC:2 // The Mapping
ch 16 cc 00 0 cc 32 00 pc 2 // corresponding Midi command using sendmidi console app
I hope, it's possible to understand my infos
If there is something to test with midi commands, let me know.
Code:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package net.gr.midi.midi_sys_ex;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.gr.midi.view.model.Control;
/**
*
* @author k
* Dieses Projekt beinhaltet einen Wrapper, um aus Java heraus System-Exclusive MIDI Daten an ein MIDI-Device zu senden.
* Der eigentliche Transmitter ist das Tool sendmidi
* The project website is https://github.com/gbevin/SendMIDI
*/
public class MIDI_SYS_EX_SENDER {
public boolean test = false;
File SEND_MIDI_PROGRAM = null; // Programm zum Senden der MIDI-SYS-EX Daten
public MIDI_SYS_EX_SENDER(File sendMidi_Program){
SEND_MIDI_PROGRAM = sendMidi_Program;
}
public MIDI_SYS_EX_SENDER(String sendMidi_Program){
SEND_MIDI_PROGRAM = new File(sendMidi_Program);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
MIDI_SYS_EX_SENDER demo = new MIDI_SYS_EX_SENDER("/Users/k/Downloads/sendmidi-macos-1.0.13/sendmidi");
System.out.println("Available MIDI-Interfaces:");
System.out.println(demo.getMidiInterfacesOUT());
// Test
demo.test = true;
for (int bank = 1; bank <=4; bank++){
for (int reg = 1; reg <=10; reg++){
demo.sendRegistrationChange_SD9("", bank, reg);
}
}
}
/**
* Einlesen aller verfügbarer MIDI-Interfaces
* @return Liefert eine Liste der verfügbaren MIDI-Interfaces OUT (aus sicht des PC) zurück.
*/
public ArrayList<String> getMidiInterfacesOUT(){
ArrayList<String> interfaces = new ArrayList<>();
String[] command = new String[2];
command[0] = SEND_MIDI_PROGRAM.getPath();
command[1] = "list";
Runtime rt = Runtime.getRuntime();
Process exec;
try {
exec = rt.exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ( (line=br.readLine())!=null){
interfaces.add(line.trim());
}
} catch (IOException ex) {
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
return interfaces;
}
/**
* Schickt einen kombinierte Note-ON / Note-OFF Event
* @param channel
* @param note
* @param midiDevice
* @param noteOFF true: Note-OFF wird nachgesendet false: nur Note-ON Event wird gesendet.
* @return ArrayList (String) mit Statusmeldungen.
* @throws Exception
*/
public ArrayList<String> sendNoteOnOffEvent(int channel, String note, String midiDevice, boolean noteOFF) throws Exception{
MIDI_TOOLS.get_Note_On_Off_Event(channel, note);
ArrayList<String> cmd = new ArrayList<>();
cmd.add( SEND_MIDI_PROGRAM.getPath() );
cmd.add( "dev" );
cmd.add( midiDevice );
cmd.add("ch");
cmd.add( Integer.toString(channel) );
cmd.add("on");
cmd.add(note);
cmd.add("64");
String commandArray[] = cmd.stream().toArray(String[]::new);
ArrayList<String> retMessage = new ArrayList<>();
Runtime rt = Runtime.getRuntime();
Process exec;
try {
exec = rt.exec(commandArray);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ( (line=br.readLine())!=null)
retMessage.add(line);
} catch (IOException ex) {
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
if (noteOFF) {
cmd = new ArrayList<>();
cmd.add(SEND_MIDI_PROGRAM.getPath());
cmd.add("dev");
cmd.add( midiDevice );
cmd.add("ch");
cmd.add(Integer.toString(channel));
cmd.add("off");
cmd.add(note);
cmd.add("0");
rt = Runtime.getRuntime();
try {
exec = rt.exec(commandArray);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ((line = br.readLine()) != null) {
retMessage.add(line);
}
} catch (IOException ex) {
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
}
return retMessage;
}
/**
* Sende System Exclusiv-Midi-Data aus Datei an das MIDIdevice senden
* @param midiDevice Empfägner MIDI-Interface
* @param sysExFile
* @return Fehlerliste
* @throws Exception
*/
public ArrayList<String> sendMidiSysExFile(String midiDevice, File sysExFile) throws Exception{
// if (!canMIDI_device(MIDIdevice))
// throw new Exception("Das MIDI-Interface " + MIDIdevice + " ist nicht verfügbar.");
ArrayList<String> cmd = new ArrayList<>();
cmd.add( SEND_MIDI_PROGRAM.getPath() );
cmd.add( "dev" );
cmd.add( midiDevice );
cmd.add( "syf" );
cmd.add( sysExFile.getPath() );
String commandArray[] = cmd.stream().toArray(String[]::new);
ArrayList<String> retMessage = new ArrayList<>();
Runtime rt = Runtime.getRuntime();
Process exec;
try {
exec = rt.exec(commandArray);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ( (line=br.readLine())!=null)
retMessage.add(line);
} catch (IOException ex) {
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
return retMessage;
}
/**
* Prüfen, ob das übergebene MIDI-Interface verfügbar ist
* @param midiDevice
* @return
* @throws Exception
*/
private boolean canMIDI_device(String midiDevice) {
ArrayList<String> midiInterfaces = getMidiInterfacesOUT();
return midiInterfaces.contains( midiDevice );
}
public ArrayList<String> sendControlChange(String MIDIdevice, int MIDIchannel, int CC, int value){
if (Control.IS_TEST)
System.out.println("Start sendControlChange()");
ArrayList<String> cmd = new ArrayList<>();
cmd.add( SEND_MIDI_PROGRAM.getPath() );
cmd.add( "dev" );
// cmd.add( MIDI_TOOLS.getEscapedDeviceName(MIDIdevice) );
cmd.add( MIDIdevice );
cmd.add( "ch" );
cmd.add( Integer.toString(MIDIchannel) );
cmd.add("cc");
cmd.add( Integer.toString(CC));
cmd.add( Integer.toString(value) );
String commandArray[] = cmd.stream().toArray(String[]::new);
if (Control.IS_TEST){
System.out.println("senControlChange() mit Daten:");
printArray(commandArray);
// return r;
}
ArrayList<String> retMessage = new ArrayList<>();
Runtime rt = Runtime.getRuntime();
Process exec;
try {
exec = rt.exec(commandArray);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ( (line=br.readLine())!=null)
retMessage.add(line);
} catch (IOException ex) {
System.out.println("Exception beim Senden des Command: " + ex.getMessage());
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
if (Control.IS_TEST){
System.out.print("Ende sendControlChange()");
for (String s : retMessage)
System.out.println(s);
}
return retMessage;
}
/**
*
* @param MIDIdevice
* @param registerBank
* @param registrierungNr
* @return Statusmeldungen
*/
public ArrayList<String> sendRegistrationChange_SD9(String midiDevice, int registerBank, int registrierungNr){
if (registerBank>4 | registerBank < 1)
throw new IndexOutOfBoundsException("Registerbank ungültig");
if (registrierungNr > 1000 | registrierungNr < 1)
throw new IndexOutOfBoundsException("Registeriungsnummer ungültig");
int regNr = registrierungNr -1;
int regBank = registerBank;
//canMIDI_device(MIDIdevice);
// Bank 1 - 4 => cc 0 = 0, 8, 16, 24
int bank[] = {0, 8, 16, 24};
// ControlChange 00:
// Value 0 - 7 Bank 1
// Value 8 - 15 Bank 2
// Value 16 - 23 Bank 3
// Value 24 - 31 Bank 4
// Regnr 0-127 cc 00 = 0;
// Regnr 128-255 cc 00 = 1;
// Regnr 256-382 cc 00 = 2;
// Regnr 382-509 cc 00 = 3;
// Regnr 509-636 cc 00 = 4;
// Regnr 636-763 cc 00 = 5;
// Regnr 763-890 cc 00 = 6;
// Regnr 890-1000 cc 00 = 7;
// Beim Überlauf über 10xx nächste Bank 8 und offset aus regNr wieder 0;
int cc00 = Math.round(regNr/128);
//System.out.println("cc00: " + cc00);
int pcNr = regNr % 128;
//System.out.println("pcNR: " + pcNr);
ArrayList<String> cmd = new ArrayList<>();
cmd.add( SEND_MIDI_PROGRAM.getPath() );
cmd.add( "dev" );
cmd.add(midiDevice );
cmd.add( "ch" );
cmd.add("16");
cmd.add("cc");
cmd.add("00");
cmd.add(Integer.toString(cc00 + bank[regBank-1]));
cmd.add("cc");
cmd.add("32");
cmd.add("00");
cmd.add("pc");
cmd.add(Integer.toString(pcNr));
String commandArray[] = cmd.stream().toArray(String[]::new);
if (test){
String csv = String.format("KetronBank:%d; KetronRegNr:%d; CC:%d; PC:%d", registerBank, registrierungNr, (cc00 + bank[regBank-1]), pcNr);
System.out.println(csv);
// return null;
System.out.println(String.format("Channel:%s Bank:%s RegNr:%s MidiCommand:%s",16, regBank, regNr, printArray(commandArray) ));
//printArray(commandArray);
ArrayList<String> r = new ArrayList<>();
r.add("Test done");
return r;
}
ArrayList<String> retMessage = new ArrayList<>();
Runtime rt = Runtime.getRuntime();
Process exec;
try {
exec = rt.exec(commandArray);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ( (line=br.readLine())!=null)
retMessage.add(line);
} catch (IOException ex) {
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
return retMessage;
}
/**
*
* @param MIDIdevice Empfäger für Sys-Ex MIDI Daten
* @param hex Hex Array für System Exclusiv Meldungen
* @return ArrayList<String%gt; Rückmeldungen aus Konsolenanwendung
* @throws java.lang.Exception
*/
public ArrayList<String> sendMidiSysExCommand(String midiDevice, String[] hex) throws Exception{
if (hex == null)
throw new Exception("Keine MIDI-Daten zum Senden übergeben");
if (hex.length==0)
throw new Exception("Keine MIDI-Daten zum Senden übergeben");
ArrayList<String> cmd = new ArrayList<>();
cmd.add( SEND_MIDI_PROGRAM.getPath() );
cmd.add( "dev" );
cmd.add(midiDevice );
cmd.add("hex" );
cmd.add( "syx" );
cmd.addAll(Arrays.asList(hex));
String commandArray[] = cmd.stream().toArray(String[]::new);
if (test){
printArray(commandArray);
ArrayList<String> r = new ArrayList<>();
r.add("Test done");
return r;
}
ArrayList<String> retMessage = new ArrayList<>();
Runtime rt = Runtime.getRuntime();
Process exec;
try {
exec = rt.exec(commandArray);
BufferedReader br = new BufferedReader(new InputStreamReader(exec.getInputStream()));
String line = "";
while ( (line=br.readLine())!=null)
retMessage.add(line);
} catch (IOException ex) {
Logger.getLogger(MIDI_SYS_EX_SENDER.class.getName()).log(Level.SEVERE, null, ex);
}
return retMessage;
}
/**
* Wandelt den übergebenen String song in einen YAMAHA GENOS Hex String um
* Problem: Umlaute können derzeit nicht korrekt umgesetzt werden.
* @param path
* @param song
* @return MIDI-Befehlt für GENOS
* @throws java.lang.Exception
*/
public String[] getHexValuesGENOS(String path, String song) throws Exception{
checkSpecialChars(song);
String toConvert = "CsR&" +path + "/" + song + ".rgt";
ArrayList<String> hexValues = new ArrayList<>();
for (int i = 0; i< toConvert.length(); i++){
String letter = toConvert.substring(i, i+1);
String hexString = Integer.toHexString( letter.charAt(0));
hexValues.add( getDoubleZero(hexString) );
}
return hexValues.stream().toArray(String[]::new);
}
private String getDoubleZero(String hex){
if (hex.length()==1){
return "0" + hex.toUpperCase();
}
return hex.toUpperCase();
}
/**
* Prüft den String auf Sonderzeichen, Umlaute etc
* @param song
*/
private void checkSpecialChars(String song) throws Exception {
String[] SPECIAL_CHARS = {"ä","ö","ü","ß"};
String search = song.toLowerCase();
for (String s : SPECIAL_CHARS)
if (search.contains(s))
throw new Exception("Unerlaubtes Sonderzeichen im Text enthalten: " + s);
}
private String printArray(String[] arr ){
StringBuilder sb = new StringBuilder();
for (String s : arr){
System.out.print(s);
sb.append(s).append(" ");
System.out.print(" ");
}
System.out.println();
return sb.toString();
}
}
I my java-program i use sendmidi and receivemidi commandline tool because I wasn't able to send/receive midi commands on other way on mac.