It works. But I think it only works as long as you don’t have
orientation(LANDSCAPE);
in your setup(). Tried several times now and whenever I’ve got it in setup() Midi was locked.
Now i call orientation(LANDSCAPE); from draw() and that works.
It works. But I think it only works as long as you don’t have
orientation(LANDSCAPE);
in your setup(). Tried several times now and whenever I’ve got it in setup() Midi was locked.
Now i call orientation(LANDSCAPE); from draw() and that works.
what’s about CountdownTimer lib?
@sensn Is that using FluidSynth or an external device or both?
Hi Mark
-I declared the new variable
-I moved the whole midi setup code again inside setup () and modified the part with the new variable
-I copied the void onPause
But it don’t work, im sorry, i think to don’t know where to insert the myOpenDevice, may i ask an help?
@shedMusic
I always test with my external synth.
I think it’s better not use orientation(LANDSCAPE);
When i call it from draw() it works, but not for the screensaver pause thing.
Without orientation(LANDSCAPE) ; both issues are gone; but when the phone goes idle, the sketch restarts in Portrait mode, so i again have to rotate it. I’d prefer to leave it on the top of my synth.
ok … more thinking needed!
Do i leave onPause() as you write it? where to recall it? Thanks
the code works as shedMusic has posted it. are you sure you have completely removed my workaround and orientation(LANDSCAPE) ?
@sensn Why remove orientation(LANDSCAPE) ? Your fix to put the code into a specific void and then recall it one time into the draw, allows us to continue working with the landscapes view, im sorry have i missing something?
@chanof
yes, the fix works just as long as you don’t use orientation(LANDSCAPE) in your setup.
shedMusic suggests not to use my workaround, and I propose to follow his suggestion…
I think he will come up with a complete fix until that you can work with my workaround or use the fix without orientation(LANDSCAPE);
One more test please… can you see what happens
Without orientation(LANDSCAPE); it starts in the expected mode. Portrait when held in portrait. Landscape when held in Landscape.
The only thing is if i start in Landscape and i put it on my synth, and the screensaver starts, when i turn it on again the sketch restarts in Portrait.
With orientation(LANDSCAPE); it’s always in Landscape but will break Midi only after screensaver. (when called from draw().
with orientation in setup(), Midi is locked right at the start. and it doesn’t matter if it’s before or after your Midi code.
I think that might be because orientation(LANDSCAPE); restarts the setup() before onPause() can be called, but I don’t know.
oh, sorry again. Now I was in the first line of draw(). my previous messages still seem to be true.
OK, more testing done …
edit your manifest file in the sketch folder to set landscape
<activity android:name=".MainActivity" android:screenOrientation=“landscape” … etc …
and don’t do anything in you code.
This seems to stop any attempt to set portrait.
yes, now it works perfectly, and the flickering when starting the app is gone too. Great.
I guess sometimes we have to think outside the box.
Great
And now I can get on with the timing stuff.
I think the countdown timer from gotoloop uses milliseconds and this is likely to cause issues for midi, where standard resolution is nano. I am fiddling with it today to see how it might work for a sequencer.
Incomplete and for testing … and for you to see if you can adapt to your sketches. I have for future reasons created a class called ShedMidi that wrap up all the things I last did in setup, so now I create an instance of that … still does exactly the same though as before.
Timing …
I have an array that just contains 16 long values that represent the start times for each grid position, relative to t=0. I then have a function that iterates through this array and calls sendMidi() when enough time has elapsed. This runs as a thread called from MousePressed(), so it can’t be interred with by any processing going on in draw() … should be better timing and less jitter.
See how it goes …
import android.app.Activity;
import android.content.Context;
import android.os.Bundle ;
import android.os.Handler ;
import android.os.Looper ;
//import android.System ;
import android.media.midi.* ;
import android.content.pm.PackageManager ;
Activity act;
Context context;
Bundle properties ;
ShedMidi shedMidi ;
// just for testing ... an array to simulate note start times .. starting at t=0 for first note
long[] noteStartTimes = new long[16];
//length in nanoseconds of a single cell in the grid
long cellLength = (long)(0.125*1000000000L) ; // 1/16th note at 120bpm ... use a bpm slider to update this (using mouseDragged() maybe?)
boolean isPlaying = false ;
void setup() {
fullScreen(P2D);
act = this.getActivity();
context = act.getApplicationContext();
println("setup m");
shedMidi = new ShedMidi() ;
for (int i=0; i<16; i++) {
noteStartTimes[i] = i*cellLength ;
}
}
void draw() {
background(0);
fill(255);
textSize(40);
textAlign(CENTER, CENTER);
text("LANDSCAPE", 0, 0, width, height);
}
void mousePressed() {
//would be better to have start & stop buttons , but for testing ....
if (!isPlaying) {
isPlaying = true ;
thread("playSequence");
} else {
isPlaying = false ;
}
}
//call as a thread e.g. as in mousePressed()
void playSequence() {
long startTime = System.nanoTime();
int index = 0 ;
while (index < 16 && isPlaying) {
if (noteStartTimes[index] < System.nanoTime() - startTime) {
shedMidi.sendMidi();
index++ ;
}
}
}
class ShedMidi {
MidiManager m ;
MidiDevice myOpenDevice ;
MidiDeviceInfo[] deviceInfo ;
MidiDeviceInfo.PortInfo[] portInfo ;
MidiInputPort inputPort ;
ShedMidi() {
m = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
//check device supports MIDI
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
// Phone.tablet supports MIDI
println("great .... can do midi things");
//search for attached devices
println("setup deviceInfo");
deviceInfo = m.getDevices();
if (deviceInfo.length == 0) {
println("No MIDI devices found .. " + deviceInfo.length);
} else {
println("Num MIDI Devices found = " + deviceInfo.length);
for (int i=0; i<deviceInfo.length; i++) {
println("Device " + i);
println(" Num MIDI inputs = " + deviceInfo[i].getInputPortCount());
println(" Num MIDI outputs = " + deviceInfo[i].getOutputPortCount());
properties = deviceInfo[i].getProperties();
println(" Manufacturer = " + properties.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER));
println(" Product =" + properties.getString(MidiDeviceInfo.PROPERTY_PRODUCT));
println(" Name = " + properties.getString(MidiDeviceInfo.PROPERTY_NAME));
println(" Serial Number = " + properties.getString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER));
//Port Information
portInfo = deviceInfo[i].getPorts();
println(" Num ports found = " + portInfo.length);
for (int j=0; j<portInfo.length; j++) {
println(" port " + j + " Name = " + portInfo[j].getName() + "Type = " + portInfo[j].getType());
}// end j loop
println(""); // to give a blank space in the console
}//end i loop
//Try to open a device
m.openDevice(deviceInfo[0], new MidiManager.OnDeviceOpenedListener() {
@Override
public void onDeviceOpened(MidiDevice device) {
if (device == null) {
println("could not open device");
} else {
myOpenDevice = device;
println("device opened and ready for use");
//Open input port
inputPort = myOpenDevice.openInputPort(0);
}//end else
}
} //end m.opendevice
, new Handler(Looper.getMainLooper())
);
} // end do things with MIDI
} else {
println("boo .... no midi possible");
}
}//end constructor
//methods
void sendMidi() {
//Send MIDI note data ... for info .send() is a methid from MidiReceiver class which
byte[] buffer = new byte[32];
int numBytes = 0;
int channel = 10; // MIDI channels 1-16 are encoded as 0-15.
buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
buffer[numBytes++] = (byte)42; // closed hi hat
buffer[numBytes++] = (byte)127; // max velocity
int offset = 0;
// post is non-blocking
try {
inputPort.send(buffer, offset, numBytes);
println("data sent");
}
catch (Exception e) {
println("error sending midi data");
}
}
}// end ShedMidi class
void onPause() {
try {
shedMidi.inputPort.close();
}
catch(Exception e) {
}
}
@shedMusic
Very Great! I can hear that this timing is a lot more exact. Great work.
It was pretty simple in the end for a quick demo, although we’ll see what happens with multiple tracks and channels!