diff --git a/android/project.properties b/android/project.properties index 0840b4a..b7c2081 100644 --- a/android/project.properties +++ b/android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-15 +target=android-10 diff --git a/android/res/raw/rom1a.syx b/android/res/raw/rom1a.syx new file mode 100644 index 0000000..ae79b46 Binary files /dev/null and b/android/res/raw/rom1a.syx differ diff --git a/android/src/com/google/synthesizer/android/AndroidGlue.java b/android/src/com/google/synthesizer/android/AndroidGlue.java index 165d539..e79c87b 100644 --- a/android/src/com/google/synthesizer/android/AndroidGlue.java +++ b/android/src/com/google/synthesizer/android/AndroidGlue.java @@ -1,14 +1,41 @@ package com.google.synthesizer.android; +import com.google.synthesizer.core.midi.MessageOutputProcessor; -public class AndroidGlue { +/** + * JNI container for connecting to C++ synth engine. The actual implementation is in the cpp/src + * subdirectory of the repository, and interfaces with JNI. + * + * This class implements the MessageOutputProcessor interface, so you can use those methods to + * actually send MIDI data. + */ +public class AndroidGlue extends MessageOutputProcessor { + /** + * Create and initialize the engine. This should be done once per process. + */ public native void start(); + + /** + * Start or pause the actual sound generation. + * + * @param isPlaying Whether the sound generation should be enabled or no. + */ public native void setPlayState(boolean isPlaying); + + /** + * Send a MIDI message. Currently supported messages include DX7 sysex data, and note-on/note-off, + * but it will expand. + * + * @param midiData The midi data to send. + */ public native void sendMidi(byte[] midiData); + public void onMessage(byte[] midiData) { + sendMidi(midiData); + } + static { System.loadLibrary("synth"); } } - diff --git a/android/src/com/google/synthesizer/android/ui/PianoActivity2.java b/android/src/com/google/synthesizer/android/ui/PianoActivity2.java index 0ec8fd0..84ac602 100644 --- a/android/src/com/google/synthesizer/android/ui/PianoActivity2.java +++ b/android/src/com/google/synthesizer/android/ui/PianoActivity2.java @@ -16,8 +16,17 @@ package com.google.synthesizer.android.ui; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; + import android.app.Activity; import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; import android.widget.Spinner; import com.google.synthesizer.R; @@ -44,7 +53,31 @@ public class PianoActivity2 extends Activity { androidGlue_ = new AndroidGlue(); androidGlue_.start(); + InputStream patchIs = getResources().openRawResource(R.raw.rom1a); + byte[] patchData = new byte[4104]; + try { + patchIs.read(patchData); + androidGlue_.sendMidi(patchData); + ArrayList patchNames = new ArrayList(); + for (int i = 0; i < 32; i++) { + patchNames.add(new String(patchData, 124 + 128 * i, 10, "ISO-8859-1")); + } + ArrayAdapter adapter = new ArrayAdapter( + this, android.R.layout.simple_spinner_item, patchNames); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + presetSpinner_.setAdapter(adapter); + } catch (IOException e) { + Log.e(getClass().getName(), "loading patches failed"); + } + presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { + public void onItemSelected(AdapterView parent, View view, int position, long id) { + androidGlue_.sendMidi(new byte[] {(byte)0xc0, (byte)position}); + } + public void onNothingSelected(AdapterView parent) { + } + }); piano_.bindTo(androidGlue_); + } @Override diff --git a/android/src/com/google/synthesizer/android/widgets/piano/PianoView.java b/android/src/com/google/synthesizer/android/widgets/piano/PianoView.java index 0099ffb..c6fa73d 100644 --- a/android/src/com/google/synthesizer/android/widgets/piano/PianoView.java +++ b/android/src/com/google/synthesizer/android/widgets/piano/PianoView.java @@ -28,7 +28,7 @@ import android.view.MotionEvent; import android.view.View; import com.google.synthesizer.R; -import com.google.synthesizer.android.AndroidGlue; +import com.google.synthesizer.core.midi.MidiListener; import com.google.synthesizer.core.model.composite.MultiChannelSynthesizer; import com.google.synthesizer.core.music.Note; @@ -360,7 +360,7 @@ public class PianoView extends View { * Connects the PianoView to an AndroidGlue. This should probably be a MidiListener instead, * though... */ - public void bindTo(final AndroidGlue midiSink) { + public void bindTo(final MidiListener midiSink) { this.setPianoViewListener(new PianoViewListener() { { fingerMap_ = new HashMap(); @@ -369,13 +369,13 @@ public class PianoView extends View { noteUp(finger); int midiNote = Note.getKeyforLog12TET(logFrequency); fingerMap_.put(finger, midiNote); - midiSink.sendMidi(new byte[] {(byte) 0x90, (byte) midiNote, 64}); + midiSink.onNoteOn(0, midiNote, 64); } public void noteUp(int finger) { if (fingerMap_.containsKey(finger)) { int midiNote = fingerMap_.get(finger); fingerMap_.remove(finger); - midiSink.sendMidi(new byte[] {(byte) 0x80, (byte) midiNote, 64}); + midiSink.onNoteOff(0, midiNote, 64); } } private Map fingerMap_;