Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
67
externals/oboe/samples/drumthumper/README.md
vendored
Normal file
|
@ -0,0 +1,67 @@
|
|||
**DrumThumper**
|
||||
==========
|
||||
Oboe playback sample app.
|
||||
|
||||
## Abstract
|
||||
**DrumThumper** is a "Drum Pad" app which demonstrates best-practices for low-latency audio playback using the Android **Oboe** API.
|
||||
**DrumThumper** consists of a set of trigger pad widgets and an optional UI for controlling the level and stereo placement of each of the virtual drums.
|
||||
The audio samples are stored in application resources as WAV data. This is parsed and loaded (by routines in **parselib**) into memory blocks.
|
||||
The audio samples are mixed and played by routines in **iolib**.
|
||||
|
||||
**DrumThumper** is written in a combination of Kotlin for the UI and JNI/C++ for the player components (to demonstrate accessing native code from a Kotlin or Java application).
|
||||
|
||||
## Scope
|
||||
**DrumThumper** is designed with the following goals in mind:
|
||||
* To demonstrate the most efficient means of playing audio with the lowest possible latency.
|
||||
* To demonstrate how to play multiple sources of audio mixed into a single Oboe stream.
|
||||
* To demonstrate the life-cycle of an Oboe audio stream and it's relationship to the application lifecycle.
|
||||
* To demonstrate the correct handling of playback errors and output device connection/disconnection.
|
||||
|
||||
Secondarily, **DrumThumper** demonstrates:
|
||||
* Using Android "assets" for audio data.
|
||||
* The mechanism for calling native (C/C++) audio functionality from a Kotlin/Java app.
|
||||
* A mechanism for sharing binary data between a Kotlin/Java app with the native (C/C++) layer.
|
||||
* A mechanism for parsing/loading one type (WAV) of audio data.
|
||||
* How to control the relative levels (gain) of audio sources mixed into an output stream.
|
||||
* How to locate a mono data source in a stereo output stream.
|
||||
* How to use the Oboe resampler to resample source audio to the device playback rate, and therefore not incur this overhead at playback time.
|
||||
|
||||
To keep things simple, **DrumThumper** specifically does not:
|
||||
* Does not support audio samples in other than 16-bit PCM Samples. It does not support different PCM formats.
|
||||
* Does not support non-WAV audio data (such as AIFF).
|
||||
* Does not support compressed audio data.
|
||||
|
||||
**DrumThumper** now supports different sample rates for the source samples.
|
||||
|
||||
**DrumThumper** now supports mono and stereo sources.
|
||||
|
||||
## DrumThumper project structure
|
||||
### Kotlin App Layer
|
||||
Contains classes for the application logic and defines the methods for accessing the native data and player functionality.
|
||||
|
||||
### Native (C++) layer
|
||||
Contains the implementation of the `native` (JNI) methods defined in the `DrumPlayer` (Kotlin) class.
|
||||
|
||||
### Dependent Libraries
|
||||
* **iolib**
|
||||
Classes for playing audio data.
|
||||
|
||||
* **parselib**
|
||||
Classes for parsing and loading audio data from WAV resources.
|
||||
|
||||
## App
|
||||
* DrumPlayer.kt
|
||||
The Kotlin class which provides the audio playback functionality by interfacing with the native (C++) libraries.
|
||||
|
||||
* DrumThumperActivity.kt
|
||||
The main application logic.
|
||||
|
||||
* TriggerPad.kt
|
||||
An Android View subclass which implements the "trigger pad" UI widgets
|
||||
|
||||
## Native-interface (JNI)
|
||||
* DrumPlayerJNI.cpp
|
||||
This is where all the access to the native functionality is implemented.
|
||||
|
||||
## Screenshots
|
||||

