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