engine on Android. Note that this particular patchset disables the Java-based synthesis, so probably shouldn't be committed as-is to mainline.bklimt
parent
a99ac7a38c
commit
c3509e50c1
@ -0,0 +1,10 @@ |
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType"> |
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/MusicSynthesizer/libs" type="2"/> </resources>}"/> |
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/> |
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/MusicSynthesizer/jni" type="2"/> </resources>}"/> |
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${system_property:user.home}/install/android-ndk-r7b/ndk-build"/> |
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/> |
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/> |
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${project_loc}"/> |
||||
</launchConfiguration> |
@ -0,0 +1,18 @@ |
||||
LOCAL_PATH := $(call my-dir)/../../cpp/src
|
||||
|
||||
include $(CLEAR_VARS) |
||||
LOCAL_MODULE := synth
|
||||
LOCAL_CPP_EXTENSION := .cc
|
||||
LOCAL_SRC_FILES := dx7note.cc \
|
||||
env.cc \
|
||||
fm_core.cc \
|
||||
fm_op_kernel.cc \
|
||||
freqlut.cc \
|
||||
resofilter.cc \
|
||||
ringbuffer.cc \
|
||||
sawtooth.cc \
|
||||
sin.cc \
|
||||
synth_unit.cc
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY) |
||||
|
@ -0,0 +1 @@ |
||||
APP_STL := stlport_static
|
@ -0,0 +1,14 @@ |
||||
# This file is automatically generated by Android Tools. |
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED! |
||||
# |
||||
# This file must be checked in Version Control Systems. |
||||
# |
||||
# To customize properties used by the Ant build system edit |
||||
# "ant.properties", and override values to adapt the script to your |
||||
# project structure. |
||||
# |
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): |
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt |
||||
|
||||
# Project target. |
||||
target=android-15 |
@ -0,0 +1,14 @@ |
||||
package com.google.synthesizer.android; |
||||
|
||||
|
||||
public class AndroidGlue { |
||||
|
||||
public native void start(); |
||||
public native void setPlayState(boolean isPlaying); |
||||
public native void sendMidi(byte[] midiData); |
||||
|
||||
static { |
||||
System.loadLibrary("synth"); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,66 @@ |
||||
/* |
||||
* Copyright 2012 Google Inc. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.synthesizer.android.ui; |
||||
|
||||
import android.app.Activity; |
||||
import android.os.Bundle; |
||||
import android.widget.Spinner; |
||||
|
||||
import com.google.synthesizer.R; |
||||
import com.google.synthesizer.android.AndroidGlue; |
||||
import com.google.synthesizer.android.widgets.knob.KnobView; |
||||
import com.google.synthesizer.android.widgets.piano.PianoView; |
||||
|
||||
/** |
||||
* Activity for simply playing the piano. |
||||
* This version is hacked up to send MIDI to the C++ engine. This needs to |
||||
* be refactored to make it cleaner. |
||||
*/ |
||||
public class PianoActivity2 extends Activity { |
||||
@Override |
||||
public void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.piano); |
||||
|
||||
piano_ = (PianoView)findViewById(R.id.piano); |
||||
volumeKnob_ = (KnobView)findViewById(R.id.volumeKnob); |
||||
presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); |
||||
// TODO: wire these up (preset spinner should send patch selection)
|
||||
|
||||
androidGlue_ = new AndroidGlue(); |
||||
androidGlue_.start(); |
||||
|
||||
piano_.bindTo(androidGlue_); |
||||
} |
||||
|
||||
@Override |
||||
protected void onPause() { |
||||
androidGlue_.setPlayState(false); |
||||
super.onPause(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onResume() { |
||||
androidGlue_.setPlayState(true); |
||||
super.onResume(); |
||||
} |
||||
|
||||
private AndroidGlue androidGlue_; |
||||
private PianoView piano_; |
||||
private KnobView volumeKnob_; |
||||
private Spinner presetSpinner_; |
||||
} |
@ -0,0 +1,145 @@ |
||||
#include <assert.h> |
||||
#include <stddef.h> |
||||
#include <jni.h> |
||||
#include <SLES/OpenSLES.h> |
||||
#include <SLES/OpenSLES_Android.h> |
||||
|
||||
#include <android/log.h> |
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "synth", __VA_ARGS__) |
||||
|
||||
#include "synth.h" |
||||
#include "freqlut.h" |
||||
#include "sin.h" |
||||
#include "synth_unit.h" |
||||
|
||||
RingBuffer *ring_buffer; |
||||
SynthUnit *synth_unit; |
||||
|
||||
const int N_BUFFERS = 2; |
||||
const int BUFFER_SIZE = 64; |
||||
|
||||
int16_t buffer[BUFFER_SIZE * N_BUFFERS]; |
||||
int cur_buffer = 0; |
||||
int count = 0; |
||||
|
||||
// engine interfaces
|
||||
static SLObjectItf engineObject = NULL; |
||||
static SLEngineItf engineEngine; |
||||
|
||||
// output mix interfaces
|
||||
static SLObjectItf outputMixObject = NULL; |
||||
|
||||
// buffer queue player interfaces
|
||||
static SLObjectItf bqPlayerObject = NULL; |
||||
static SLPlayItf bq_player_play; |
||||
static SLVolumeItf bq_player_volume; |
||||
static SLAndroidSimpleBufferQueueItf bq_player_buffer_queue; |
||||
static SLBufferQueueItf buffer_queue_itf; |
||||
|
||||
extern "C" void BqPlayerCallback(SLAndroidSimpleBufferQueueItf queueItf, |
||||
void *data) { |
||||
if (count >= 1000) return; |
||||
int16_t *buf_ptr = buffer + BUFFER_SIZE * cur_buffer; |
||||
synth_unit->GetSamples(BUFFER_SIZE, buf_ptr); |
||||
SLresult result = (*queueItf)->Enqueue(bq_player_buffer_queue, |
||||
buf_ptr, BUFFER_SIZE * 2); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
cur_buffer = (cur_buffer + 1) % N_BUFFERS; |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jint JNICALL |
||||
Java_com_google_synthesizer_android_AndroidGlue_hello(JNIEnv *env, |
||||
jobject thiz) { |
||||
LOGI("here %d!", 42); |
||||
return 42; |
||||
} |
||||
|
||||
void CreateEngine() { |
||||
SLresult result; |
||||
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
|
||||
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
|
||||
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, |
||||
&engineEngine); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
|
||||
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, |
||||
0, NULL, NULL); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT void JNICALL |
||||
Java_com_google_synthesizer_android_AndroidGlue_start(JNIEnv *env, |
||||
jobject thiz) { |
||||
CreateEngine(); |
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = |
||||
{SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, N_BUFFERS}; |
||||
SLDataFormat_PCM format_pcm = { |
||||
SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_48, |
||||
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, |
||||
SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN |
||||
// TODO: compute real endianness
|
||||
}; |
||||
SLDataSource audio_src = {&loc_bufq, &format_pcm}; |
||||
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, |
||||
outputMixObject}; |
||||
SLDataSink audio_sink = {&loc_outmix, NULL}; |
||||
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; |
||||
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; |
||||
SLresult result; |
||||
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, |
||||
&audio_src, &audio_sink, 2, ids, req); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, |
||||
&bq_player_play); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, |
||||
&bq_player_buffer_queue); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, |
||||
&bq_player_volume); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
result = (*bq_player_buffer_queue)->RegisterCallback(bq_player_buffer_queue, |
||||
&BqPlayerCallback, NULL); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
|
||||
double sample_rate = 48000.0; |
||||
Freqlut::init(sample_rate); |
||||
Sin::init(); |
||||
ring_buffer = new RingBuffer(); |
||||
synth_unit = new SynthUnit(ring_buffer); |
||||
for (int i = 0; i < N_BUFFERS - 1; ++i) { |
||||
BqPlayerCallback(bq_player_buffer_queue, NULL); |
||||
} |
||||
|
||||
result = (*bq_player_play)->SetPlayState(bq_player_play, |
||||
SL_PLAYSTATE_PLAYING); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT void JNICALL |
||||
Java_com_google_synthesizer_android_AndroidGlue_sendMidi(JNIEnv *env, |
||||
jobject thiz, jbyteArray jb) { |
||||
uint8_t *data = (uint8_t *)env->GetByteArrayElements(jb, NULL); |
||||
if (data != NULL) { |
||||
ring_buffer->Write(data, env->GetArrayLength(jb)); |
||||
env->ReleaseByteArrayElements(jb, (jbyte *)data, JNI_ABORT); |
||||
} |
||||
} |
||||
|
||||
extern "C" JNIEXPORT void JNICALL |
||||
Java_com_google_synthesizer_android_AndroidGlue_setPlayState(JNIEnv *env, |
||||
jobject thiz, jboolean isPlaying) { |
||||
SLresult result = (*bq_player_play)->SetPlayState(bq_player_play, |
||||
isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED); |
||||
assert(SL_RESULT_SUCCESS == result); |
||||
} |
||||
|
Loading…
Reference in new issue