|
52
externals/oboe/samples/drumthumper/build.gradle
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
android {
|
||||
defaultConfig {
|
||||
// Usually the applicationId follows the same scheme as the application package name,
|
||||
// however, this sample will be published on the Google Play Store which will not allow an
|
||||
// applicationId starting with "com.google" as this is reserved for official Google
|
||||
// products. The current owner of the DrumThumper sample apps on Google Play is Paul McLean,
|
||||
// who publishes using the application Id prefix of "com.plausiblesoftware".
|
||||
applicationId "com.plausiblesoftware.drumthumper"
|
||||
minSdkVersion 23
|
||||
compileSdkVersion 35
|
||||
targetSdkVersion 35
|
||||
versionCode 2
|
||||
versionName "1.01"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_18
|
||||
targetCompatibility JavaVersion.VERSION_18
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '18'
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path 'src/main/cpp/CMakeLists.txt'
|
||||
}
|
||||
}
|
||||
|
||||
namespace 'com.plausiblesoftware.drumthumper'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "androidx.core:core-ktx:$core_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
implementation project(path: ':iolib')
|
||||
implementation project(path: ':parselib')
|
||||
}
|
||||
|
BIN
externals/oboe/samples/drumthumper/drumthumper-screenshot.png
vendored
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
externals/oboe/samples/drumthumper/playstore/DrumSetFeatureImage.png
vendored
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
externals/oboe/samples/drumthumper/playstore/ScreenShotPhone.png
vendored
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
externals/oboe/samples/drumthumper/playstore/ScreenShotWithMix.png
vendored
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
externals/oboe/samples/drumthumper/playstore/drumset.jpg
vendored
Normal file
After Width: | Height: | Size: 33 KiB |
21
externals/oboe/samples/drumthumper/src/main/AndroidManifest.xml
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name="com.plausiblesoftware.drumthumper.DrumThumperActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
externals/oboe/samples/drumthumper/src/main/assets/CrashCymbal.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/HiHat_Closed.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/HiHat_Open.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/KickDrum.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/LowTom.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/MidTom.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/RideCymbal.wav
vendored
Normal file
BIN
externals/oboe/samples/drumthumper/src/main/assets/SnareDrum.wav
vendored
Normal file
74
externals/oboe/samples/drumthumper/src/main/cpp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
# Copyright 2019 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
# Pull in parselib
|
||||
set (PARSELIB_DIR ../../../../parselib)
|
||||
#message("PARSELIB_DIR = " + ${PARSELIB_DIR})
|
||||
|
||||
# Pull in iolib
|
||||
set (IOLIB_DIR ../../../../iolib)
|
||||
#message("IOLIB_DIR = " + ${IOLIB_DIR})
|
||||
|
||||
# Set the path to the Oboe library directory
|
||||
set (OBOE_DIR ../../../../../)
|
||||
#message("OBOE_DIR = " + ${OBOE_DIR})
|
||||
|
||||
add_subdirectory(${OBOE_DIR} ./oboe-bin)
|
||||
|
||||
# include folders
|
||||
include_directories(
|
||||
${OBOE_DIR}/include
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
include(${PARSELIB_DIR}/src/main/cpp/CMakeLists.txt)
|
||||
include(${IOLIB_DIR}/src/main/cpp/CMakeLists.txt)
|
||||
|
||||
# Include the WavLib headers and shared sample code
|
||||
include_directories(
|
||||
${PARSELIB_DIR}/src/main/cpp
|
||||
${IOLIB_DIR}/src/main/cpp)
|
||||
|
||||
# App specific sources
|
||||
set (APP_SOURCES
|
||||
DrumPlayerJNI.cpp
|
||||
)
|
||||
|
||||
# Build the drumthumper (native) library
|
||||
add_library(drumthumper SHARED
|
||||
${APP_SOURCES}
|
||||
)
|
||||
|
||||
# Enable optimization flags: if having problems with source level debugging,
|
||||
# disable -Ofast ( and debug ), re-enable after done debugging.
|
||||
target_compile_options(drumthumper PRIVATE -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
|
||||
|
||||
target_link_libraries( # Specifies the target library.
|
||||
drumthumper
|
||||
|
||||
-Wl,--whole-archive
|
||||
iolib
|
||||
parselib
|
||||
-Wl,--no-whole-archive
|
||||
|
||||
oboe
|
||||
|
||||
# Links the target library to the log library
|
||||
# included in the NDK.
|
||||
log)
|
||||
target_link_options(drumthumper PRIVATE "-Wl,-z,max-page-size=16384")
|
172
externals/oboe/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
vendored
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
// parselib includes
|
||||
#include <stream/MemInputStream.h>
|
||||
#include <wav/WavStreamReader.h>
|
||||
|
||||
#include <player/OneShotSampleSource.h>
|
||||
#include <player/SimpleMultiPlayer.h>
|
||||
|
||||
static const char* TAG = "DrumPlayerJNI";
|
||||
|
||||
// JNI functions are "C" calling convention
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
using namespace iolib;
|
||||
using namespace parselib;
|
||||
|
||||
static SimpleMultiPlayer sDTPlayer;
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.setupAudioStreamNative()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_setupAudioStreamNative(
|
||||
JNIEnv* env, jobject, jint numChannels) {
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "%s", "init()");
|
||||
sDTPlayer.setupAudioStream(numChannels);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_plausiblesoftware_drumthumper_DrumPlayer_startAudioStreamNative(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
sDTPlayer.startStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.teardownAudioStreamNative()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_teardownAudioStreamNative(JNIEnv* , jobject) {
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "%s", "deinit()");
|
||||
|
||||
// we know in this case that the sample buffers are all 1-channel, 44.1K
|
||||
sDTPlayer.teardownAudioStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.allocSampleDataNative()
|
||||
*/
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.loadWavAssetNative()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_loadWavAssetNative(
|
||||
JNIEnv* env, jobject, jbyteArray bytearray, jint index, jfloat pan) {
|
||||
int len = env->GetArrayLength (bytearray);
|
||||
|
||||
unsigned char* buf = new unsigned char[len];
|
||||
env->GetByteArrayRegion (bytearray, 0, len, reinterpret_cast<jbyte*>(buf));
|
||||
|
||||
MemInputStream stream(buf, len);
|
||||
|
||||
WavStreamReader reader(&stream);
|
||||
reader.parse();
|
||||
|
||||
reader.getNumChannels();
|
||||
|
||||
SampleBuffer* sampleBuffer = new SampleBuffer();
|
||||
sampleBuffer->loadSampleData(&reader);
|
||||
|
||||
OneShotSampleSource* source = new OneShotSampleSource(sampleBuffer, pan);
|
||||
sDTPlayer.addSampleSource(source, sampleBuffer);
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.unloadWavAssetsNative()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_unloadWavAssetsNative(JNIEnv* env, jobject) {
|
||||
sDTPlayer.unloadSampleData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.trigger()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_trigger(JNIEnv* env, jobject, jint index) {
|
||||
sDTPlayer.triggerDown(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.trigger()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_stopTrigger(JNIEnv* env, jobject, jint index) {
|
||||
sDTPlayer.triggerUp(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.getOutputReset()
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_getOutputReset(JNIEnv*, jobject) {
|
||||
return sDTPlayer.getOutputReset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.clearOutputReset()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_clearOutputReset(JNIEnv*, jobject) {
|
||||
sDTPlayer.clearOutputReset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Native (JNI) implementation of DrumPlayer.restartStream()
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_restartStream(JNIEnv*, jobject) {
|
||||
sDTPlayer.resetAll();
|
||||
if (sDTPlayer.openStream() && sDTPlayer.startStream()){
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "openStream successful");
|
||||
} else {
|
||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "openStream failed");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_setPan(
|
||||
JNIEnv *env, jobject thiz, jint index, jfloat pan) {
|
||||
sDTPlayer.setPan(index, pan);
|
||||
}
|
||||
|
||||
JNIEXPORT jfloat JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_getPan(
|
||||
JNIEnv *env, jobject thiz, jint index) {
|
||||
return sDTPlayer.getPan(index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_setGain(
|
||||
JNIEnv *env, jobject thiz, jint index, jfloat gain) {
|
||||
sDTPlayer.setGain(index, gain);
|
||||
}
|
||||
|
||||
JNIEXPORT jfloat JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_getGain(
|
||||
JNIEnv *env, jobject thiz, jint index) {
|
||||
return sDTPlayer.getGain(index);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_setLoopMode(
|
||||
JNIEnv *env, jobject thiz, jint index, jboolean isLoopMode) {
|
||||
sDTPlayer.setLoopMode(index, isLoopMode);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
116
externals/oboe/samples/drumthumper/src/main/kotlin/com/plausibleaudio/drumthumper/DrumPlayer.kt
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.plausiblesoftware.drumthumper
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import android.util.Log
|
||||
import java.io.IOException
|
||||
|
||||
class DrumPlayer {
|
||||
companion object {
|
||||
// Sample attributes
|
||||
val NUM_PLAY_CHANNELS: Int = 2 // The number of channels in the player Stream.
|
||||
// Stereo Playback, set to 1 for Mono playback
|
||||
|
||||
// Sample Buffer IDs
|
||||
val BASSDRUM: Int = 0
|
||||
val SNAREDRUM: Int = 1
|
||||
val CRASHCYMBAL: Int = 2
|
||||
val RIDECYMBAL: Int = 3
|
||||
val MIDTOM: Int = 4
|
||||
val LOWTOM: Int = 5
|
||||
val HIHATOPEN: Int = 6
|
||||
val HIHATCLOSED: Int = 7
|
||||
|
||||
// initial pan position for each drum sample
|
||||
val PAN_BASSDRUM: Float = 0f // Dead Center
|
||||
val PAN_SNAREDRUM: Float = -0.75f // Mostly Left
|
||||
val PAN_CRASHCYMBAL: Float = -0.75f // Mostly Left
|
||||
val PAN_RIDECYMBAL: Float = 1.0f // Hard Right
|
||||
val PAN_MIDTOM: Float = 0.25f // A little Right
|
||||
val PAN_LOWTOM: Float = 0.75f // Mostly Right
|
||||
val PAN_HIHATOPEN: Float = -1.0f // Hard Left
|
||||
val PAN_HIHATCLOSED: Float = -1.0f // Hard Left
|
||||
|
||||
// Logging Tag
|
||||
val TAG: String = "DrumPlayer"
|
||||
}
|
||||
|
||||
fun setupAudioStream() {
|
||||
setupAudioStreamNative(NUM_PLAY_CHANNELS)
|
||||
}
|
||||
|
||||
fun startAudioStream() {
|
||||
startAudioStreamNative()
|
||||
}
|
||||
|
||||
fun teardownAudioStream() {
|
||||
teardownAudioStreamNative()
|
||||
}
|
||||
|
||||
// asset-based samples
|
||||
fun loadWavAssets(assetMgr: AssetManager) {
|
||||
loadWavAsset(assetMgr, "KickDrum.wav", BASSDRUM, PAN_BASSDRUM)
|
||||
loadWavAsset(assetMgr, "SnareDrum.wav", SNAREDRUM, PAN_SNAREDRUM)
|
||||
loadWavAsset(assetMgr, "CrashCymbal.wav", CRASHCYMBAL, PAN_CRASHCYMBAL)
|
||||
loadWavAsset(assetMgr, "RideCymbal.wav", RIDECYMBAL, PAN_RIDECYMBAL)
|
||||
loadWavAsset(assetMgr, "MidTom.wav", MIDTOM, PAN_MIDTOM)
|
||||
loadWavAsset(assetMgr, "LowTom.wav", LOWTOM, PAN_LOWTOM)
|
||||
loadWavAsset(assetMgr, "HiHat_Open.wav", HIHATOPEN, PAN_HIHATOPEN)
|
||||
loadWavAsset(assetMgr, "HiHat_Closed.wav", HIHATCLOSED, PAN_HIHATCLOSED)
|
||||
}
|
||||
|
||||
fun unloadWavAssets() {
|
||||
unloadWavAssetsNative()
|
||||
}
|
||||
|
||||
private fun loadWavAsset(assetMgr: AssetManager, assetName: String, index: Int, pan: Float) {
|
||||
try {
|
||||
val assetFD = assetMgr.openFd(assetName)
|
||||
val dataStream = assetFD.createInputStream()
|
||||
val dataLen = assetFD.getLength().toInt()
|
||||
val dataBytes = ByteArray(dataLen)
|
||||
dataStream.read(dataBytes, 0, dataLen)
|
||||
loadWavAssetNative(dataBytes, index, pan)
|
||||
assetFD.close()
|
||||
} catch (ex: IOException) {
|
||||
Log.i(TAG, "IOException$ex")
|
||||
}
|
||||
}
|
||||
|
||||
private external fun setupAudioStreamNative(numChannels: Int)
|
||||
private external fun startAudioStreamNative()
|
||||
private external fun teardownAudioStreamNative()
|
||||
|
||||
private external fun loadWavAssetNative(wavBytes: ByteArray, index: Int, pan: Float)
|
||||
private external fun unloadWavAssetsNative()
|
||||
|
||||
external fun trigger(drumIndex: Int)
|
||||
external fun stopTrigger(drumIndex: Int)
|
||||
|
||||
external fun setPan(index: Int, pan: Float)
|
||||
external fun getPan(index: Int): Float
|
||||
|
||||
external fun setGain(index: Int, gain: Float)
|
||||
external fun getGain(index: Int): Float
|
||||
|
||||
external fun setLoopMode(index: Int, isLoopMode: Boolean)
|
||||
|
||||
external fun getOutputReset() : Boolean
|
||||
external fun clearOutputReset()
|
||||
|
||||
external fun restartStream()
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* Copyright 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.plausiblesoftware.drumthumper
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.SeekBar
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Timer
|
||||
import kotlin.concurrent.schedule
|
||||
|
||||
class DrumThumperActivity : AppCompatActivity(),
|
||||
TriggerPad.DrumPadTriggerListener,
|
||||
SeekBar.OnSeekBarChangeListener,
|
||||
View.OnClickListener {
|
||||
private val TAG = "DrumThumperActivity"
|
||||
|
||||
private var mAudioMgr: AudioManager? = null
|
||||
|
||||
private var mDrumPlayer = DrumPlayer()
|
||||
|
||||
private val mUseDeviceChangeFallback = false
|
||||
private val mSwitchTimerMs = 500L
|
||||
|
||||
private var mDevicesInitialized = false
|
||||
|
||||
private var mDeviceListener: DeviceListener = DeviceListener()
|
||||
|
||||
private var mMixControlsShowing = false
|
||||
|
||||
// Store the loop mode states for each drum
|
||||
private val mLoopModes = mutableMapOf(
|
||||
DrumPlayer.BASSDRUM to false,
|
||||
DrumPlayer.SNAREDRUM to false,
|
||||
DrumPlayer.CRASHCYMBAL to false,
|
||||
DrumPlayer.RIDECYMBAL to false,
|
||||
DrumPlayer.MIDTOM to false,
|
||||
DrumPlayer.LOWTOM to false,
|
||||
DrumPlayer.HIHATOPEN to false,
|
||||
DrumPlayer.HIHATCLOSED to false
|
||||
)
|
||||
|
||||
// Store the button references
|
||||
private val mLoopButtons = mutableMapOf<Int, Button>()
|
||||
|
||||
init {
|
||||
// Load the library containing the a native code including the JNI functions
|
||||
System.loadLibrary("drumthumper")
|
||||
}
|
||||
|
||||
inner class DeviceListener: AudioDeviceCallback() {
|
||||
private fun logDevices(label: String, devices: Array<AudioDeviceInfo> ) {
|
||||
Log.i(TAG, label + " " + devices.size)
|
||||
for(device in devices) {
|
||||
Log.i(TAG, " " + device.getProductName().toString()
|
||||
+ " type:" + device.getType()
|
||||
+ " source:" + device.isSource()
|
||||
+ " sink:" + device.isSink())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo> ) {
|
||||
// Note: This will get called when the callback is installed.
|
||||
if (mDevicesInitialized) {
|
||||
logDevices("onAudioDevicesAdded", addedDevices)
|
||||
// This is not the initial callback, so devices have changed
|
||||
Toast.makeText(applicationContext, "Added Device", Toast.LENGTH_LONG).show()
|
||||
resetOutput()
|
||||
}
|
||||
mDevicesInitialized = true
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo> ) {
|
||||
logDevices("onAudioDevicesRemoved", removedDevices)
|
||||
Toast.makeText(applicationContext, "Removed Device", Toast.LENGTH_LONG).show()
|
||||
resetOutput()
|
||||
}
|
||||
|
||||
private fun resetOutput() {
|
||||
Log.i(TAG, "resetOutput() time:" + LocalDateTime.now() + " native reset:" + mDrumPlayer.getOutputReset())
|
||||
if (mDrumPlayer.getOutputReset()) {
|
||||
// the (native) stream has been reset by the onErrorAfterClose() callback
|
||||
mDrumPlayer.clearOutputReset()
|
||||
} else {
|
||||
// give the (native) stream a chance to close it.
|
||||
val timer = Timer("stream restart timer time:" + LocalDateTime.now(),
|
||||
false)
|
||||
// schedule a single event
|
||||
timer.schedule(mSwitchTimerMs) {
|
||||
if (!mDrumPlayer.getOutputReset()) {
|
||||
// still didn't get reset, so lets do it ourselves
|
||||
Log.i(TAG, "restartStream() time:" + LocalDateTime.now())
|
||||
mDrumPlayer.restartStream()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// UI Helpers
|
||||
//
|
||||
val GAIN_FACTOR = 100.0f
|
||||
val MAX_PAN_POSITION = 200.0f
|
||||
val HALF_PAN_POSITION = MAX_PAN_POSITION / 2.0f
|
||||
|
||||
private fun gainPosToGainVal(pos: Int) : Float {
|
||||
// map 0 -> 200 to 0.0f -> 2.0f
|
||||
return pos.toFloat() / GAIN_FACTOR
|
||||
}
|
||||
|
||||
private fun gainValToGainPos(value: Float) : Int {
|
||||
return (value * GAIN_FACTOR).toInt()
|
||||
}
|
||||
|
||||
private fun panPosToPanVal(pos: Int) : Float {
|
||||
// map 0 -> 200 to -1.0f -> 1..0f
|
||||
return (pos.toFloat() - HALF_PAN_POSITION) / HALF_PAN_POSITION
|
||||
}
|
||||
|
||||
private fun panValToPanPos(value: Float) : Int {
|
||||
// map -1.0f -> 1.0f to 0 -> 200
|
||||
return ((value * HALF_PAN_POSITION) + HALF_PAN_POSITION).toInt()
|
||||
}
|
||||
|
||||
private fun showMixControls(show : Boolean) {
|
||||
mMixControlsShowing = show
|
||||
val showFlag = if (mMixControlsShowing) View.VISIBLE else View.GONE
|
||||
findViewById<LinearLayout>(R.id.kickMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.snareMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.hihatOpenMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.hihatClosedMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.midTomMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.lowTomMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.rideMixControls).setVisibility(showFlag)
|
||||
findViewById<LinearLayout>(R.id.crashMixControls).setVisibility(showFlag)
|
||||
|
||||
findViewById<Button>(R.id.mixCtrlBtn).text =
|
||||
if (mMixControlsShowing) "Hide Mix Controls" else "Show Mix Controls"
|
||||
}
|
||||
|
||||
private fun connectMixSliders(panSliderId : Int, gainSliderId : Int, drumIndex : Int) {
|
||||
val panSeekbar = findViewById<SeekBar>(panSliderId)
|
||||
panSeekbar.setOnSeekBarChangeListener(this)
|
||||
panSeekbar.progress = panValToPanPos(mDrumPlayer.getPan(drumIndex))
|
||||
|
||||
val gainSeekbar = findViewById<SeekBar>(gainSliderId)
|
||||
gainSeekbar.setOnSeekBarChangeListener(this)
|
||||
gainSeekbar.progress = gainValToGainPos(mDrumPlayer.getGain(drumIndex))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mAudioMgr = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
mDrumPlayer.setupAudioStream()
|
||||
|
||||
mDrumPlayer.loadWavAssets(getAssets())
|
||||
|
||||
mDrumPlayer.startAudioStream()
|
||||
|
||||
if (mUseDeviceChangeFallback) {
|
||||
mAudioMgr!!.registerAudioDeviceCallback(mDeviceListener, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
// UI
|
||||
setContentView(R.layout.drumthumper_activity)
|
||||
|
||||
// "Kick" drum
|
||||
findViewById<TriggerPad>(R.id.kickPad).addListener(this)
|
||||
connectMixSliders(R.id.kickPan, R.id.kickGain, DrumPlayer.BASSDRUM)
|
||||
mLoopButtons[DrumPlayer.BASSDRUM] = findViewById(R.id.kickLoopBtn)
|
||||
mLoopButtons[DrumPlayer.BASSDRUM]?.setOnClickListener(this)
|
||||
|
||||
// Snare drum
|
||||
findViewById<TriggerPad>(R.id.snarePad).addListener(this)
|
||||
connectMixSliders(R.id.snarePan, R.id.snareGain, DrumPlayer.SNAREDRUM)
|
||||
mLoopButtons[DrumPlayer.SNAREDRUM] = findViewById(R.id.snareLoopBtn)
|
||||
mLoopButtons[DrumPlayer.SNAREDRUM]?.setOnClickListener(this)
|
||||
|
||||
// Mid tom
|
||||
findViewById<TriggerPad>(R.id.midTomPad).addListener(this)
|
||||
connectMixSliders(R.id.midTomPan, R.id.midTomGain, DrumPlayer.MIDTOM)
|
||||
mLoopButtons[DrumPlayer.MIDTOM] = findViewById(R.id.midTomLoopBtn)
|
||||
mLoopButtons[DrumPlayer.MIDTOM]?.setOnClickListener(this)
|
||||
|
||||
// Low tom
|
||||
findViewById<TriggerPad>(R.id.lowTomPad).addListener(this)
|
||||
connectMixSliders(R.id.lowTomPan, R.id.lowTomGain, DrumPlayer.LOWTOM)
|
||||
mLoopButtons[DrumPlayer.LOWTOM] = findViewById(R.id.lowTomLoopBtn)
|
||||
mLoopButtons[DrumPlayer.LOWTOM]?.setOnClickListener(this)
|
||||
|
||||
// Open hihat
|
||||
findViewById<TriggerPad>(R.id.hihatOpenPad).addListener(this)
|
||||
connectMixSliders(R.id.hihatOpenPan, R.id.hihatOpenGain, DrumPlayer.HIHATOPEN)
|
||||
mLoopButtons[DrumPlayer.HIHATOPEN] = findViewById(R.id.hihatOpenLoopBtn)
|
||||
mLoopButtons[DrumPlayer.HIHATOPEN]?.setOnClickListener(this)
|
||||
|
||||
// Closed hihat
|
||||
findViewById<TriggerPad>(R.id.hihatClosedPad).addListener(this)
|
||||
connectMixSliders(R.id.hihatClosedPan, R.id.hihatClosedGain, DrumPlayer.HIHATCLOSED)
|
||||
mLoopButtons[DrumPlayer.HIHATCLOSED] = findViewById(R.id.hihatClosedLoopBtn)
|
||||
mLoopButtons[DrumPlayer.HIHATCLOSED]?.setOnClickListener(this)
|
||||
|
||||
// Ride cymbal
|
||||
findViewById<TriggerPad>(R.id.ridePad).addListener(this)
|
||||
connectMixSliders(R.id.ridePan, R.id.rideGain, DrumPlayer.RIDECYMBAL)
|
||||
mLoopButtons[DrumPlayer.RIDECYMBAL] = findViewById(R.id.rideLoopBtn)
|
||||
mLoopButtons[DrumPlayer.RIDECYMBAL]?.setOnClickListener(this)
|
||||
|
||||
// Crash cymbal
|
||||
findViewById<TriggerPad>(R.id.crashPad).addListener(this)
|
||||
connectMixSliders(R.id.crashPan, R.id.crashGain, DrumPlayer.CRASHCYMBAL)
|
||||
mLoopButtons[DrumPlayer.CRASHCYMBAL] = findViewById(R.id.crashLoopBtn)
|
||||
mLoopButtons[DrumPlayer.CRASHCYMBAL]?.setOnClickListener(this)
|
||||
|
||||
findViewById<Button>(R.id.mixCtrlBtn).setOnClickListener(this)
|
||||
showMixControls(false)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
if (mUseDeviceChangeFallback) {
|
||||
mAudioMgr!!.unregisterAudioDeviceCallback(mDeviceListener)
|
||||
}
|
||||
|
||||
mDrumPlayer.teardownAudioStream()
|
||||
|
||||
mDrumPlayer.unloadWavAssets()
|
||||
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
//
|
||||
// DrumPad.DrumPadTriggerListener
|
||||
//
|
||||
override fun triggerDown(pad: TriggerPad) {
|
||||
// trigger the sound based on the pad
|
||||
when (pad.id) {
|
||||
R.id.kickPad -> mDrumPlayer.trigger(DrumPlayer.BASSDRUM)
|
||||
R.id.snarePad -> mDrumPlayer.trigger(DrumPlayer.SNAREDRUM)
|
||||
R.id.midTomPad -> mDrumPlayer.trigger(DrumPlayer.MIDTOM)
|
||||
R.id.lowTomPad -> mDrumPlayer.trigger(DrumPlayer.LOWTOM)
|
||||
R.id.hihatOpenPad -> {
|
||||
mDrumPlayer.trigger(DrumPlayer.HIHATOPEN)
|
||||
// For a real drum set, hi-hat can play either the open or the closed sound at any
|
||||
// given time.
|
||||
mDrumPlayer.stopTrigger(DrumPlayer.HIHATCLOSED)
|
||||
}
|
||||
R.id.hihatClosedPad -> {
|
||||
mDrumPlayer.trigger(DrumPlayer.HIHATCLOSED)
|
||||
// For a real drum set, hi-hat can play either the open or the closed sound at any
|
||||
// given time.
|
||||
mDrumPlayer.stopTrigger(DrumPlayer.HIHATOPEN)
|
||||
}
|
||||
R.id.ridePad -> mDrumPlayer.trigger(DrumPlayer.RIDECYMBAL)
|
||||
R.id.crashPad -> mDrumPlayer.trigger(DrumPlayer.CRASHCYMBAL)
|
||||
}
|
||||
}
|
||||
|
||||
override fun triggerUp(pad: TriggerPad) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
//
|
||||
// SeekBar.OnSeekBarChangeListener
|
||||
//
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
when (seekBar!!.id) {
|
||||
// BASSDRUM
|
||||
R.id.kickGain -> mDrumPlayer.setGain(DrumPlayer.BASSDRUM, gainPosToGainVal(progress))
|
||||
R.id.kickPan -> mDrumPlayer.setPan(DrumPlayer.BASSDRUM, panPosToPanVal(progress))
|
||||
|
||||
// SNAREDRUM
|
||||
R.id.snareGain -> mDrumPlayer.setGain(DrumPlayer.SNAREDRUM, gainPosToGainVal(progress))
|
||||
R.id.snarePan -> mDrumPlayer.setPan(DrumPlayer.SNAREDRUM, panPosToPanVal(progress))
|
||||
|
||||
// MIDTOM
|
||||
R.id.midTomGain -> mDrumPlayer.setGain(DrumPlayer.MIDTOM, gainPosToGainVal(progress))
|
||||
R.id.midTomPan -> mDrumPlayer.setPan(DrumPlayer.MIDTOM, panPosToPanVal(progress))
|
||||
|
||||
// LOWTOM
|
||||
R.id.lowTomGain -> mDrumPlayer.setGain(DrumPlayer.LOWTOM, gainPosToGainVal(progress))
|
||||
R.id.lowTomPan -> mDrumPlayer.setPan(DrumPlayer.LOWTOM, panPosToPanVal(progress))
|
||||
|
||||
// HIHATOPEN
|
||||
R.id.hihatOpenGain -> mDrumPlayer.setGain(DrumPlayer.HIHATOPEN, gainPosToGainVal(progress))
|
||||
R.id.hihatOpenPan -> mDrumPlayer.setPan(DrumPlayer.HIHATOPEN, panPosToPanVal(progress))
|
||||
|
||||
// HIHATCLOSED
|
||||
R.id.hihatClosedGain -> mDrumPlayer.setGain(DrumPlayer.HIHATCLOSED, gainPosToGainVal(progress))
|
||||
R.id.hihatClosedPan -> mDrumPlayer.setPan(DrumPlayer.HIHATCLOSED, panPosToPanVal(progress))
|
||||
|
||||
// RIDECYMBAL
|
||||
R.id.rideGain -> mDrumPlayer.setGain(DrumPlayer.RIDECYMBAL, gainPosToGainVal(progress))
|
||||
R.id.ridePan -> mDrumPlayer.setPan(DrumPlayer.RIDECYMBAL, panPosToPanVal(progress))
|
||||
|
||||
// CRASHCYMBAL
|
||||
R.id.crashGain -> mDrumPlayer.setGain(DrumPlayer.CRASHCYMBAL, gainPosToGainVal(progress))
|
||||
R.id.crashPan -> mDrumPlayer.setPan(DrumPlayer.CRASHCYMBAL, panPosToPanVal(progress))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar?) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar?) {
|
||||
// NOP
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
when (v?.id) {
|
||||
R.id.mixCtrlBtn -> showMixControls(!mMixControlsShowing)
|
||||
R.id.kickLoopBtn -> handleLoopButtonClick(DrumPlayer.BASSDRUM)
|
||||
R.id.snareLoopBtn -> handleLoopButtonClick(DrumPlayer.SNAREDRUM)
|
||||
R.id.midTomLoopBtn -> handleLoopButtonClick(DrumPlayer.MIDTOM)
|
||||
R.id.lowTomLoopBtn -> handleLoopButtonClick(DrumPlayer.LOWTOM)
|
||||
R.id.hihatOpenLoopBtn -> handleLoopButtonClick(DrumPlayer.HIHATOPEN)
|
||||
R.id.hihatClosedLoopBtn -> handleLoopButtonClick(DrumPlayer.HIHATCLOSED)
|
||||
R.id.rideLoopBtn -> handleLoopButtonClick(DrumPlayer.RIDECYMBAL)
|
||||
R.id.crashLoopBtn -> handleLoopButtonClick(DrumPlayer.CRASHCYMBAL)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleLoopButtonClick(drumIndex: Int) {
|
||||
// Toggle the loop mode
|
||||
mLoopModes[drumIndex] = !mLoopModes[drumIndex]!!
|
||||
mDrumPlayer.setLoopMode(drumIndex, mLoopModes[drumIndex]!!)
|
||||
|
||||
// Update the button appearance
|
||||
val button = mLoopButtons[drumIndex]
|
||||
button?.setTextColor(if (mLoopModes[drumIndex]!!) getColor(R.color.red) else getColor(R.color.black))
|
||||
}
|
||||
}
|
205
externals/oboe/samples/drumthumper/src/main/kotlin/com/plausibleaudio/drumthumper/TriggerPad.kt
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.plausiblesoftware.drumthumper
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
|
||||
class TriggerPad: View {
|
||||
|
||||
private val mDrawRect = RectF()
|
||||
private val mPaint = Paint()
|
||||
|
||||
private val mUpColor = Color.LTGRAY
|
||||
private val mDownColor = Color.DKGRAY
|
||||
private var mIsDown = false
|
||||
|
||||
private var mText = "DrumPad"
|
||||
private var mTextSizeSp = 28.0f
|
||||
|
||||
private val mTextColor = Color.BLACK
|
||||
|
||||
val DISPLAY_MASK = 0x00000003
|
||||
val DISPLAY_RECT = 0x00000000
|
||||
val DISPLAY_CIRCLE = 0x00000001
|
||||
val DISPLAY_ROUND_RECT = 0x00000002
|
||||
|
||||
private var mDisplayFlags = DISPLAY_ROUND_RECT
|
||||
|
||||
interface DrumPadTriggerListener {
|
||||
fun triggerDown(pad: TriggerPad)
|
||||
fun triggerUp(pad: TriggerPad)
|
||||
}
|
||||
|
||||
var mListeners = ArrayList<DrumPadTriggerListener>()
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
extractAttributes(attrs)
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyle: Int): super(context, attrs, defStyle) {
|
||||
extractAttributes(attrs)
|
||||
}
|
||||
|
||||
//
|
||||
// Attributes
|
||||
//
|
||||
private fun extractAttributes(attrs: AttributeSet) {
|
||||
val xmlns = "http://schemas.android.com/apk/res/android"
|
||||
val textVal = attrs.getAttributeValue(xmlns, "text")
|
||||
if (textVal != null) {
|
||||
mText = textVal
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Layout Routines
|
||||
//
|
||||
private fun calcTextSizeInPixels(): Float {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
mTextSizeSp,
|
||||
resources.displayMetrics
|
||||
)
|
||||
}
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
val padLeft = paddingLeft
|
||||
val padRight = paddingRight
|
||||
val padTop = paddingTop
|
||||
val padBottom = paddingBottom
|
||||
|
||||
mDrawRect.set(padLeft.toFloat(),
|
||||
padTop.toFloat(),
|
||||
w - padRight.toFloat(),
|
||||
h - padBottom.toFloat())
|
||||
|
||||
// mTextSize = mDrawRect.bottom / 4.0f
|
||||
}
|
||||
|
||||
override fun onMeasure (widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val width = MeasureSpec.getSize(widthMeasureSpec)
|
||||
|
||||
val padTop = paddingTop
|
||||
val padBottom = paddingBottom
|
||||
|
||||
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
|
||||
var height = MeasureSpec.getSize(heightMeasureSpec)
|
||||
|
||||
val textSizePixels = calcTextSizeInPixels()
|
||||
when (heightMode) {
|
||||
MeasureSpec.AT_MOST -> run {
|
||||
// mText = "AT_MOST"
|
||||
val newHeight = (textSizePixels.toInt() * 2) + padTop + padBottom
|
||||
height = minOf(height, newHeight) }
|
||||
|
||||
MeasureSpec.EXACTLY -> run {
|
||||
/*mText = "EXACTLY"*/ }
|
||||
|
||||
MeasureSpec.UNSPECIFIED -> run {
|
||||
// mText = "UNSPECIFIED"
|
||||
height = textSizePixels.toInt() }
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, height)
|
||||
}
|
||||
|
||||
//
|
||||
// Drawing Routines
|
||||
//
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
// Face
|
||||
if (mIsDown) {
|
||||
mPaint.color = mDownColor
|
||||
} else {
|
||||
mPaint.color = mUpColor
|
||||
}
|
||||
|
||||
when (mDisplayFlags and DISPLAY_MASK) {
|
||||
DISPLAY_RECT -> canvas.drawRect(mDrawRect, mPaint)
|
||||
|
||||
DISPLAY_CIRCLE -> run {
|
||||
val midX = mDrawRect.left + mDrawRect.width() / 2.0f
|
||||
val midY = mDrawRect.top + mDrawRect.height() / 2.0f
|
||||
val radius = minOf(mDrawRect.height() / 2.0f, mDrawRect.width() / 2.0f)
|
||||
canvas.drawCircle(midX, midY, radius - 5.0f, mPaint)
|
||||
}
|
||||
|
||||
DISPLAY_ROUND_RECT -> run {
|
||||
val rad = minOf(mDrawRect.width() / 8.0f, mDrawRect.height() / 8.0f)
|
||||
canvas.drawRoundRect(mDrawRect, rad, rad, mPaint)
|
||||
}
|
||||
}
|
||||
|
||||
// Text
|
||||
val midX = mDrawRect.width() / 2
|
||||
mPaint.textSize = calcTextSizeInPixels()
|
||||
val textWidth = mPaint.measureText(mText)
|
||||
mPaint.color = mTextColor
|
||||
val textSizePixels = calcTextSizeInPixels()
|
||||
canvas.drawText(mText, mDrawRect.left + midX - textWidth / 2,
|
||||
mDrawRect.bottom/2 + textSizePixels/2, mPaint)
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Input Routines
|
||||
//
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
if (event.actionMasked == MotionEvent.ACTION_DOWN ||
|
||||
event.actionMasked == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
mIsDown = true
|
||||
triggerDown()
|
||||
invalidate()
|
||||
return true
|
||||
} else if (event.actionMasked == MotionEvent.ACTION_UP) {
|
||||
mIsDown = false
|
||||
triggerUp()
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//
|
||||
// Event Listeners
|
||||
//
|
||||
fun addListener(listener: DrumPadTriggerListener) {
|
||||
mListeners.add(listener)
|
||||
}
|
||||
|
||||
private fun triggerDown() {
|
||||
for( listener in mListeners) {
|
||||
listener.triggerDown(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerUp() {
|
||||
for( listener in mListeners) {
|
||||
listener.triggerUp(this)
|
||||
}
|
||||
}
|
||||
}
|
34
externals/oboe/samples/drumthumper/src/main/res/drawable-v24/_ic_launcher_foreground.xml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
170
externals/oboe/samples/drumthumper/src/main/res/drawable/_ic_launcher_background.xml
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#008577"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
611
externals/oboe/samples/drumthumper/src/main/res/layout-land/drumthumper_activity.xml
vendored
Normal file
|
@ -0,0 +1,611 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
tools:context="com.plausiblesoftware.drumthumper.DrumThumperActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/kickPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Kick" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/kickMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/kickPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/kickGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/kickLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/snarePad"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Snare" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/snareMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/snarePan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/snareGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/snareLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/hihatOpenPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Open Hat" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/hihatOpenMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatOpenPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatOpenGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/hihatOpenLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/hihatClosedPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Closed Hat" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/hihatClosedMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatClosedPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatClosedGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/hihatClosedLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/midTomPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Mid Tom" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/midTomMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/midTomPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/midTomGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/midTomLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/lowTomPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Low Tom" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/lowTomMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/lowTomPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/lowTomGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/lowTomLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/ridePad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Ride" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/rideMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/ridePan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/rideGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/rideLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/crashPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Crash" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/crashMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/crashPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/crashGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/crashLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hide/Show Mix Controls"
|
||||
android:id="@+id/mixCtrlBtn"/>
|
||||
</LinearLayout>
|
623
externals/oboe/samples/drumthumper/src/main/res/layout/drumthumper_activity.xml
vendored
Normal file
|
@ -0,0 +1,623 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
tools:context="com.plausiblesoftware.drumthumper.DrumThumperActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/kickPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Kick" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/kickMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/kickPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/kickGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/kickLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/snarePad"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Snare" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/snareMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/snarePan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/snareGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/snareLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/hihatOpenPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Open Hat" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/hihatOpenMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatOpenPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatOpenGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/hihatOpenLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/hihatClosedPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Closed Hat" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/hihatClosedMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatClosedPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/hihatClosedGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/hihatClosedLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/midTomPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Mid Tom" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/midTomMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/midTomPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/midTomGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/midTomLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/lowTomPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Low Tom" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/lowTomMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/lowTomPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/lowTomGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/lowTomLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/ridePad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Ride" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/rideMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/ridePan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/rideGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/rideLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="128dp"
|
||||
android:layout_weight=".5"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.plausiblesoftware.drumthumper.TriggerPad
|
||||
android:id="@+id/crashPad"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:padding="5dp"
|
||||
android:text="Crash" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/crashMixControls">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="P:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/crashPan"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="G:"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/crashGain"
|
||||
style="@android:style/Widget.DeviceDefault.SeekBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:max="200" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/crashLoopBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="5dp"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="Loop"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginStart="60dp"
|
||||
android:layout_marginEnd="60dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hide/Show Mix Controls"
|
||||
android:id="@+id/mixCtrlBtn"/>
|
||||
</LinearLayout>
|
5
externals/oboe/samples/drumthumper/src/main/res/mipmap-anydpi-v26/_ic_launcher.xml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/_ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/_ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
5
externals/oboe/samples/drumthumper/src/main/res/mipmap-anydpi-v26/_ic_launcher_round.xml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/_ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/_ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-hdpi/ic_launcher.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-hdpi/ic_launcher_round.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-mdpi/ic_launcher.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-mdpi/ic_launcher_round.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-xhdpi/ic_launcher.png
vendored
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-xhdpi/ic_launcher_round.png
vendored
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-xxhdpi/ic_launcher.png
vendored
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
vendored
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-xxxhdpi/ic_launcher.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
externals/oboe/samples/drumthumper/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
8
externals/oboe/samples/drumthumper/src/main/res/values/colors.xml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="red">#BB0000</color>
|
||||
</resources>
|
3
externals/oboe/samples/drumthumper/src/main/res/values/strings.xml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">DrumThumper</string>
|
||||
</resources>
|
11
externals/oboe/samples/drumthumper/src/main/res/values/styles.xml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|