├── .github
└── workflows
│ └── android.yml
├── .gitignore
├── .gitmodules
├── CircleOfFifths
├── AndroidManifest.xml
├── LICENSE.txt
├── build.gradle
├── misc
│ ├── Makefile
│ ├── a.svg
│ ├── ab.svg
│ ├── android.svg
│ ├── android_guitar.png
│ ├── android_guitar.svg
│ ├── b.svg
│ ├── bb.svg
│ ├── c.svg
│ ├── d.svg
│ ├── db.svg
│ ├── e.svg
│ ├── eb.svg
│ ├── f.svg
│ ├── fs.svg
│ ├── g.svg
│ ├── guitar.png
│ └── guitar.svg
├── res
│ ├── drawable
│ │ ├── background.png
│ │ ├── btn_normal.9.png
│ │ ├── btn_selected.9.png
│ │ ├── icon.png
│ │ ├── ks00.png
│ │ ├── ks01.png
│ │ ├── ks02.png
│ │ ├── ks03.png
│ │ ├── ks04.png
│ │ ├── ks05.png
│ │ ├── ks06.png
│ │ ├── ks07.png
│ │ ├── ks08.png
│ │ ├── ks09.png
│ │ ├── ks10.png
│ │ ├── ks11.png
│ │ └── radiobuttons.xml
│ ├── layout
│ │ └── main.xml
│ ├── menu
│ │ └── circle_menu.xml
│ ├── raw
│ │ └── patch.zip
│ └── values
│ │ └── strings.xml
└── src
│ └── org
│ └── puredata
│ └── android
│ └── fifths
│ ├── CircleOfFifths.java
│ └── CircleView.java
├── PdCore
├── AndroidManifest.xml
├── LICENSE.txt
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── puredata
│ │ └── android
│ │ ├── io
│ │ ├── AudioFormatUtil.java
│ │ ├── AudioParameters.java
│ │ ├── AudioRecordWrapper.java
│ │ ├── AudioWrapper.java
│ │ └── PdAudio.java
│ │ ├── midi
│ │ ├── MidiToPdAdapter.java
│ │ └── PdToMidiAdapter.java
│ │ ├── service
│ │ ├── PdPreferences.java
│ │ └── PdService.java
│ │ └── utils
│ │ ├── PdUiDispatcher.java
│ │ └── Properties.java
│ ├── jni
│ ├── Android.mk
│ └── Application.mk
│ └── res
│ ├── drawable
│ └── icon.png
│ ├── raw
│ ├── extra_abs.zip
│ └── silence.wav
│ ├── values
│ ├── audio.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── preferences.xml
├── PdTest
├── AndroidManifest.xml
├── LICENSE.txt
├── build.gradle
├── jni
│ ├── Android.mk
│ ├── Application.mk
│ └── helloworld.c
├── proguard-rules.pro
├── res
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-ldpi
│ │ └── icon.png
│ ├── drawable-mdpi
│ │ └── icon.png
│ ├── layout
│ │ └── main.xml
│ ├── menu
│ │ └── pd_test_menu.xml
│ ├── raw
│ │ └── test.pd
│ └── values
│ │ └── strings.xml
└── src
│ └── org
│ └── puredata
│ └── android
│ └── test
│ └── PdTest.java
├── README.md
├── ScenePlayer
├── AndroidManifest.xml
├── LICENSE.txt
├── build.gradle
├── jni
│ ├── Android.mk
│ ├── Application.mk
│ ├── rj_accum.c
│ ├── rj_barkflux_accum~.c
│ ├── rj_centroid~.c
│ ├── rj_senergy~.c
│ └── rj_zcr~.c
├── res
│ ├── drawable
│ │ ├── all_transparent.9.png
│ │ ├── default_thumb.jpg
│ │ ├── divider_horizontal_dark.xml
│ │ ├── file.png
│ │ ├── folder.png
│ │ ├── info_button.xml
│ │ ├── mic_icon.png
│ │ ├── notification_icon.png
│ │ ├── play_button.xml
│ │ ├── popup_custom.9.png
│ │ ├── record_button.xml
│ │ ├── sceneplayer.png
│ │ ├── sceneplayer_notify.png
│ │ ├── tab_recordings_dark.png
│ │ ├── tab_recordings_light.png
│ │ ├── tab_recordings_selector.xml
│ │ ├── tab_rjdj_me_dark.png
│ │ ├── tab_rjdj_me_light.png
│ │ ├── tab_rjdj_me_selector.xml
│ │ ├── tab_scenes_dark.png
│ │ ├── tab_scenes_light.png
│ │ ├── tab_scenes_selector.xml
│ │ ├── transport_edit_description.png
│ │ ├── transport_goto_scene.png
│ │ ├── transport_list.png
│ │ ├── transport_list_pressed.png
│ │ ├── transport_pause.png
│ │ ├── transport_pause_pressed.png
│ │ ├── transport_play.png
│ │ ├── transport_play_pressed.png
│ │ ├── transport_record.png
│ │ ├── transport_record_active.png
│ │ ├── transport_record_active_pressed.png
│ │ ├── transport_record_pressed.png
│ │ ├── white_gradient_bottom.9.png
│ │ └── white_gradient_top.9.png
│ ├── layout
│ │ ├── file_dialog_main.xml
│ │ ├── file_dialog_row.xml
│ │ ├── recording_item.xml
│ │ ├── recording_player.xml
│ │ ├── recording_selection.xml
│ │ ├── scene_player.xml
│ │ ├── scene_selection.xml
│ │ ├── tab_layout.xml
│ │ ├── two_line_dialog_title.xml
│ │ └── two_line_list_item.xml
│ ├── menu
│ │ └── selection_menu.xml
│ ├── raw
│ │ ├── abstractions.zip
│ │ └── atsuke.zip
│ └── values
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ ├── com
│ └── lamerman
│ │ └── FileDialog.java
│ └── org
│ └── puredata
│ └── android
│ └── scenes
│ ├── ImageOverlay.java
│ ├── Overlay.java
│ ├── RecordingListCursorAdapter.java
│ ├── RecordingPlayer.java
│ ├── RecordingSelection.java
│ ├── SceneDataBase.java
│ ├── SceneListCursorAdapter.java
│ ├── ScenePlayer.java
│ ├── SceneSelection.java
│ ├── SceneTabs.java
│ ├── SceneView.java
│ ├── TextOverlay.java
│ └── VersionedTouch.java
├── Voice-O-Rama
├── AndroidManifest.xml
├── LICENSE.txt
├── build.gradle
├── res
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-ldpi
│ │ └── icon.png
│ ├── drawable-mdpi
│ │ └── icon.png
│ ├── layout-land
│ │ └── main.xml
│ ├── layout
│ │ └── main.xml
│ ├── menu
│ │ └── pd_test_menu.xml
│ ├── raw
│ │ └── test.pd
│ └── values
│ │ └── strings.xml
└── src
│ └── at
│ └── or
│ └── at
│ └── voiceorama
│ ├── VersionedTouch.java
│ └── VoiceORama.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | paths-ignore:
8 | - '**/README.md'
9 | pull_request:
10 | branches:
11 | - master
12 |
13 | jobs:
14 | build:
15 |
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - uses: actions/checkout@v3
20 | - name: Set up JDK 17
21 | uses: actions/setup-java@v3
22 | with:
23 | java-version: '17'
24 | distribution: 'adopt'
25 | - run: |
26 | git submodule sync --recursive
27 | git submodule update --init --recursive
28 | - run: ./gradlew androidDependencies
29 | - run: ./gradlew clean assembleRelease
30 | env:
31 | JVM_OPTS: -Xmx3200m
32 | - uses: actions/upload-artifact@v2
33 | with:
34 | name: pd-core-aar
35 | path: PdCore/build/outputs/aar
36 | - if: github.event_name == 'push'
37 | run: ./gradlew publishToSonatype
38 | env:
39 | ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USERNAME }}
40 | ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }}
41 | #ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SIGNING_KEY }}
42 | #ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SIGNING_PASSWORD }}
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | SX files
2 | .DS_Store
3 |
4 | # Ignore gradle files
5 | .gradle
6 | .gradletasknamecache
7 |
8 | # generated files
9 | bin/
10 | gen/
11 | build/
12 | gdbserver
13 | gdb.setup
14 | *.o
15 | *.o.d
16 |
17 | # built application files
18 | *.apk
19 | *.ap_
20 |
21 | # files for the dex VM
22 | *.dex
23 |
24 | # shared object binaries
25 | *.so
26 |
27 | # Java class files
28 | *.class
29 |
30 | # Local configuration file (sdk path, etc)
31 | local.properties
32 |
33 | # Eclipse project files
34 | .classpath
35 | .project
36 | .settings/org.eclipse.buildship.core.prefs
37 |
38 | # Proguard folder generated by Eclipse
39 | proguard/
40 |
41 | # Intellij project files
42 | *.iml
43 | *.ipr
44 | *.iws
45 | .idea/
46 |
47 | # NetBeans project files
48 | .nb-gradle/
49 |
50 | # Code
51 | .vscode/settings.json
52 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "PdCore/src/main/jni/libpd"]
2 | path = PdCore/src/main/jni/libpd
3 | url = https://github.com/libpd/libpd.git
4 |
--------------------------------------------------------------------------------
/CircleOfFifths/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/CircleOfFifths/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | dependencies {
4 | implementation project(':PdCore')
5 | }
6 |
7 | android {
8 | compileSdkVersion rootProject.compileSdkVersion
9 | buildToolsVersion rootProject.buildToolsVersion
10 | ndkVersion rootProject.ndkVersion
11 | namespace = 'org.puredata.android.fifths'
12 |
13 | defaultConfig {
14 | applicationId "org.puredata.android.fifths"
15 | minSdkVersion rootProject.minSdkVersion
16 | targetSdkVersion 28
17 | versionCode 3
18 | versionName "0.3"
19 | }
20 |
21 | sourceSets {
22 | main {
23 | manifest.srcFile 'AndroidManifest.xml'
24 | java.srcDirs = ['src']
25 | resources.srcDirs = ['src']
26 | aidl.srcDirs = ['src']
27 | renderscript.srcDirs = ['src']
28 | res.srcDirs = ['res']
29 | assets.srcDirs = ['assets']
30 | }
31 |
32 | // Move the build types to build-types/
33 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
34 | // This moves them out of them default location under src//... which would
35 | // conflict with src/ being used by the main source set.
36 | // Adding new build types or product flavors should be accompanied
37 | // by a similar customization.
38 | debug.setRoot('build-types/debug')
39 | release.setRoot('build-types/release')
40 | }
41 |
42 | lintOptions {
43 | ignore 'ExpiredTargetSdkVersion'
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/CircleOfFifths/misc/Makefile:
--------------------------------------------------------------------------------
1 | FILES = ab.svg a.svg bb.svg b.svg c.svg db.svg d.svg eb.svg e.svg fs.svg \
2 | f.svg g.svg
3 |
4 | .PHONY: all clean
5 |
6 | .SUFFIXES:
7 |
8 | .SUFFIXES: .svg .png
9 |
10 | .svg.png:
11 | rsvg-convert -a -h 72 -o $@ $<
12 |
13 | all: ${FILES:.svg=.png}
14 |
15 | clean:
16 | -rm *.png
17 |
18 |
--------------------------------------------------------------------------------
/CircleOfFifths/misc/android.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
170 |
--------------------------------------------------------------------------------
/CircleOfFifths/misc/android_guitar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/misc/android_guitar.png
--------------------------------------------------------------------------------
/CircleOfFifths/misc/guitar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/misc/guitar.png
--------------------------------------------------------------------------------
/CircleOfFifths/misc/guitar.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
188 |
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/background.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/btn_normal.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/btn_normal.9.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/btn_selected.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/btn_selected.9.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/icon.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks00.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks01.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks02.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks03.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks04.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks05.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks06.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks07.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks08.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks09.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks10.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/ks11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/drawable/ks11.png
--------------------------------------------------------------------------------
/CircleOfFifths/res/drawable/radiobuttons.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/CircleOfFifths/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
10 |
13 |
16 |
19 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/CircleOfFifths/res/menu/circle_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/CircleOfFifths/res/raw/patch.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/CircleOfFifths/res/raw/patch.zip
--------------------------------------------------------------------------------
/CircleOfFifths/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Circle Of Fifths
4 | Dom7\nDim7
5 | Maj7\nMin7
6 | Added\nSixth
7 | Sus4\nSus2
8 | Help
9 | About
10 | Circle of Fifths\nCopyright 2010 Peter
11 | Brinkmann\n(peter.brinkmann@gmail.com)\nhttp://nettoyeur.noisepages.com/
12 | Tap a field in order to play the corresponding
13 | chord. Change the key signature by dragging the rim of the circle. The
14 | top line of a button describes the effect on major
15 | chords; the bottom line describes the effect on minor chords.
16 |
17 |
--------------------------------------------------------------------------------
/CircleOfFifths/src/org/puredata/android/fifths/CircleOfFifths.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.fifths;
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 |
15 | import org.puredata.android.io.AudioParameters;
16 | import org.puredata.android.io.PdAudio;
17 | import org.puredata.core.PdBase;
18 | import org.puredata.core.utils.IoUtils;
19 |
20 | import android.app.Activity;
21 | import android.app.AlertDialog;
22 | import android.os.Bundle;
23 | import android.view.Menu;
24 | import android.view.MenuInflater;
25 | import android.view.MenuItem;
26 | import android.view.View;
27 | import android.view.View.OnClickListener;
28 | import android.widget.RadioGroup;
29 | import android.widget.Toast;
30 |
31 |
32 | public class CircleOfFifths extends Activity implements OnClickListener {
33 |
34 | private static final String TAG = "Pd Circle Of Fifths";
35 | private static final String TOP = "top";
36 | private static final int MIN_SAMPLE_RATE = 44100;
37 | private RadioGroup options;
38 | private int option = 0;
39 |
40 | private Toast toast = null;
41 |
42 | private void toast(final String msg) {
43 | runOnUiThread(new Runnable() {
44 | @Override
45 | public void run() {
46 | if (toast == null) {
47 | toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);
48 | }
49 | toast.setText(TAG + ": " + msg);
50 | toast.show();
51 | }
52 | });
53 | }
54 |
55 | @Override
56 | protected void onCreate(Bundle savedInstanceState) {
57 | super.onCreate(savedInstanceState);
58 | initGui();
59 | try {
60 | initPd();
61 | } catch (IOException e) {
62 | toast(e.toString());
63 | finish();
64 | }
65 | }
66 |
67 | @Override
68 | protected void onStart() {
69 | super.onStart();
70 | PdAudio.startAudio(this);
71 | }
72 |
73 | @Override
74 | protected void onStop() {
75 | PdAudio.stopAudio();
76 | super.onStop();
77 | }
78 |
79 | @Override
80 | protected void onDestroy() {
81 | cleanup();
82 | super.onDestroy();
83 | }
84 |
85 | private void initGui() {
86 | setContentView(R.layout.main);
87 | CircleView circle = (CircleView) findViewById(R.id.circleview);
88 | circle.setOwner(this);
89 | int top = getPreferences(MODE_PRIVATE).getInt(TOP, 0);
90 | circle.setTopSegment(top);
91 | options = (RadioGroup) findViewById(R.id.options);
92 | findViewById(R.id.domdim).setOnClickListener(this);
93 | findViewById(R.id.majmin).setOnClickListener(this);
94 | findViewById(R.id.sixth).setOnClickListener(this);
95 | findViewById(R.id.susp).setOnClickListener(this);
96 | }
97 |
98 | private void initPd() throws IOException {
99 | AudioParameters.init(this);
100 | int srate = Math.max(MIN_SAMPLE_RATE, AudioParameters.suggestSampleRate());
101 | PdAudio.initAudio(srate, 0, 2, 1, true);
102 |
103 | File dir = getFilesDir();
104 | File patchFile = new File(dir, "chords.pd");
105 | IoUtils.extractZipResource(getResources().openRawResource(R.raw.patch), dir, true);
106 | PdBase.openPatch(patchFile.getAbsolutePath());
107 | }
108 |
109 | private void cleanup() {
110 | // make sure to release all resources
111 | PdAudio.release();
112 | PdBase.release();
113 | }
114 |
115 | public void playChord(boolean major, int n) {
116 | PdBase.sendList("playchord", option + (major ? 1 : 0), n);
117 | }
118 |
119 | public void endChord() {
120 | PdBase.sendBang("endchord");
121 | resetOptions();
122 | }
123 |
124 | public void setTop(int top) {
125 | PdBase.sendFloat("shift", top);
126 | getPreferences(MODE_PRIVATE).edit().putInt(TOP, top).commit();
127 | }
128 |
129 | @Override
130 | public void onClick(View v) {
131 | int newOption;
132 | int id = v.getId();
133 | if (id == R.id.domdim) {
134 | newOption = 2;
135 | } else if (id == R.id.majmin) {
136 | newOption = 4;
137 | } else if (id == R.id.sixth) {
138 | newOption = 6;
139 | } else if (id == R.id.susp) {
140 | newOption = 8;
141 | } else {
142 | newOption = 0;
143 | }
144 | if (option == newOption) {
145 | resetOptions();
146 | } else {
147 | option = newOption;
148 | }
149 | }
150 |
151 | private void resetOptions() {
152 | option = 0;
153 | options.clearCheck();
154 | }
155 |
156 | @Override
157 | public boolean onCreateOptionsMenu(Menu menu) {
158 | MenuInflater inflater = getMenuInflater();
159 | inflater.inflate(R.menu.circle_menu, menu);
160 | return true;
161 | }
162 |
163 | @Override
164 | public boolean onOptionsItemSelected(MenuItem item) {
165 | AlertDialog.Builder ad = new AlertDialog.Builder(this);
166 | int itemId = item.getItemId();
167 | if (itemId == R.id.about_item) {
168 | ad.setTitle(R.string.about_title);
169 | ad.setMessage(R.string.about_msg);
170 | } else if (itemId == R.id.help_item) {
171 | ad.setTitle(R.string.help_title);
172 | ad.setMessage(R.string.help_msg);
173 | }
174 | ad.setNeutralButton(android.R.string.ok, null);
175 | ad.setCancelable(true);
176 | ad.show();
177 | return true;
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/PdCore/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/PdCore/LICENSE.txt:
--------------------------------------------------------------------------------
1 | This software is copyrighted by Peter Brinkmann and others. The following
2 | terms (the "Standard Improved BSD License") apply to all files associated with
3 | the software unless explicitly disclaimed in individual files:
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 | 3. The name of the author may not be used to endorse or promote
16 | products derived from this software without specific prior
17 | written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 | THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/PdCore/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'signing'
4 | id 'maven-publish'
5 | }
6 |
7 | group = rootProject.group
8 | archivesBaseName = 'pd-core'
9 | version = rootProject.version
10 |
11 | dependencies {
12 | api 'com.noisepages.nettoyeur:midi:1.0.0-rc1'
13 | implementation 'com.noisepages.nettoyeur:midi:1.0.0-rc1'
14 | implementation 'androidx.legacy:legacy-support-v4:' + rootProject.androidxLegacySupportVersion
15 | }
16 |
17 | android {
18 | compileSdkVersion rootProject.compileSdkVersion
19 | buildToolsVersion rootProject.buildToolsVersion
20 | ndkVersion rootProject.ndkVersion
21 | namespace = 'org.puredata.android.service'
22 |
23 | defaultConfig {
24 | minSdkVersion rootProject.minSdkVersion
25 | targetSdkVersion 33
26 | versionCode 1
27 | versionName version
28 | }
29 |
30 | sourceSets {
31 | main {
32 | manifest.srcFile 'AndroidManifest.xml'
33 | java.srcDirs = ['src/main/java', 'src/main/jni/libpd/java']
34 | jniLibs.srcDir 'src/main/libs' //set .so files location to libs
35 | jni.srcDirs = [] //disable automatic ndk-build call
36 | res.srcDirs = ['src/main/res']
37 | assets.srcDirs = ['assets']
38 | }
39 |
40 | // Move the build types to build-types/
41 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
42 | // This moves them out of them default location under src//... which would
43 | // conflict with src/ being used by the main source set.
44 | // Adding new build types or product flavors should be accompanied
45 | // by a similar customization.
46 | debug.setRoot('build-types/debug')
47 | release.setRoot('build-types/release')
48 | }
49 |
50 | tasks.create(name: 'buildNative', type: Exec, description: 'Compile JNI source via NDK') {
51 | commandLine ndkBuildExecutablePath,
52 | '-C', file('src/main/jni').absolutePath,
53 | '-j', Runtime.runtime.availableProcessors(),
54 | 'all',
55 | 'NDK_DEBUG=1'
56 | }
57 |
58 | // After ndk-build, copy libexpr.so to libexpr_tilde.so and libfexpr_tilde.so
59 | buildNative.doLast {
60 | def src = 'libexpr.so'
61 | file('src/main/libs').eachDir() { dir ->
62 | println "Cloning $src in $dir"
63 | copy { from(dir) into(dir) include(src) rename(src, 'libexpr_tilde.so') }
64 | copy { from(dir) into(dir) include(src) rename(src, 'libfexpr_tilde.so') }
65 | }
66 | }
67 |
68 | tasks.create(name: 'cleanNative', type: Exec, description: 'Clean JNI object files') {
69 | commandLine ndkBuildExecutablePath, '-C', file('src/main/jni').absolutePath, 'clean'
70 | }
71 |
72 | clean.configure {
73 | dependsOn tasks.named('cleanNative')
74 | }
75 |
76 | tasks.withType(JavaCompile).configureEach {
77 | dependsOn tasks.named('buildNative')
78 | }
79 |
80 | libraryVariants.all { variant ->
81 | variant.outputs.all { output ->
82 | outputFileName = "${archivesBaseName}.aar"
83 | }
84 | }
85 | }
86 |
87 | import org.apache.tools.ant.taskdefs.condition.Os
88 |
89 | // TODO: Move to convention plugin?
90 | def getNdkBuildExecutablePath() {
91 | // android.ndkDirectory should return project.android.ndkVersion ndkDirectory
92 | def ndkDir = android.ndkDirectory.absolutePath
93 | def ndkBuildName = Os.isFamily(Os.FAMILY_WINDOWS) ? 'ndk-build.cmd' : 'ndk-build'
94 | def ndkBuildFullPath = new File(ndkDir, ndkBuildName).getAbsolutePath()
95 | if (!new File(ndkBuildFullPath).canExecute()) {
96 | throw new GradleScriptException("ndk-build executable not found: $ndkBuildFullPath")
97 | }
98 | return ndkBuildFullPath
99 | }
100 |
101 | task sourcesJar(type: Jar) {
102 | archiveClassifier.set('sources')
103 | from android.sourceSets.main.java.srcDirs
104 | }
105 |
106 | task javadoc(type: Javadoc) {
107 | source = android.sourceSets.main.java.srcDirs
108 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
109 | failOnError = false // TODO: fix javadoc issues
110 | }
111 |
112 | task javadocJar(type: Jar, dependsOn: javadoc) {
113 | archiveClassifier.set('javadoc')
114 | from javadoc.destinationDir
115 | }
116 |
117 | artifacts {
118 | archives javadocJar
119 | archives sourcesJar
120 | }
121 |
122 | def siteUrl = 'https://github.com/libpd/pd-for-android'
123 |
124 | publishing {
125 | publications {
126 | maven(MavenPublication) {
127 | groupId group
128 | artifactId archivesBaseName
129 | version version
130 | // TODO: include aar artifact from components?
131 | artifact "${buildDir}/outputs/aar/${archivesBaseName}.aar"
132 | // ossrh requires javadoc and sources
133 | artifact sourcesJar
134 | artifact javadocJar
135 |
136 | pom {
137 | name = "${project.group}:${project.archivesBaseName}"
138 | description = 'Pure Data for Android'
139 | url = siteUrl
140 | licenses {
141 | license {
142 | name = 'BSD New'
143 | url = 'https://raw.githubusercontent.com/libpd/pd-for-android/master/PdCore/LICENSE.txt'
144 | }
145 | }
146 | developers {
147 | developer {
148 | id = 'joebowbeer'
149 | name = 'Joe Bowbeer'
150 | }
151 | // TODO: Add all other devs here...
152 | }
153 | scm {
154 | connection = 'scm:git:https://github.com/libpd/pd-for-android'
155 | developerConnection = 'scm:git:ssh://github.com/libpd/pd-for-android.git'
156 | url = siteUrl
157 | }
158 | }
159 | }
160 | }
161 | }
162 |
163 | // configure publishing to a local directory for testing (not necessary)
164 | // ./gradlew publishMavenPublicationToLocalRepository
165 | // tree ./PdCore/build/repos
166 | publishing {
167 | repositories {
168 | maven {
169 | name = 'local'
170 | def releasesRepoUrl = "$buildDir/repos/releases"
171 | def snapshotsRepoUrl = "$buildDir/repos/snapshots"
172 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
173 | }
174 | }
175 | }
176 |
177 | // ossrh requires signed releases, but not snapshots.
178 | // This configures signing if a key is found.
179 | // The following environment variables provide a signing key and passphrase:
180 | // export ORG_GRADLE_PROJECT_signingKey=`cat private.pgp`
181 | // export ORG_GRADLE_PROJECT_signingPassword=""
182 | // After making the above available, you can try signing using
183 | // ./gradlew signMavenPublication
184 | def hasSigningKey = project.hasProperty('signingKeyId') || project.hasProperty('signingKey')
185 | if (hasSigningKey) {
186 | sign(project)
187 | }
188 | void sign(Project project) {
189 | project.signing {
190 | required { project.gradle.taskGraph.hasTask('required') }
191 | def signingKeyId = project.findProperty('signingKeyId')
192 | def signingKey = project.findProperty('signingKey')
193 | def signingPassword = project.findProperty('signingPassword')
194 | if (signingKeyId) {
195 | // use in-memory ascii-armored OpenPGP subkey
196 | useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
197 | } else if (signingKey) {
198 | // use in-memory ascii-armored key
199 | useInMemoryPgpKeys(signingKey, signingPassword)
200 | }
201 | sign publishing.publications.maven
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/io/AudioFormatUtil.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.io;
9 |
10 | import org.puredata.android.utils.Properties;
11 |
12 | import android.media.AudioFormat;
13 | import android.util.Log;
14 |
15 | /**
16 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
17 | *
18 | */
19 | public class AudioFormatUtil {
20 |
21 | private AudioFormatUtil() {
22 | // do nothing
23 | }
24 |
25 | public static int getInFormat(int inChannels) {
26 | switch (inChannels) {
27 | case 1: return AudioFormat.CHANNEL_IN_MONO;
28 | case 2: return AudioFormat.CHANNEL_IN_STEREO;
29 | default: throw new IllegalArgumentException("illegal number of input channels: " + inChannels);
30 | }
31 | }
32 |
33 | public static int getOutFormat(int outChannels) {
34 | switch (outChannels) {
35 | case 1: return AudioFormat.CHANNEL_OUT_MONO;
36 | case 2: return AudioFormat.CHANNEL_OUT_STEREO;
37 | case 4: return AudioFormat.CHANNEL_OUT_QUAD;
38 | case 6: return AudioFormat.CHANNEL_OUT_5POINT1;
39 | case 8: return AudioFormat.CHANNEL_OUT_7POINT1;
40 | default: throw new IllegalArgumentException("illegal number of output channels: " + outChannels);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/io/AudioRecordWrapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.io;
9 |
10 | import java.io.IOException;
11 | import java.util.concurrent.BlockingQueue;
12 | import java.util.concurrent.SynchronousQueue;
13 |
14 | import android.media.AudioFormat;
15 | import android.media.AudioRecord;
16 | import android.media.MediaRecorder;
17 | import android.os.Process;
18 |
19 | /**
20 | *
21 | * AudioRecordWrapper is a wrapper for {@link AudioRecord}. It is an auxiliary class for {@link AudioWrapper};
22 | * the purpose of the bizarre queuing mechanism is to work around the AudioRecord.read blocking problem on Droid X,
23 | * without messing things up on other devices.
24 | *
25 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
26 | *
27 | */
28 | public class AudioRecordWrapper {
29 |
30 | private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
31 | private final AudioRecord rec;
32 | private final int bufSizeShorts;
33 | private final BlockingQueue queue = new SynchronousQueue();
34 | private Thread inputThread = null;
35 |
36 | public AudioRecordWrapper(int sampleRate, int inChannels, int bufferSizePerChannel) throws IOException {
37 | int channelConfig = AudioFormatUtil.getInFormat(inChannels);
38 | bufSizeShorts = inChannels * bufferSizePerChannel;
39 | int bufSizeBytes = 2 * bufSizeShorts;
40 | int recSizeBytes = 2 * bufSizeBytes;
41 | int minRecSizeBytes = AudioRecord.getMinBufferSize(sampleRate, channelConfig, ENCODING);
42 | if (minRecSizeBytes <= 0) {
43 | throw new IOException("bad AudioRecord parameters; sr: " + sampleRate + ", ch: " + inChannels + ", bufSize: " + bufferSizePerChannel);
44 | }
45 | while (recSizeBytes < minRecSizeBytes) recSizeBytes += bufSizeBytes;
46 | rec = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, ENCODING, recSizeBytes);
47 | if (rec != null && rec.getState() != AudioRecord.STATE_INITIALIZED) {
48 | rec.release();
49 | throw new IOException("unable to initialize AudioRecord instance for sr: " + sampleRate + ", ch: " + inChannels + ", bufSize: " + bufferSizePerChannel);
50 | }
51 | }
52 |
53 | public synchronized void start() {
54 | inputThread = new Thread() {
55 | @Override
56 | public void run() {
57 | Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
58 | rec.startRecording();
59 | short buf[] = new short[bufSizeShorts];
60 | short auxBuf[] = new short[bufSizeShorts];
61 | while (!Thread.interrupted()) {
62 | int nRead = 0;
63 | while (nRead < bufSizeShorts && !Thread.interrupted()) {
64 | nRead += rec.read(buf, nRead, bufSizeShorts - nRead);
65 | }
66 | if (nRead < bufSizeShorts) break;
67 | try {
68 | queue.put(buf);
69 | } catch (InterruptedException e) {
70 | break;
71 | }
72 | short tmp[] = buf;
73 | buf = auxBuf;
74 | auxBuf = tmp;
75 | }
76 | rec.stop();
77 | };
78 | };
79 | inputThread.start();
80 | }
81 |
82 | public synchronized void stop() {
83 | if (inputThread == null) return;
84 | inputThread.interrupt();
85 | try {
86 | inputThread.join();
87 | } catch (InterruptedException e) {
88 | Thread.currentThread().interrupt(); // Preserve interrupt flag for caller.
89 | }
90 | inputThread = null;
91 | }
92 |
93 | public synchronized void release() {
94 | stop();
95 | rec.release();
96 | queue.clear();
97 | }
98 |
99 | public short[] poll() {
100 | return queue.poll();
101 | }
102 |
103 | public short[] take() throws InterruptedException {
104 | return queue.take();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/io/AudioWrapper.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.io;
9 |
10 | import java.io.IOException;
11 |
12 | import org.puredata.android.service.R;
13 | import org.puredata.android.utils.Properties;
14 |
15 | import android.annotation.TargetApi;
16 | import android.content.Context;
17 | import android.media.AudioFormat;
18 | import android.media.AudioManager;
19 | import android.media.AudioRecord;
20 | import android.media.AudioTrack;
21 | import android.media.MediaPlayer;
22 | import android.os.Build;
23 | import android.os.Process;
24 | import android.util.Log;
25 |
26 | /**
27 | *
28 | * AudioWrapper wraps {@link AudioTrack} and {@link AudioRecord} objects and manages the main audio rendering
29 | * thread. It hides the complexity of working with raw PCM audio; client code only needs to implement a JACK-style
30 | * audio processing callback (jackaudio.org).
31 | *
32 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
33 | *
34 | */
35 | public abstract class AudioWrapper {
36 |
37 | private static final String AUDIO_WRAPPER = "AudioWrapper";
38 | private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
39 | private final AudioRecordWrapper rec;
40 | private final AudioTrack track;
41 | final short outBuf[];
42 | final int inputSizeShorts;
43 | final int bufSizeShorts;
44 | private Thread audioThread = null;
45 |
46 | /**
47 | * Constructor; initializes {@link AudioTrack} and {@link AudioRecord} objects
48 | *
49 | * @param sampleRate
50 | * @param inChannels number of input channels
51 | * @param outChannels number of output channels
52 | * @param bufferSizePerChannel number of samples per buffer per channel
53 | * @throws IOException if the audio parameters are not supported by the device
54 | */
55 | public AudioWrapper(int sampleRate, int inChannels, int outChannels, int bufferSizePerChannel) throws IOException {
56 | int channelConfig = AudioFormatUtil.getOutFormat(outChannels);
57 | rec = (inChannels == 0) ? null : new AudioRecordWrapper(sampleRate, inChannels, bufferSizePerChannel);
58 | inputSizeShorts = inChannels * bufferSizePerChannel;
59 | bufSizeShorts = outChannels * bufferSizePerChannel;
60 | outBuf = new short[bufSizeShorts];
61 | int bufSizeBytes = 2 * bufSizeShorts;
62 | int trackSizeBytes = 2 * bufSizeBytes;
63 | int minTrackSizeBytes = AudioTrack.getMinBufferSize(sampleRate, channelConfig, ENCODING);
64 | if (minTrackSizeBytes <= 0) {
65 | throw new IOException("bad AudioTrack parameters; sr: " + sampleRate +", ch: " + outChannels + ", bufSize: " + trackSizeBytes);
66 | }
67 | while (trackSizeBytes < minTrackSizeBytes) trackSizeBytes += bufSizeBytes;
68 | track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, ENCODING, trackSizeBytes, AudioTrack.MODE_STREAM);
69 | if (track.getState() != AudioTrack.STATE_INITIALIZED) {
70 | track.release();
71 | throw new IOException("unable to initialize AudioTrack instance for sr: " + sampleRate +", ch: " + outChannels + ", bufSize: " + trackSizeBytes);
72 | }
73 | }
74 |
75 | /**
76 | * Main audio rendering callback, reads input samples and writes output samples; inspired by the process callback of JACK
77 | *
78 | * Channels are striped across buffers, i.e., if there are two output channels, then outBuffer[0] will be the first sample
79 | * for the left channel, outBuffer[1] will be the first sample for the right channel, outBuffer[2] will be the second sample
80 | * for the left channel, etc.
81 | *
82 | * @param inBuffer array of input samples to be processed, e.g., from the microphone
83 | * @param outBuffer array of output samples, e.g., to be sent to the speakers
84 | * @return
85 | */
86 | protected abstract int process(short inBuffer[], short outBuffer[]);
87 |
88 | /**
89 | * Start the audio rendering thread as well as {@link AudioTrack} and {@link AudioRecord} objects
90 | *
91 | * @param context
92 | */
93 | public synchronized void start(Context context) {
94 | avoidClickHack(context);
95 | audioThread = new Thread() {
96 | @Override
97 | public void run() {
98 | Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
99 | if (rec != null) rec.start();
100 | track.play();
101 | short inBuf[];
102 | try {
103 | inBuf = (rec != null) ? rec.take() : new short[inputSizeShorts];
104 | } catch (InterruptedException e) {
105 | return;
106 | }
107 | while (!Thread.interrupted()) {
108 | if (process(inBuf, outBuf) != 0) break;
109 | track.write(outBuf, 0, bufSizeShorts);
110 | if (rec != null) {
111 | short newBuf[] = rec.poll();
112 | if (newBuf != null) {
113 | inBuf = newBuf;
114 | } else {
115 | Log.w(AUDIO_WRAPPER, "no input buffer available");
116 | }
117 | }
118 | }
119 | if (rec != null) rec.stop();
120 | track.stop();
121 | }
122 | };
123 | audioThread.start();
124 | }
125 |
126 | /**
127 | * Stop the audio thread as well as {@link AudioTrack} and {@link AudioRecord} objects
128 | */
129 | public synchronized void stop() {
130 | if (audioThread == null) return;
131 | audioThread.interrupt();
132 | try {
133 | audioThread.join();
134 | } catch (InterruptedException e) {
135 | Thread.currentThread().interrupt(); // Preserve interrupt flag for caller.
136 | }
137 | audioThread = null;
138 | }
139 |
140 | /**
141 | * Release resources held by {@link AudioTrack} and {@link AudioRecord} objects;
142 | * stops the audio thread if it is still running
143 | */
144 | public synchronized void release() {
145 | stop();
146 | track.release();
147 | if (rec != null) rec.release();
148 | }
149 |
150 | /**
151 | * @return true if and only if the audio thread is currently running
152 | */
153 | public synchronized boolean isRunning() {
154 | return audioThread != null && audioThread.getState() != Thread.State.TERMINATED;
155 | }
156 |
157 | /**
158 | * @return the audio session ID
159 | */
160 | public synchronized int getAudioSessionId() {
161 | return track.getAudioSessionId();
162 | }
163 |
164 | // weird little hack; eliminates the nasty click when AudioTrack (dis)engages by playing
165 | // a few milliseconds of silence before starting AudioTrack
166 | private void avoidClickHack(Context context) {
167 | try {
168 | MediaPlayer mp = MediaPlayer.create(context, R.raw.silence);
169 | mp.start();
170 | Thread.sleep(10);
171 | mp.stop();
172 | mp.release();
173 | } catch (Exception e) {
174 | Log.e(AUDIO_WRAPPER, e.toString());
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/io/PdAudio.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.io;
9 |
10 | import java.io.IOException;
11 | import java.util.Arrays;
12 |
13 | import org.puredata.core.PdBase;
14 |
15 | import android.content.Context;
16 | import android.os.Handler;
17 | import android.os.Looper;
18 |
19 | /**
20 | *
21 | * PdAudio manages an instance of {@link AudioWrapper} that uses Pure Data for audio processing.
22 | *
23 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
24 | *
25 | */
26 | public class PdAudio {
27 |
28 | private static AudioWrapper audioWrapper = null;
29 | private static final Handler handler = new Handler(Looper.getMainLooper());
30 | private static final Runnable pollRunner = new Runnable() {
31 | @Override
32 | public void run() {
33 | PdBase.pollMidiQueue();
34 | PdBase.pollPdMessageQueue();
35 | handler.postDelayed(this, 5);
36 | }
37 | };
38 |
39 | private PdAudio() {
40 | // Do nothing; we just don't want instances of this class.
41 | }
42 |
43 | /**
44 | * Initializes Pure Data as well as audio components.
45 | *
46 | * @param sampleRate
47 | * @param inChannels number of input channels
48 | * @param outChannels number of output channels
49 | * @param ticksPerBuffer number of Pure Data ticks (i.e., blocks of 64 samples) per buffer; choose 1 for minimal latency,
50 | * or more if performance is a concern; for Java audio only (Android 2.2 or earlier),
51 | * ignored by OpenSL components
52 | * @param restart flag indicating whether the audio thread should be stopped if it is currently running
53 | * @throws IOException if the audio parameters are not supported by the device
54 | */
55 | public synchronized static void initAudio(int sampleRate, int inChannels, int outChannels, final int ticksPerBuffer, boolean restart)
56 | throws IOException {
57 | if (isRunning() && !restart) return;
58 | stopAudio();
59 | if (PdBase.openAudio(inChannels, outChannels, sampleRate, null) != 0) {
60 | throw new IOException("unable to open Pd audio: " + sampleRate + ", " + inChannels + ", " + outChannels);
61 | }
62 | if (!PdBase.implementsAudio()) {
63 | if (!AudioParameters.checkParameters(sampleRate, inChannels, outChannels) || ticksPerBuffer <= 0) {
64 | throw new IOException("bad Java audio parameters: " + sampleRate + ", " + inChannels + ", " + outChannels + ", " + ticksPerBuffer);
65 | }
66 | int bufferSizePerChannel = ticksPerBuffer * PdBase.blockSize();
67 | audioWrapper = new AudioWrapper(sampleRate, inChannels, outChannels, bufferSizePerChannel) {
68 | @Override
69 | protected int process(short[] inBuffer, short[] outBuffer) {
70 | Arrays.fill(outBuffer, (short) 0);
71 | int err = PdBase.process(ticksPerBuffer, inBuffer, outBuffer);
72 | PdBase.pollMidiQueue();
73 | PdBase.pollPdMessageQueue();
74 | return err;
75 | }
76 | };
77 | }
78 | }
79 |
80 | /**
81 | * Starts the audio components.
82 | *
83 | * @param context current application context
84 | */
85 | public synchronized static void startAudio(Context context) {
86 | PdBase.computeAudio(true);
87 | if (PdBase.implementsAudio()) {
88 | handler.post(pollRunner);
89 | PdBase.startAudio();
90 | } else {
91 | if (audioWrapper == null) {
92 | throw new IllegalStateException("audio not initialized");
93 | }
94 | audioWrapper.start(context);
95 | }
96 | }
97 |
98 | /**
99 | * Stops the audio components.
100 | */
101 | public synchronized static void stopAudio() {
102 | if (PdBase.implementsAudio()) {
103 | PdBase.pauseAudio();
104 | handler.removeCallbacks(pollRunner);
105 | handler.post(new Runnable() {
106 | @Override
107 | public void run() {
108 | PdBase.pollMidiQueue(); // Flush pending messages.
109 | PdBase.pollPdMessageQueue();
110 | }
111 | });
112 | } else {
113 | if (!isRunning()) return;
114 | audioWrapper.stop();
115 | }
116 | }
117 |
118 | /**
119 | * @return true if and only if the audio wrapper is running
120 | */
121 | public synchronized static boolean isRunning() {
122 | if (PdBase.implementsAudio()) {
123 | return PdBase.isRunning();
124 | } else {
125 | return audioWrapper != null && audioWrapper.isRunning();
126 | }
127 | }
128 |
129 | /**
130 | * Releases resources held by the audio components.
131 | */
132 | public synchronized static void release() {
133 | stopAudio();
134 | if (PdBase.implementsAudio()) {
135 | PdBase.closeAudio();
136 | } else {
137 | if (audioWrapper == null) return;
138 | audioWrapper.release();
139 | audioWrapper = null;
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/midi/MidiToPdAdapter.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.midi;
9 |
10 | import org.puredata.core.PdBase;
11 |
12 | import com.noisepages.nettoyeur.midi.MidiReceiver;
13 |
14 | /**
15 | * Adapter class for connecting output from AndroidMidi to MIDI input for Pd.
16 | *
17 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
18 | */
19 | public class MidiToPdAdapter implements MidiReceiver {
20 |
21 | @Override
22 | public void onRawByte(byte value) {
23 | PdBase.sendMidiByte(0, value);
24 | }
25 |
26 | @Override
27 | public void onProgramChange(int channel, int program) {
28 | PdBase.sendProgramChange(channel, program);
29 | }
30 |
31 | @Override
32 | public void onPolyAftertouch(int channel, int key, int velocity) {
33 | PdBase.sendPolyAftertouch(channel, key, velocity);
34 | }
35 |
36 | @Override
37 | public void onPitchBend(int channel, int value) {
38 | PdBase.sendPitchBend(channel, value);
39 | }
40 |
41 | @Override
42 | public void onNoteOn(int channel, int key, int velocity) {
43 | PdBase.sendNoteOn(channel, key, velocity);
44 | }
45 |
46 | @Override
47 | public void onNoteOff(int channel, int key, int velocity) {
48 | PdBase.sendNoteOn(channel, key, 0);
49 | }
50 |
51 | @Override
52 | public void onControlChange(int channel, int controller, int value) {
53 | PdBase.sendControlChange(channel, controller, value);
54 | }
55 |
56 | @Override
57 | public void onAftertouch(int channel, int velocity) {
58 | PdBase.sendAftertouch(channel, velocity);
59 | }
60 |
61 | @Override
62 | public boolean beginBlock() {
63 | return false;
64 | }
65 |
66 | @Override
67 | public void endBlock() {}
68 | }
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/midi/PdToMidiAdapter.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.midi;
9 |
10 | import org.puredata.core.PdMidiReceiver;
11 |
12 | import com.noisepages.nettoyeur.midi.MidiReceiver;
13 |
14 | /**
15 | * Adapter class for connecting MIDI output from Pd to input for AndroidMidi.
16 | *
17 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
18 | */
19 | public class PdToMidiAdapter implements PdMidiReceiver {
20 |
21 | private final MidiReceiver receiver;
22 |
23 | /**
24 | * Constructor. Note that instances of this class still need to be installed with
25 | * PdBase.setMidiReceiver.
26 | *
27 | * @param receiver to forward MIDI messages to
28 | */
29 | public PdToMidiAdapter(MidiReceiver receiver) {
30 | this.receiver = receiver;
31 | }
32 |
33 | @Override
34 | public void receiveProgramChange(int channel, int value) {
35 | receiver.onProgramChange(channel, value);
36 | }
37 |
38 | @Override
39 | public void receivePolyAftertouch(int channel, int pitch, int value) {
40 | receiver.onPolyAftertouch(channel, pitch, value);
41 | }
42 |
43 | @Override
44 | public void receivePitchBend(int channel, int value) {
45 | receiver.onPitchBend(channel, value);
46 | }
47 |
48 | @Override
49 | public void receiveNoteOn(int channel, int pitch, int velocity) {
50 | receiver.onNoteOn(channel, pitch, velocity);
51 | }
52 |
53 | @Override
54 | public void receiveMidiByte(int port, int value) {
55 | receiver.onRawByte((byte) value);
56 | }
57 |
58 | @Override
59 | public void receiveControlChange(int channel, int controller, int value) {
60 | receiver.onControlChange(channel, controller, value);
61 | }
62 |
63 | @Override
64 | public void receiveAftertouch(int channel, int value) {
65 | receiver.onAftertouch(channel, value);
66 | }
67 |
68 | @Override
69 | public boolean beginBlock() {
70 | return receiver.beginBlock();
71 | }
72 |
73 | @Override
74 | public void endBlock() {
75 | receiver.endBlock();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/service/PdPreferences.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.service;
9 |
10 | import org.puredata.android.io.AudioParameters;
11 | import org.puredata.core.PdBase;
12 |
13 | import android.content.Context;
14 | import android.content.SharedPreferences;
15 | import android.content.res.Resources;
16 | import android.os.Bundle;
17 | import android.preference.PreferenceActivity;
18 | import android.preference.PreferenceManager;
19 |
20 | /**
21 | *
22 | * PdPreferences is a simple preference activity for choosing audio properties such
23 | * as sample rate and the number of audio I/O channels.
24 | *
25 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
26 | *
27 | */
28 | public class PdPreferences extends PreferenceActivity {
29 |
30 | @SuppressWarnings("deprecation")
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | AudioParameters.init(this);
35 | initPreferences(getApplicationContext());
36 | addPreferencesFromResource(R.xml.preferences);
37 | }
38 |
39 | @Override
40 | protected void onDestroy() {
41 | super.onDestroy();
42 | }
43 |
44 | /**
45 | * If no preferences are available, initialize preferences with defaults suggested by {@link PdBase} or {@link AudioParameters}, in that order.
46 | *
47 | * @param context current application context
48 | */
49 | public static void initPreferences(Context context) {
50 | Resources res = context.getResources();
51 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
52 | if (!prefs.contains(res.getString(R.string.pref_key_srate))) {
53 | SharedPreferences.Editor editor = prefs.edit();
54 | int srate = PdBase.suggestSampleRate();
55 | editor.putString(res.getString(R.string.pref_key_srate), "" + ((srate > 0) ? srate : AudioParameters.suggestSampleRate()));
56 | int nic = PdBase.suggestInputChannels();
57 | editor.putString(res.getString(R.string.pref_key_inchannels), "" + ((nic > 0) ? nic : AudioParameters.suggestInputChannels()));
58 | int noc = PdBase.suggestOutputChannels();
59 | editor.putString(res.getString(R.string.pref_key_outchannels), "" + ((noc > 0) ? noc : AudioParameters.suggestOutputChannels()));
60 | editor.commit();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/service/PdService.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.service;
9 |
10 | import org.puredata.android.io.AudioParameters;
11 | import org.puredata.android.io.PdAudio;
12 | import org.puredata.core.PdBase;
13 | import org.puredata.core.utils.IoUtils;
14 |
15 | import android.app.Notification;
16 | import android.app.NotificationChannel;
17 | import android.app.NotificationManager;
18 | import android.app.PendingIntent;
19 | import android.app.Service;
20 | import android.content.Intent;
21 | import android.content.SharedPreferences;
22 | import android.content.pm.ServiceInfo;
23 | import android.content.res.Resources;
24 | import android.os.Binder;
25 | import android.os.Build;
26 | import android.os.IBinder;
27 | import android.preference.PreferenceManager;
28 | import androidx.core.app.NotificationCompat;
29 | import android.util.Log;
30 |
31 | import java.io.File;
32 | import java.io.IOException;
33 |
34 | /**
35 | *
36 | * PdService allows applications to run Pure Data as a (local) service, with foreground priority if desired.
37 | *
38 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
39 | *
40 | */
41 | public class PdService extends Service {
42 |
43 | public class PdBinder extends Binder {
44 | public PdService getService() {
45 | return PdService.this;
46 | }
47 | }
48 |
49 | private static final String TAG = "PD Service";
50 | private static final int NOTIFICATION_ID = 1;
51 | private static boolean abstractionsInstalled = false;
52 |
53 | private final PdBinder binder = new PdBinder();
54 | private boolean hasForeground = false;
55 |
56 | private volatile int sampleRate = 0;
57 | private volatile int inputChannels = 0;
58 | private volatile int outputChannels = 0;
59 | private volatile float bufferSizeMillis = 0.0f;
60 |
61 | /**
62 | * @return the current audio buffer size in milliseconds (approximate value;
63 | * the exact value is a multiple of the Pure Data tick size (64 samples))
64 | */
65 | public float getBufferSizeMillis() {
66 | return bufferSizeMillis;
67 | }
68 |
69 | /**
70 | * @return number of input channels
71 | */
72 | public int getInputChannels() {
73 | return inputChannels;
74 | }
75 |
76 | /**
77 | * @return number of output channels
78 | */
79 | public int getOutputChannels() {
80 | return outputChannels;
81 | }
82 |
83 | /**
84 | * @return current sample rate
85 | */
86 | public int getSampleRate() {
87 | return sampleRate;
88 | }
89 |
90 | /**
91 | * Initialize Pure Data and audio thread
92 | *
93 | * @param srate sample rate
94 | * @param nic number of input channels
95 | * @param noc number of output channels
96 | * @param millis audio buffer size in milliseconds; for Java audio only (Android 2.2 or earlier),
97 | * will be ignored by OpenSL components
98 | * @throws IOException if the audio parameters are not supported by the device
99 | */
100 | public synchronized void initAudio(int srate, int nic, int noc, float millis) throws IOException {
101 | stopForeground();
102 | Resources res = getResources();
103 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
104 | if (srate < 0) {
105 | String s = prefs.getString(res.getString(R.string.pref_key_srate), null);
106 | if (s != null) {
107 | srate = Integer.parseInt(s);
108 | } else {
109 | srate = PdBase.suggestSampleRate();
110 | if (srate < 0) {
111 | srate = AudioParameters.suggestSampleRate();
112 | }
113 | }
114 | }
115 | if (nic < 0) {
116 | String s = prefs.getString(res.getString(R.string.pref_key_inchannels), null);
117 | if (s != null) {
118 | nic = Integer.parseInt(s);
119 | } else {
120 | nic = PdBase.suggestInputChannels();
121 | if (nic < 0) {
122 | nic = AudioParameters.suggestInputChannels();
123 | }
124 | }
125 | }
126 | if (noc < 0) {
127 | String s = prefs.getString(res.getString(R.string.pref_key_outchannels), null);
128 | if (s != null) {
129 | noc = Integer.parseInt(s);
130 | } else {
131 | noc = PdBase.suggestOutputChannels();
132 | if (noc < 0) {
133 | noc = AudioParameters.suggestOutputChannels();
134 | }
135 | }
136 | }
137 | if (millis < 0) {
138 | millis = 50.0f; // conservative choice
139 | }
140 | int tpb = (int) (0.001f * millis * srate / PdBase.blockSize()) + 1;
141 | PdAudio.initAudio(srate, nic, noc, tpb, true);
142 | sampleRate = srate;
143 | inputChannels = nic;
144 | outputChannels = noc;
145 | bufferSizeMillis = millis;
146 | }
147 |
148 | /**
149 | * Start the audio thread without foreground privileges
150 | */
151 | public synchronized void startAudio() {
152 | PdAudio.startAudio(this);
153 | }
154 |
155 | /**
156 | * Start the audio thread with foreground privileges
157 | *
158 | * @param intent intent to be triggered when the user selects the notification of the service
159 | * @param icon icon representing the notification
160 | * @param title title of the notification
161 | * @param description description of the notification
162 | */
163 | public synchronized void startAudio(Intent intent, int icon, String title, String description) {
164 | startAudio(makeNotification(intent, icon, title, description));
165 | }
166 |
167 | /**
168 | * Start the audio thread with foreground privileges
169 | *
170 | * @param notification notification to display
171 | */
172 | public synchronized void startAudio(Notification notification) {
173 | startForeground(notification);
174 | PdAudio.startAudio(this);
175 | }
176 |
177 | /**
178 | * Stop the audio thread
179 | */
180 | public synchronized void stopAudio() {
181 | PdAudio.stopAudio();
182 | stopForeground();
183 | }
184 |
185 | /**
186 | * @return true if and only if the audio thread is running
187 | */
188 | public synchronized boolean isRunning() {
189 | return PdAudio.isRunning();
190 | }
191 |
192 | /**
193 | * Releases all resources
194 | */
195 | public synchronized void release() {
196 | stopAudio();
197 | PdAudio.release();
198 | PdBase.release();
199 | }
200 |
201 | @Override
202 | public IBinder onBind(Intent intent) {
203 | return binder;
204 | }
205 |
206 | @Override
207 | public boolean onUnbind(Intent intent) {
208 | release();
209 | return false;
210 | }
211 |
212 | @Override
213 | public void onCreate() {
214 | super.onCreate();
215 | AudioParameters.init(this);
216 | if (!abstractionsInstalled) {
217 | try {
218 | File dir = getFilesDir();
219 | IoUtils.extractZipResource(getResources().openRawResource(R.raw.extra_abs), dir, true);
220 | abstractionsInstalled = true;
221 | PdBase.addToSearchPath(dir.getAbsolutePath());
222 | PdBase.addToSearchPath(getApplicationInfo().nativeLibraryDir); // Location of standard externals.
223 | } catch (IOException e) {
224 | Log.e(TAG, "unable to unpack abstractions:" + e.toString());
225 | }
226 | }
227 | }
228 |
229 | @Override
230 | public void onDestroy() {
231 | super.onDestroy();
232 | release();
233 | }
234 |
235 | private Notification makeNotification(Intent intent, int icon, String title, String description) {
236 | NotificationManager notificationManager =
237 | (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
238 | NotificationChannel channel =
239 | new NotificationChannel(TAG, TAG, NotificationManager.IMPORTANCE_LOW);
240 | if (notificationManager != null) {
241 | notificationManager.createNotificationChannel(channel);
242 | }
243 |
244 | PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_IMMUTABLE);
245 | return new NotificationCompat.Builder(PdService.this, TAG)
246 | .setSmallIcon(icon)
247 | .setContentTitle(title)
248 | .setTicker(title)
249 | .setContentText(description)
250 | .setOngoing(true)
251 | .setContentIntent(pi)
252 | .setWhen(System.currentTimeMillis())
253 | .build();
254 | }
255 |
256 | private void startForeground(Notification notification) {
257 | stopForeground();
258 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
259 | int foregroundServiceTypes = ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
260 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
261 | foregroundServiceTypes |= ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
262 | }
263 | startForeground(NOTIFICATION_ID, notification, foregroundServiceTypes);
264 | } else {
265 | startForeground(NOTIFICATION_ID, notification);
266 | }
267 | hasForeground = true;
268 | }
269 |
270 | private void stopForeground() {
271 | if (hasForeground) {
272 | stopForeground(true);
273 | hasForeground = false;
274 | }
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/utils/PdUiDispatcher.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.utils;
9 |
10 | import org.puredata.core.utils.PdDispatcher;
11 |
12 | import android.os.Handler;
13 | import android.util.Log;
14 |
15 | /**
16 | * Subclass of {@link PdDispatcher} for executing callbacks on the main UI thread
17 | * of an Android app. It is actually more general than that; instances of this
18 | * class will execute their callbacks in whichever thread they were created in,
19 | * but in practice it really only makes sense to create instances of this class
20 | * in the main UI thread.
21 | *
22 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
23 | */
24 | public class PdUiDispatcher extends PdDispatcher {
25 |
26 | private final static String TAG = PdUiDispatcher.class.getSimpleName();
27 | private final Handler handler;
28 | private final Thread target;
29 |
30 | /**
31 | * Constructor; invoke from the main UI thread
32 | */
33 | public PdUiDispatcher() {
34 | handler = new Handler();
35 | target = Thread.currentThread();
36 | }
37 |
38 | @Override
39 | public void print(String s) {
40 | Log.i(TAG, "print: " + s);
41 | }
42 |
43 | @Override
44 | public synchronized void receiveBang(final String source) {
45 | if (Thread.currentThread().equals(target)) {
46 | PdUiDispatcher.super.receiveBang(source);
47 | } else {
48 | handler.post(new Runnable() {
49 | @Override
50 | public void run() {
51 | PdUiDispatcher.super.receiveBang(source);
52 | }
53 | });
54 | }
55 | }
56 |
57 | @Override
58 | public synchronized void receiveFloat(final String source, final float x) {
59 | if (Thread.currentThread().equals(target)) {
60 | PdUiDispatcher.super.receiveFloat(source, x);
61 | } else {
62 | handler.post(new Runnable() {
63 | @Override
64 | public void run() {
65 | PdUiDispatcher.super.receiveFloat(source, x);
66 | }
67 | });
68 | }
69 | }
70 |
71 | @Override
72 | public synchronized void receiveSymbol(final String source, final String symbol) {
73 | if (Thread.currentThread().equals(target)) {
74 | PdUiDispatcher.super.receiveSymbol(source, symbol);
75 | } else {
76 | handler.post(new Runnable() {
77 | @Override
78 | public void run() {
79 | PdUiDispatcher.super.receiveSymbol(source, symbol);
80 | }
81 | });
82 | }
83 | }
84 |
85 | @Override
86 | public synchronized void receiveList(final String source, final Object... args) {
87 | if (Thread.currentThread().equals(target)) {
88 | PdUiDispatcher.super.receiveList(source, args);
89 | } else {
90 | handler.post(new Runnable() {
91 | @Override
92 | public void run() {
93 | PdUiDispatcher.super.receiveList(source, args);
94 | }
95 | });
96 | }
97 | }
98 |
99 | @Override
100 | public synchronized void receiveMessage(final String source, final String symbol, final Object... args) {
101 | if (Thread.currentThread().equals(target)) {
102 | PdUiDispatcher.super.receiveMessage(source, symbol, args);
103 | } else {
104 | handler.post(new Runnable() {
105 | @Override
106 | public void run() {
107 | PdUiDispatcher.super.receiveMessage(source, symbol, args);
108 | }
109 | });
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/PdCore/src/main/java/org/puredata/android/utils/Properties.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
4 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
5 | *
6 | */
7 |
8 | package org.puredata.android.utils;
9 |
10 | import android.os.Build;
11 |
12 | /**
13 | *
14 | * Properties is a utility class that checks whether armeabi-v7a is available.
15 | *
16 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
17 | *
18 | */
19 | public class Properties {
20 |
21 | /**
22 | * Android version as an integer (e.g., 8 for FroYo)
23 | */
24 | @SuppressWarnings("deprecation")
25 | public static final int version = Integer.parseInt(Build.VERSION.SDK);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/PdCore/src/main/jni/Android.mk:
--------------------------------------------------------------------------------
1 | include $(call all-subdir-makefiles)
2 |
--------------------------------------------------------------------------------
/PdCore/src/main/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_PLATFORM := android-28
2 | APP_OPTIM := release
3 | APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
4 |
--------------------------------------------------------------------------------
/PdCore/src/main/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/PdCore/src/main/res/drawable/icon.png
--------------------------------------------------------------------------------
/PdCore/src/main/res/raw/extra_abs.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/PdCore/src/main/res/raw/extra_abs.zip
--------------------------------------------------------------------------------
/PdCore/src/main/res/raw/silence.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/PdCore/src/main/res/raw/silence.wav
--------------------------------------------------------------------------------
/PdCore/src/main/res/values/audio.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 8000Hz
5 | - 11025Hz
6 | - 16000Hz
7 | - 22050Hz
8 | - 32000Hz
9 | - 44100Hz
10 | - 48000Hz
11 |
12 |
13 | - 8000
14 | - 11025
15 | - 16000
16 | - 22050
17 | - 32000
18 | - 44100
19 | - 48000
20 |
21 |
22 | - None
23 | - Mono
24 | - Stereo
25 |
26 |
27 | - 0
28 | - 1
29 | - 2
30 |
31 |
32 | - None
33 | - Mono
34 | - Stereo
35 | - Quadraphonic
36 | - 5.1 Surround
37 | - 7.1 surround
38 |
39 |
40 | - 0
41 | - 1
42 | - 2
43 | - 4
44 | - 6
45 | - 8
46 |
47 |
48 |
--------------------------------------------------------------------------------
/PdCore/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pure Data Preferences
4 | Pure Data Preferences
5 | SAMPLE_RATE
6 | Sample rate
7 | Sample rate for Pure Data
8 | INPUT_CHANNELS
9 | Input channels
10 | Number of input channels
11 | OUTPUT_CHANNELS
12 | Output channels
13 | Number of output channels
14 |
15 |
--------------------------------------------------------------------------------
/PdCore/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/PdCore/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/PdTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PdTest/LICENSE.txt:
--------------------------------------------------------------------------------
1 | This software is copyrighted by Peter Brinkmann and others. The following
2 | terms (the "Standard Improved BSD License") apply to all files associated with
3 | the software unless explicitly disclaimed in individual files:
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 | 3. The name of the author may not be used to endorse or promote
16 | products derived from this software without specific prior
17 | written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 | THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/PdTest/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | import org.apache.tools.ant.taskdefs.condition.Os
4 |
5 | dependencies {
6 | implementation project(':PdCore')
7 | implementation 'androidx.legacy:legacy-support-v4:' + rootProject.androidxLegacySupportVersion
8 | }
9 |
10 | android {
11 | compileSdkVersion rootProject.compileSdkVersion
12 | buildToolsVersion rootProject.buildToolsVersion
13 | ndkVersion rootProject.ndkVersion
14 | namespace = 'org.puredata.android.test'
15 |
16 | defaultConfig {
17 | minSdkVersion rootProject.minSdkVersion
18 | targetSdkVersion 33
19 | versionCode 1
20 | versionName '1.0'
21 |
22 | // Uncomment the following 'ndk' section to include only 32-bit CPU architectures in the APK
23 | // ndk {
24 | // abiFilters 'x86', 'armeabi-v7a'
25 | // }
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled true
31 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 |
35 | sourceSets {
36 | main {
37 | manifest.srcFile 'AndroidManifest.xml'
38 | java.srcDirs = ['src']
39 | jniLibs.srcDir 'libs' //set .so files location to libs
40 | jni.srcDirs = [] //disable automatic ndk-build call
41 | resources.srcDirs = ['src']
42 | aidl.srcDirs = ['src']
43 | renderscript.srcDirs = ['src']
44 | res.srcDirs = ['res']
45 | assets.srcDirs = ['assets']
46 | }
47 |
48 | // Move the build types to build-types/
49 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
50 | // This moves them out of the default location under src//... which would
51 | // conflict with src/ being used by the main source set.
52 | // Adding new build types or product flavors should be accompanied
53 | // by a similar customization.
54 | debug.setRoot('build-types/debug')
55 | release.setRoot('build-types/release')
56 | }
57 |
58 | tasks.create(name: 'buildNative', type: Exec, description: 'Compile JNI source via NDK') {
59 | commandLine ndkBuildExecutablePath,
60 | 'V=1',
61 | '-C', file('jni').absolutePath,
62 | '-j', Runtime.runtime.availableProcessors(),
63 | 'all',
64 | 'NDK_DEBUG=1'
65 | }
66 |
67 | tasks.create(name: 'cleanNative', type: Exec, description: 'Clean JNI object files') {
68 | commandLine ndkBuildExecutablePath, 'V=1', '-C', file('jni').absolutePath, 'clean'
69 | }
70 |
71 | clean.configure {
72 | dependsOn tasks.named('cleanNative')
73 | }
74 |
75 | tasks.withType(JavaCompile).configureEach {
76 | dependsOn tasks.named('buildNative')
77 | }
78 | }
79 |
80 | // TODO: Move to convention plugin?
81 | def getNdkBuildExecutablePath() {
82 | // android.ndkDirectory should return project.android.ndkVersion ndkDirectory
83 | def ndkDir = android.ndkDirectory.absolutePath
84 | def ndkBuildName = Os.isFamily(Os.FAMILY_WINDOWS) ? 'ndk-build.cmd' : 'ndk-build'
85 | def ndkBuildFullPath = new File(ndkDir, ndkBuildName).getAbsolutePath()
86 | if (!new File(ndkBuildFullPath).canExecute()) {
87 | throw new GradleScriptException("ndk-build executable not found: $ndkBuildFullPath")
88 | }
89 | return ndkBuildFullPath
90 | }
91 |
--------------------------------------------------------------------------------
/PdTest/jni/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 |
3 | #---------------------------------------------------------------
4 |
5 | include $(CLEAR_VARS)
6 | LOCAL_MODULE := pd
7 | LOCAL_EXPORT_C_INCLUDES := ../../PdCore/src/main/jni/libpd/pure-data/src
8 | LOCAL_SRC_FILES := ../../PdCore/src/main/libs/$(TARGET_ARCH_ABI)/libpd.so
9 | ifneq ($(MAKECMDGOALS),clean)
10 | include $(PREBUILT_SHARED_LIBRARY)
11 | endif
12 |
13 | #---------------------------------------------------------------
14 |
15 | include $(CLEAR_VARS)
16 | LOCAL_MODULE := helloworld
17 | LOCAL_CFLAGS := -DPD
18 | LOCAL_SRC_FILES := helloworld.c
19 | LOCAL_SHARED_LIBRARIES = pd
20 | include $(BUILD_SHARED_LIBRARY)
21 |
22 | #---------------------------------------------------------------
23 |
--------------------------------------------------------------------------------
/PdTest/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_PLATFORM := android-17
2 | APP_OPTIM := release
3 | APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
4 | APP_ALLOW_MISSING_DEPS=true
--------------------------------------------------------------------------------
/PdTest/jni/helloworld.c:
--------------------------------------------------------------------------------
1 | // 'helloworld' external example taken from "HOWTO write an External for Pure Data" by IOhannes m Zmoelnig, 2014
2 | // See: http://pdstatic.iem.at/externals-HOWTO/
3 |
4 | #include "m_pd.h"
5 |
6 | static t_class *helloworld_class;
7 |
8 | typedef struct _helloworld {
9 | t_object x_obj;
10 | } t_helloworld;
11 |
12 | void helloworld_bang(t_helloworld *x)
13 | {
14 | post("Hello world !!");
15 | }
16 |
17 | void *helloworld_new(void)
18 | {
19 | t_helloworld *x = (t_helloworld *)pd_new(helloworld_class);
20 |
21 | return (void *)x;
22 | }
23 |
24 | void helloworld_setup(void) {
25 | helloworld_class = class_new(gensym("helloworld"),
26 | (t_newmethod)helloworld_new,
27 | 0, sizeof(t_helloworld),
28 | CLASS_DEFAULT, 0);
29 | class_addbang(helloworld_class, helloworld_bang);
30 | }
--------------------------------------------------------------------------------
/PdTest/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Keep PdCore and AndroidMidi classes unchanged.
2 | -keep class org.puredata.** { *; }
3 | -keep class com.noisepages.nettoyeur.** { *; }
4 |
--------------------------------------------------------------------------------
/PdTest/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/PdTest/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/PdTest/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/PdTest/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/PdTest/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/PdTest/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/PdTest/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
11 |
14 |
17 |
20 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/PdTest/res/menu/pd_test_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/PdTest/res/raw/test.pd:
--------------------------------------------------------------------------------
1 | #N canvas 582 78 560 426 10;
2 | #X obj 78 116 dac~;
3 | #X obj 157 81 *~ 1;
4 | #X obj 158 37 *~ 0.2;
5 | #X obj 14 83 *~ 1;
6 | #X obj 15 20 osc~ 440;
7 | #X obj 15 39 *~ 0.2;
8 | #X obj 158 18 osc~ 660;
9 | #X obj 90 19 adc~ 1;
10 | #X obj 89 65 *~ 1;
11 | #X obj 11 174 s android;
12 | #X obj 35 63 r left;
13 | #X obj 110 44 r mic;
14 | #X obj 178 60 r right;
15 | #X obj 11 151 r test;
16 | #X obj 87 152 loadbang;
17 | #X obj 87 174 metro 1000;
18 | #X obj 87 195 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
19 | 1;
20 | #X obj 87 239 realtime;
21 | #X obj 87 262 print PD_RUNS;
22 | #X obj 87 216 sel 0;
23 | #X obj 132 217 sel 1;
24 | #X obj 228 213 helloworld;
25 | #X text 223 193 This object is here to test external binding;
26 | #X obj 229 261 expr~;
27 | #X obj 270 260 fexpr~;
28 | #X obj 314 260 sigmund~;
29 | #X obj 373 260 bob~;
30 | #X obj 407 259 expr;
31 | #X obj 440 259 fiddle~;
32 | #X obj 229 281 bonk~;
33 | #X obj 271 281 choice;
34 | #X obj 315 281 loop~;
35 | #X obj 355 280 lrshift~;
36 | #X obj 413 282 pique;
37 | #X text 225 240 test if extra objects can be created;
38 | #X obj 452 280 stdout;
39 | #X obj 228 304 clone;
40 | #X obj 227 345 fudiparse;
41 | #X obj 297 345 fudiformat;
42 | #X text 225 325 test that pd 0.48 objects can be created;
43 | #X connect 1 0 0 1;
44 | #X connect 2 0 1 0;
45 | #X connect 3 0 0 0;
46 | #X connect 4 0 5 0;
47 | #X connect 5 0 3 0;
48 | #X connect 6 0 2 0;
49 | #X connect 7 0 8 0;
50 | #X connect 8 0 0 0;
51 | #X connect 8 0 0 1;
52 | #X connect 10 0 3 1;
53 | #X connect 11 0 8 1;
54 | #X connect 12 0 1 1;
55 | #X connect 13 0 9 0;
56 | #X connect 14 0 15 0;
57 | #X connect 15 0 16 0;
58 | #X connect 16 0 19 0;
59 | #X connect 16 0 20 0;
60 | #X connect 17 0 18 0;
61 | #X connect 19 0 17 0;
62 | #X connect 20 0 17 1;
--------------------------------------------------------------------------------
/PdTest/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Pure Data Test
4 | Sine wave in left channel
5 | Sine wave in right channel
6 | Patch mic to both channels
7 | Enter message to Pure Data
8 | Preferences
9 | About Pure Data
10 | Pure Data is a real-time graphical programming
11 | environment for audio, video, and graphical processing, originally
12 | developed by Miller Puckette and company at IRCAM. Android port by
13 | Peter Brinkmann, Peter Kirn, Hans-Christoph Steiner, and others.
14 |
15 | Play/Pause
16 |
17 |
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [ ](https://maven-badges.herokuapp.com/maven-central/io.github.libpd.android/pd-core)
2 | 
3 |
4 | [](https://gitter.im/libpd/pd-for-android)
5 | \- Try the chat for problems with setting up the library to work with your app
6 |
7 | []( http://stackoverflow.com/questions/tagged/libpd )
8 | \- For questions regarding libpd
9 |
10 | ## How to use the library
11 |
12 | Make sure you have Maven Central in your repositories:
13 |
14 | ```gradle
15 | allprojects {
16 | repositories {
17 | mavenCentral()
18 | // ... other repositories
19 | }
20 | }
21 | ```
22 |
23 | Add the dependency to your app:
24 |
25 | ```gradle
26 | dependencies {
27 | implementation 'io.github.libpd.android:pd-core:1.2.1-rc6'
28 |
29 | // ... other dependencies
30 | }
31 | ```
32 |
33 | Please note that pd-for-android depends on the vanilla version of Pure Data. Currently this is Pure Data vanilla version 0.51-3. You can get desktop distributions of it here:
34 | http://msp.ucsd.edu/software.html
35 |
36 | If you're building the patch for your app using the extended distribution of Pure Data, or any other distribution that is not vanilla, you should be careful not to use PD objects that are not part of the vanilla distribution, because these will not work with libpd out of the box. It is however possible to add PD externals to your pd-for-android app. For a simple example as to how this could be done see the PdTest app in this repository, specifically [the jni folder](https://github.com/libpd/pd-for-android/tree/master/PdTest/jni) and the [build.gradle](https://github.com/libpd/pd-for-android/tree/master/PdTest/build.gradle) file. If you take this path, you'll need to clone this repository and use it as the base folder for your app, similar to the way described in the following section on creating an .aar file.
37 |
38 | ## How to create an .aar file of pd-for-android
39 |
40 | ### Using the terminal
41 |
42 | 1. Clone this repository
43 | 2. Go to the repository folder:
44 | ```
45 | cd pd-for-android
46 | ```
47 | 3. Initialize and udpate the git submodules:
48 | ```
49 | git submodule sync --recursive
50 | git submodule update --init --recursive
51 | ```
52 | 4. Install dependencies and assemble the release: (Note: Windows users should run `gradlew`)
53 | ```
54 | ./gradlew androidDependencies
55 | ./gradlew clean assembleRelease
56 | ```
57 |
58 | Now you have your PdCore .aar file in the folder PdCore/build/outputs/aar
59 |
60 | ### Using Android Studio
61 |
62 | 1. Install Android Studio
63 | 1. Make sure the Android SDK and NDK tools are installed and that Android Studio is properly configured to use them
64 | 1. Clone and initialize this repository as per steps 1-3 above
65 | 1. Create a new Android Studio project by importing `settings.gradle` from the pd-for-android root folder: `File > New > Import Project...`
66 | 1. Open the Gradle Toolbar and run the task assembleRelease in the project :PdCore
67 |
68 | ## How to update PdCore module to use latest libpd version
69 |
70 | 1. From the project root folder, step into the libpd submodule folder: `cd PdCore/src/main/jni/libpd`
71 | 1. Update the libpd submodule to the latest commit by running: `git fetch && git checkout origin/master`
72 | 1. Step back to the project root folder and run `git submodule update --init --recursive`
73 | 1. Test that the PdTest app builds and runs correctly. This can be done by importing the project in Android Studio and running a clean build ('Build' > 'Rebuild Project', run PdTest).
74 |
75 |
--------------------------------------------------------------------------------
/ScenePlayer/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
49 |
54 |
58 |
64 |
65 |
67 |
68 |
--------------------------------------------------------------------------------
/ScenePlayer/LICENSE.txt:
--------------------------------------------------------------------------------
1 | This software is copyrighted by Peter Brinkmann. The following
2 | terms (the "Standard Improved BSD License") apply to all files associated with
3 | the software unless explicitly disclaimed in individual files:
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 | 3. The name of the author may not be used to endorse or promote
16 | products derived from this software without specific prior
17 | written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 | THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/ScenePlayer/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | import org.apache.tools.ant.taskdefs.condition.Os
4 |
5 | dependencies {
6 | implementation project(':PdCore')
7 | }
8 |
9 | android {
10 | compileSdkVersion rootProject.compileSdkVersion
11 | buildToolsVersion rootProject.buildToolsVersion
12 | ndkVersion rootProject.ndkVersion
13 | namespace = 'org.puredata.android.scenes'
14 |
15 | defaultConfig {
16 | minSdkVersion rootProject.minSdkVersion
17 | targetSdkVersion 28
18 | versionCode 11
19 | versionName "0.9.2"
20 | }
21 |
22 | sourceSets {
23 | main {
24 | manifest.srcFile 'AndroidManifest.xml'
25 | java.srcDirs = ['src']
26 | jniLibs.srcDir 'libs' //set .so files location to libs
27 | jni.srcDirs = [] //disable automatic ndk-build call
28 | resources.srcDirs = ['src']
29 | aidl.srcDirs = ['src']
30 | renderscript.srcDirs = ['src']
31 | res.srcDirs = ['res']
32 | assets.srcDirs = ['assets']
33 | }
34 |
35 | // Move the build types to build-types/
36 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
37 | // This moves them out of them default location under src//... which would
38 | // conflict with src/ being used by the main source set.
39 | // Adding new build types or product flavors should be accompanied
40 | // by a similar customization.
41 | debug.setRoot('build-types/debug')
42 | release.setRoot('build-types/release')
43 | }
44 |
45 | tasks.create(name: 'buildNative', type: Exec, description: 'Compile JNI source via NDK') {
46 | commandLine ndkBuildExecutablePath,
47 | '-C', file('jni').absolutePath,
48 | '-j', Runtime.runtime.availableProcessors(),
49 | 'all',
50 | 'NDK_DEBUG=1'
51 | }
52 |
53 | tasks.create(name: 'cleanNative', type: Exec, description: 'Clean JNI object files') {
54 | commandLine ndkBuildExecutablePath, '-C', file('jni').absolutePath, 'clean'
55 | }
56 |
57 | clean.configure {
58 | dependsOn tasks.named('cleanNative')
59 | }
60 |
61 | tasks.withType(JavaCompile).configureEach {
62 | dependsOn tasks.named('buildNative')
63 | }
64 |
65 | lintOptions {
66 | ignore 'ExpiredTargetSdkVersion'
67 | }
68 | }
69 |
70 | // TODO: Move to convention plugin?
71 | def getNdkBuildExecutablePath() {
72 | // android.ndkDirectory should return project.android.ndkVersion ndkDirectory
73 | def ndkDir = android.ndkDirectory.absolutePath
74 | def ndkBuildName = Os.isFamily(Os.FAMILY_WINDOWS) ? 'ndk-build.cmd' : 'ndk-build'
75 | def ndkBuildFullPath = new File(ndkDir, ndkBuildName).getAbsolutePath()
76 | if (!new File(ndkBuildFullPath).canExecute()) {
77 | throw new GradleScriptException("ndk-build executable not found: $ndkBuildFullPath")
78 | }
79 | return ndkBuildFullPath
80 | }
81 |
--------------------------------------------------------------------------------
/ScenePlayer/jni/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 |
3 | #---------------------------------------------------------------
4 |
5 | include $(CLEAR_VARS)
6 | LOCAL_MODULE := pd
7 | LOCAL_EXPORT_C_INCLUDES := ../../PdCore/src/main/jni/libpd/pure-data/src
8 | LOCAL_SRC_FILES := ../../PdCore/src/main/libs/$(TARGET_ARCH_ABI)/libpd.so
9 | ifneq ($(MAKECMDGOALS),clean)
10 | include $(PREBUILT_SHARED_LIBRARY)
11 | endif
12 |
13 | #---------------------------------------------------------------
14 |
15 | include $(CLEAR_VARS)
16 | LOCAL_MODULE := rj_accum
17 | LOCAL_CFLAGS := -DPD
18 | LOCAL_SRC_FILES := rj_accum.c
19 | LOCAL_SHARED_LIBRARIES = pd
20 | include $(BUILD_SHARED_LIBRARY)
21 |
22 | #---------------------------------------------------------------
23 |
24 | include $(CLEAR_VARS)
25 | LOCAL_MODULE := rj_senergy_tilde
26 | LOCAL_CFLAGS := -DPD
27 | LOCAL_SRC_FILES := rj_senergy~.c
28 | LOCAL_SHARED_LIBRARIES = pd
29 | include $(BUILD_SHARED_LIBRARY)
30 |
31 | #---------------------------------------------------------------
32 |
33 | include $(CLEAR_VARS)
34 | LOCAL_MODULE := rj_barkflux_accum_tilde
35 | LOCAL_CFLAGS := -DPD
36 | LOCAL_SRC_FILES := rj_barkflux_accum~.c
37 | LOCAL_SHARED_LIBRARIES = pd
38 | include $(BUILD_SHARED_LIBRARY)
39 |
40 | #---------------------------------------------------------------
41 |
42 | include $(CLEAR_VARS)
43 | LOCAL_MODULE := rj_centroid_tilde
44 | LOCAL_CFLAGS := -DPD
45 | LOCAL_SRC_FILES := rj_centroid~.c
46 | LOCAL_SHARED_LIBRARIES = pd
47 | include $(BUILD_SHARED_LIBRARY)
48 |
49 | #---------------------------------------------------------------
50 |
51 | include $(CLEAR_VARS)
52 | LOCAL_MODULE := rj_zcr_tilde
53 | LOCAL_CFLAGS := -DPD
54 | LOCAL_SRC_FILES := rj_zcr~.c
55 | LOCAL_SHARED_LIBRARIES = pd
56 | include $(BUILD_SHARED_LIBRARY)
57 |
58 | #---------------------------------------------------------------
59 |
--------------------------------------------------------------------------------
/ScenePlayer/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_PLATFORM := android-17
2 | APP_OPTIM := release
3 | APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
4 | APP_ALLOW_MISSING_DEPS=true
--------------------------------------------------------------------------------
/ScenePlayer/jni/rj_accum.c:
--------------------------------------------------------------------------------
1 | /* code for the "rj_accum" pd class.
2 | ver 0.2
3 | Amaury Hazan
4 | Damian Stewart
5 | */
6 |
7 | #include "m_pd.h"
8 | #include
9 | #include
10 |
11 | #define DEF_BLOCKSIZE 512
12 |
13 | typedef struct rj_accum
14 | {
15 | t_object x_obj;
16 |
17 | // configuration values
18 | float blocksize;
19 | float samplerate;
20 |
21 | //short-time buffer, size,counter and desired duration (in s)
22 | float * st_buffer;
23 | int st_buffersize;
24 | int st_buffercnt;
25 | float st_duration;
26 | float st_mean;
27 | float st_total;
28 | int st_idx;
29 |
30 | //long-time buffer, size, counter and desired duration (in s)
31 | float * lt_buffer;
32 | int lt_buffersize;
33 | int lt_buffercnt;
34 | float lt_duration;
35 | float lt_mean;
36 | float lt_total;
37 | int lt_idx;
38 |
39 | float rel_change;
40 |
41 | t_outlet* relative_change; /* m: place for outlet */
42 |
43 | } t_rj_accum;
44 |
45 | void rj_accum_float(t_rj_accum *x, t_floatarg f)
46 | {
47 | if (x->st_buffercnt< x->st_buffersize-1) x->st_buffercnt++;
48 | // calculate new total: subtract old, add new
49 | x->st_total -= x->st_buffer[x->st_idx];
50 | x->st_total += f;
51 | x->st_buffer[x->st_idx] = f;
52 | // increment index
53 | x->st_idx = ( x->st_idx + 1 ) % x->st_buffersize;
54 |
55 | //x->st_mean=x->st_mean*st_before_weight + f*st_after_weight;
56 | x->st_mean = x->st_total / x->st_buffercnt;
57 |
58 | if (x->lt_buffercnt< x->lt_buffersize-1) x->lt_buffercnt++;
59 | // calculate new total: subtract old, add new
60 | x->lt_total -= x->lt_buffer[x->lt_idx];
61 | x->lt_total += f;
62 | x->lt_buffer[x->lt_idx] = f;
63 | // increment index
64 | x->lt_idx = ( x->lt_idx + 1 ) % x->lt_buffersize;
65 | //x->lt_mean=x->lt_mean*lt_before_weight + f*lt_after_weight;
66 | x->lt_mean = x->lt_total / x->lt_buffercnt;
67 |
68 | if (x->lt_mean==0) x->rel_change=0;
69 | else x->rel_change=(x->st_mean-x->lt_mean)/x->lt_mean;
70 |
71 | outlet_float(x->relative_change, x->rel_change);
72 | }
73 |
74 | t_class *rj_accum_class;
75 |
76 | void rj_accum_set_st(t_rj_accum *x, t_floatarg g)
77 | {
78 | post("short term duration fixed to %f", g);
79 | x->st_duration=g;
80 | // determining st buffer size
81 | x->st_buffersize= (int) ((x->st_duration*x->samplerate)/x->blocksize);
82 | x->st_buffercnt=0;
83 | free( x->st_buffer );
84 | x->st_buffer = malloc( x->st_buffersize*sizeof(float) );
85 | memset( x->st_buffer, 0, x->st_buffersize*sizeof(float) );
86 | x->st_total = 0;
87 | x->st_idx = 0;
88 | post("short term number of frames %d", x->st_buffersize);
89 |
90 | }
91 |
92 | void rj_accum_set_lt(t_rj_accum *x, t_floatarg g)
93 | {
94 | post("long term duration fixed to %f", g);
95 | x->lt_duration=g;
96 | // determining st buffer size
97 | x->lt_buffersize= (int) ((x->lt_duration*x->samplerate)/x->blocksize);
98 | x->lt_buffercnt=0;
99 | free( x->lt_buffer );
100 | x->lt_buffer = malloc( x->lt_buffersize*sizeof(float) );
101 | memset( x->lt_buffer, 0, x->lt_buffersize*sizeof(float) );
102 | x->lt_total = 0;
103 | x->lt_idx = 0;
104 | post("long term number of frames %d", x->lt_buffersize);
105 | }
106 |
107 | void *rj_accum_new(t_symbol *selector, int argcount, t_atom *argvec)
108 | {
109 | t_rj_accum *x = (t_rj_accum *)pd_new(rj_accum_class);
110 | x->relative_change=outlet_new(&x->x_obj, &s_float);
111 |
112 | post("new %s", selector->s_name);
113 |
114 | // param passing
115 | if (argcount==1){
116 | x->st_duration=5.f;
117 | x->lt_duration=30.f;
118 | x->blocksize=argvec[0].a_w.w_float;
119 | x->samplerate=sys_getsr();
120 | }
121 | else if (argcount==0){
122 | x->st_duration=5.f;
123 | x->lt_duration=30.f;
124 | x->blocksize=DEF_BLOCKSIZE;
125 | x->samplerate=sys_getsr();
126 | }
127 | else{
128 | post("usage: rj_accum [hopsize]");
129 | post(" where hopsize is processing hop size (default 512)");
130 |
131 | post("you provided %d arguments",argcount);
132 |
133 | x->st_duration=5.f;
134 | x->lt_duration=30.f;
135 | x->blocksize=DEF_BLOCKSIZE;
136 | x->samplerate=sys_getsr();
137 | }
138 |
139 | post("std %f", x->st_duration);
140 | post("ltd %f", x->lt_duration);
141 | post("hopsize %f", x->blocksize);
142 | post("samplerate %f", x->samplerate);
143 |
144 | // buffers allocation
145 | int cnt;
146 |
147 | // detrmining st buffer size
148 | x->st_buffersize= (int) ((x->st_duration*x->samplerate)/x->blocksize);
149 | x->st_buffercnt=0;
150 |
151 | // detrmining lt buffer size
152 | x->lt_buffersize= (int) ((x->lt_duration*x->samplerate)/x->blocksize);
153 | x->lt_buffercnt=0;
154 |
155 | // initializing buffers
156 | x->st_buffer = (float*)malloc( x->st_buffersize*sizeof(float) );
157 | x->lt_buffer = (float*)malloc( x->lt_buffersize*sizeof(float) );
158 | memset( x->st_buffer, 0, x->st_buffersize*sizeof(float) );
159 | memset( x->lt_buffer, 0, x->lt_buffersize*sizeof(float) );
160 |
161 | // initilaizing means
162 | x->st_mean=0.f;
163 | x->lt_mean=0.f;
164 |
165 | // initializing totals and indexes
166 | x->st_total = 0.f;
167 | x->st_idx = 0;
168 | x->lt_total = 0.f;
169 | x->lt_idx = 0;
170 |
171 | x->rel_change=0.f;
172 |
173 | return (void *)x;
174 | }
175 |
176 | static void rj_accumulator_free(t_rj_accum *x)
177 | {
178 | free( x->st_buffer );
179 | free( x->lt_buffer );
180 | }
181 |
182 | void rj_accum_setup(void)
183 | {
184 |
185 | /* We specify "A_GIMME" as creation argument for both the creation
186 | routine and the method (callback) for the "conf" message. */
187 | rj_accum_class = class_new(gensym("rj_accum"), (t_newmethod)rj_accum_new,
188 | 0, sizeof(t_rj_accum), 0, A_GIMME, 0);
189 |
190 | class_addfloat(rj_accum_class, rj_accum_float);
191 | class_addmethod(rj_accum_class, (t_method)rj_accum_set_st, gensym("st"), A_FLOAT, 0);
192 | class_addmethod(rj_accum_class, (t_method)rj_accum_set_lt, gensym("lt"), A_FLOAT, 0);
193 | post("rj_accum version 0.2");
194 | }
195 |
196 |
--------------------------------------------------------------------------------
/ScenePlayer/jni/rj_centroid~.c:
--------------------------------------------------------------------------------
1 | #include "m_pd.h"
2 | #ifdef NT
3 | #pragma warning( disable : 4244 )
4 | #pragma warning( disable : 4305 )
5 | #endif
6 |
7 | // size of the magnitude spectrum to analyze
8 | #define WINSIZE 513
9 |
10 | /* ------------------------ rj_centroid~ for pd----------------------------- */
11 |
12 | /* tilde object to take absolute value. */
13 |
14 | static t_class *rj_centroid_class;
15 |
16 | typedef struct _rj_centroid
17 | {
18 | t_object x_obj; /* obligatory header */
19 | t_float x_f;
20 | t_outlet* rj_centroid; /* m: place for outlet */
21 |
22 | } t_rj_centroid;
23 |
24 | /* this is the actual performance routine which acts on the samples.
25 | It's called with a single pointer "w" which is our location in the
26 | DSP call list. We return a new "w" which will point to the next item
27 | after us. Meanwhile, w[0] is just a pointer to dsp-perform itself
28 | (no use to us), w[1] and w[2] are the input and output vector locations,
29 | and w[3] is the number of points to calculate. */
30 |
31 | static t_int *rj_centroid_perform(t_int *w)
32 | {
33 |
34 | t_rj_centroid *x = (t_rj_centroid *)(w[1]);
35 | t_float *in = (t_float *)(w[2]);
36 |
37 | //int size=(int)(w[3]);
38 | int size=WINSIZE;
39 |
40 | int j;
41 | float sum = 0., sc = 0.;
42 | for ( j = 0; j < size; j++ ) {
43 | sum += in[j];
44 | }
45 | if (sum == 0.) {
46 | outlet_float(x->rj_centroid,0.f);
47 | }
48 | else {
49 | for ( j = 0; j < size; j++ ) {
50 | sc += (float)j * in[j];
51 | }
52 |
53 | outlet_float(x->rj_centroid, sc / sum * sys_getsr() / (float)(size));
54 | }
55 |
56 | return (w+4);
57 | }
58 |
59 | /* called to start DSP. Here we call Pd back to add our perform
60 | routine to a linear callback list which Pd in turn calls to grind
61 | out the samples. */
62 | static void rj_centroid_dsp(t_rj_centroid *x, t_signal **sp)
63 | {
64 | dsp_add(rj_centroid_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
65 | }
66 |
67 | static void *rj_centroid_new(void)
68 | {
69 | t_rj_centroid *x = (t_rj_centroid *)pd_new(rj_centroid_class);
70 | x->rj_centroid=outlet_new(&x->x_obj, &s_float);
71 | x->x_f = 0;
72 |
73 | return (x);
74 | }
75 |
76 | static void rj_centroid_free(t_rj_centroid *x) {
77 |
78 | }
79 |
80 |
81 | /* this routine, which must have exactly this name (with the "~" replaced
82 | by "_tilde) is called when the code is first loaded, and tells Pd how
83 | to build the "class". */
84 | void rj_centroid_tilde_setup(void)
85 | {
86 | rj_centroid_class = class_new(gensym("rj_centroid~"), (t_newmethod)rj_centroid_new, (t_method)rj_centroid_free,
87 | sizeof(t_rj_centroid), 0, A_DEFFLOAT, 0);
88 |
89 | /* this is magic to declare that the leftmost, "main" inlet
90 | takes signals; other signal inlets are done differently... */
91 |
92 | CLASS_MAINSIGNALIN(rj_centroid_class, t_rj_centroid, x_f);
93 | /* here we tell Pd about the "dsp" method, which is called back
94 | when DSP is turned on. */
95 |
96 | class_addmethod(rj_centroid_class, (t_method)rj_centroid_dsp, gensym("dsp"), 0);
97 | post("rj_centroid version 0.1");
98 | }
99 |
--------------------------------------------------------------------------------
/ScenePlayer/jni/rj_senergy~.c:
--------------------------------------------------------------------------------
1 | #include "m_pd.h"
2 | #ifdef NT
3 | #pragma warning( disable : 4244 )
4 | #pragma warning( disable : 4305 )
5 | #endif
6 |
7 | // size of the magnitude spectrum to analyze
8 | #define WINSIZE 513
9 |
10 | /* ------------------------ rj_senergy~ for pd----------------------------- */
11 |
12 | /* tilde object to take absolute value. */
13 |
14 | static t_class *rj_senergy_class;
15 |
16 | typedef struct _rj_senergy
17 | {
18 | t_object x_obj; /* obligatory header */
19 | t_float x_f;
20 | t_outlet* rj_senergy; /* m: place for outlet */
21 |
22 | } t_rj_senergy;
23 |
24 | /* this is the actual performance routine which acts on the samples.
25 | It's called with a single pointer "w" which is our location in the
26 | DSP call list. We return a new "w" which will point to the next item
27 | after us. Meanwhile, w[0] is just a pointer to dsp-perform itself
28 | (no use to us), w[1] and w[2] are the input and output vector locations,
29 | and w[3] is the number of points to calculate. */
30 |
31 | static t_int *rj_senergy_perform(t_int *w)
32 | {
33 |
34 | t_rj_senergy *x = (t_rj_senergy *)(w[1]);
35 | t_float *in = (t_float *)(w[2]);
36 |
37 | //int size=(int)(w[3]);
38 | int size=WINSIZE;
39 |
40 | int j;
41 | float sum = 0.f;
42 | for ( j = 0; j < size; j++ ) {
43 | sum += in[j]*in[j];
44 | }
45 |
46 | outlet_float(x->rj_senergy, sum / (float)(size));
47 |
48 |
49 | return (w+4);
50 | }
51 |
52 | /* called to start DSP. Here we call Pd back to add our perform
53 | routine to a linear callback list which Pd in turn calls to grind
54 | out the samples. */
55 | static void rj_senergy_dsp(t_rj_senergy *x, t_signal **sp)
56 | {
57 | dsp_add(rj_senergy_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
58 | }
59 |
60 | static void *rj_senergy_new(void)
61 | {
62 | t_rj_senergy *x = (t_rj_senergy *)pd_new(rj_senergy_class);
63 | x->rj_senergy=outlet_new(&x->x_obj, &s_float);
64 | x->x_f = 0;
65 |
66 | return (x);
67 | }
68 |
69 | static void rj_senergy_free(t_rj_senergy *x) {
70 |
71 | }
72 |
73 | /* this routine, which must have exactly this name (with the "~" replaced
74 | by "_tilde) is called when the code is first loaded, and tells Pd how
75 | to build the "class". */
76 | void rj_senergy_tilde_setup(void)
77 | {
78 | rj_senergy_class = class_new(gensym("rj_senergy~"), (t_newmethod)rj_senergy_new, (t_method)rj_senergy_free,
79 | sizeof(t_rj_senergy), 0, A_DEFFLOAT, 0);
80 |
81 | /* this is magic to declare that the leftmost, "main" inlet
82 | takes signals; other signal inlets are done differently... */
83 |
84 | CLASS_MAINSIGNALIN(rj_senergy_class, t_rj_senergy, x_f);
85 | /* here we tell Pd about the "dsp" method, which is called back
86 | when DSP is turned on. */
87 |
88 | class_addmethod(rj_senergy_class, (t_method)rj_senergy_dsp, gensym("dsp"), 0);
89 | post("rj_senergy version 0.1");
90 | }
91 |
--------------------------------------------------------------------------------
/ScenePlayer/jni/rj_zcr~.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "m_pd.h"
3 | #ifdef NT
4 | #pragma warning( disable : 4244 )
5 | #pragma warning( disable : 4305 )
6 | #endif
7 |
8 | #define WINDOWSIZE 1024
9 |
10 | /* ------------------------ rj_zcr~ for pd----------------------------- */
11 |
12 | /* tilde object to take absolute value. */
13 |
14 | static t_class *rj_zcr_class;
15 |
16 | typedef struct _rj_zcr
17 | {
18 | t_object x_obj; /* obligatory header */
19 | t_float x_f;
20 | t_outlet* rj_zcr; /* m: place for outlet */
21 |
22 | float * buffer;
23 | int buffercnt;
24 |
25 | } t_rj_zcr;
26 |
27 | /* this is the actual performance routine which acts on the samples.
28 | It's called with a single pointer "w" which is our location in the
29 | DSP call list. We return a new "w" which will point to the next item
30 | after us. Meanwhile, w[0] is just a pointer to dsp-perform itself
31 | (no use to us), w[1] and w[2] are the input and output vector locations,
32 | and w[3] is the number of points to calculate. */
33 |
34 | static t_int *rj_zcr_perform(t_int *w)
35 | {
36 |
37 | t_rj_zcr *x = (t_rj_zcr *)(w[1]);
38 |
39 | t_float *in = (t_float *)(w[2]);
40 |
41 | t_float rate=1.f;
42 |
43 | int size=(int)(w[3]);
44 |
45 | int ibuf;
46 | for (ibuf=0; ibufbuffer[x->buffercnt++]=in[ibuf];
48 | if(x->buffercnt==WINDOWSIZE-1) {
49 |
50 | int ncross=0;
51 | int i;
52 | for (i=0; irj_zcr, rate);
59 |
60 | x->buffercnt=0;
61 | }
62 | }
63 |
64 | return (w+4);
65 | }
66 |
67 | /* called to start DSP. Here we call Pd back to add our perform
68 | routine to a linear callback list which Pd in turn calls to grind
69 | out the samples. */
70 | static void rj_zcr_dsp(t_rj_zcr *x, t_signal **sp)
71 | {
72 | dsp_add(rj_zcr_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
73 | }
74 |
75 | static void *rj_zcr_new(void)
76 | {
77 | t_rj_zcr *x = (t_rj_zcr *)pd_new(rj_zcr_class);
78 | x->rj_zcr=outlet_new(&x->x_obj, &s_float);
79 | x->x_f = 0;
80 |
81 | x->buffer=malloc(WINDOWSIZE*sizeof(float));
82 | x->buffercnt=0;
83 |
84 | return (x);
85 | }
86 |
87 | static void rj_zcr_free(t_rj_zcr *x) {
88 | free(x->buffer);
89 | }
90 |
91 |
92 | /* this routine, which must have exactly this name (with the "~" replaced
93 | by "_tilde) is called when the code is first loaded, and tells Pd how
94 | to build the "class". */
95 | void rj_zcr_tilde_setup(void)
96 | {
97 | rj_zcr_class = class_new(gensym("rj_zcr~"), (t_newmethod)rj_zcr_new, (t_method)rj_zcr_free,
98 | sizeof(t_rj_zcr), 0, A_DEFFLOAT, 0);
99 |
100 | /* this is magic to declare that the leftmost, "main" inlet
101 | takes signals; other signal inlets are done differently... */
102 |
103 | CLASS_MAINSIGNALIN(rj_zcr_class, t_rj_zcr, x_f);
104 | /* here we tell Pd about the "dsp" method, which is called back
105 | when DSP is turned on. */
106 |
107 | class_addmethod(rj_zcr_class, (t_method)rj_zcr_dsp, gensym("dsp"), 0);
108 | post("rj_zcr version 0.1");
109 | }
110 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/all_transparent.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/all_transparent.9.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/default_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/default_thumb.jpg
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/divider_horizontal_dark.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/file.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/folder.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/info_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/mic_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/mic_icon.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/notification_icon.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/play_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
11 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/popup_custom.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/popup_custom.9.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/record_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
11 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/sceneplayer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/sceneplayer.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/sceneplayer_notify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/sceneplayer_notify.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_recordings_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/tab_recordings_dark.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_recordings_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/tab_recordings_light.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_recordings_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_rjdj_me_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/tab_rjdj_me_dark.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_rjdj_me_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/tab_rjdj_me_light.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_rjdj_me_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_scenes_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/tab_scenes_dark.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_scenes_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/tab_scenes_light.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/tab_scenes_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_edit_description.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_edit_description.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_goto_scene.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_goto_scene.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_list.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_list_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_list_pressed.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_pause.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_pause_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_pause_pressed.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_play.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_play_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_play_pressed.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_record.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_record.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_record_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_record_active.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_record_active_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_record_active_pressed.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/transport_record_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/transport_record_pressed.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/white_gradient_bottom.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/white_gradient_bottom.9.png
--------------------------------------------------------------------------------
/ScenePlayer/res/drawable/white_gradient_top.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/drawable/white_gradient_top.9.png
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/file_dialog_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
9 |
11 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/file_dialog_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
12 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/recording_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
11 |
16 |
18 |
23 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/recording_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
14 |
20 |
21 |
25 |
29 |
33 |
37 |
38 |
40 |
43 |
47 |
48 |
51 |
55 |
56 |
57 |
60 |
64 |
65 |
66 |
69 |
73 |
74 |
75 |
78 |
82 |
83 |
84 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/recording_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/scene_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
14 |
20 |
21 |
24 |
28 |
33 |
38 |
41 |
42 |
46 |
50 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/scene_selection.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/tab_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/two_line_dialog_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
17 |
21 |
31 |
41 |
42 |
43 |
46 |
--------------------------------------------------------------------------------
/ScenePlayer/res/layout/two_line_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
18 |
28 |
38 |
39 |
--------------------------------------------------------------------------------
/ScenePlayer/res/menu/selection_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/ScenePlayer/res/raw/abstractions.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/raw/abstractions.zip
--------------------------------------------------------------------------------
/ScenePlayer/res/raw/atsuke.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/ScenePlayer/res/raw/atsuke.zip
--------------------------------------------------------------------------------
/ScenePlayer/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | ScenePlayer
4 | Playing
5 | Play
6 | Record
7 | Recording
8 | Install scene from SD card
9 | Download scene from the web
10 | http://shop.oreilly.com/product/0636920022503.do
11 | About
12 | ScenePlayer\nCopyright 2010 Peter Brinkmann\n(peter.brinkmann@gmail.com)\nhttp://nettoyeur.noisepages.com/
13 | Help
14 | ScenePlayer is a partial Android port of the awesome RjDj app (http://rjdj.me/).
15 | If you want to install more scenes, search the web for RjDj scenes (Martin Brinkmann, Chris McCormick, and Berenger Recoules are among the artists who
16 | have made some of their scenes available for free) and copy them to your SD card. Then you can add them to your list of scenes.
17 |
18 | WARNING: Apps cannot access the SD card while it is mounted as external storage on your computer. Make sure to disconnect your Android device from your
19 | computer before adding scenes.
20 |
21 | Location
22 | Unable to read folder
23 | Select
24 | No Data
25 | Unable to delete scene
26 | Unable to open scene
27 | Unable to delete recording
28 | yyyy-MM-dd hh:mm
29 | mm:ss
30 | /sdcard/pd
31 | Date
32 | Duration
33 | Description
34 | Edit description:
35 | Longitude
36 | Latitude
37 | Unable to open audio file
38 | No such recording
39 | Delete scene
40 | Delete scene and all associated files?
41 | Delete recording
42 | Delete recording?
43 | No recordings
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ScenePlayer/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
--------------------------------------------------------------------------------
/ScenePlayer/src/com/lamerman/FileDialog.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Based on Alexander Ponomarev's file dialog class (https://code.google.com/p/android-file-dialog/)
3 | *
4 | * @author Alexander Ponomarev
5 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
6 | */
7 |
8 | package com.lamerman;
9 |
10 | import java.io.File;
11 | import java.util.ArrayList;
12 | import java.util.HashMap;
13 | import java.util.List;
14 | import java.util.TreeMap;
15 | import java.util.regex.Pattern;
16 |
17 | import org.puredata.android.scenes.R;
18 |
19 | import android.app.AlertDialog;
20 | import android.app.ListActivity;
21 | import android.content.DialogInterface;
22 | import android.content.Intent;
23 | import android.os.Bundle;
24 | import android.view.View;
25 | import android.widget.ListView;
26 | import android.widget.SimpleAdapter;
27 | import android.widget.TextView;
28 |
29 | public class FileDialog extends ListActivity {
30 |
31 | private static final String ITEM_KEY = "key";
32 | private static final String ITEM_IMAGE = "image";
33 |
34 | public static final String START_PATH = "START_PATH";
35 | public static final String RESULT_PATH = "RESULT_PATH";
36 | public static final String SELECT_PATTERN = "SELECT_PATTERN";
37 | public static final String ACCEPT_FOLDER = "ACCEPT_FOLDER";
38 | public static final String ACCEPT_FILE = "ACCEPT_FILE";
39 |
40 | private Intent intent;
41 | private List item = null;
42 | private List path = null;
43 | private String root = "/";
44 | private TextView myPath;
45 | private ArrayList> mList;
46 |
47 | private String parentPath;
48 | private String currentPath = root;
49 | private boolean acceptFolder;
50 | private boolean acceptFile;
51 | private Pattern pattern;
52 |
53 | private File selectedFile;
54 | private HashMap lastPositions = new HashMap();
55 |
56 | @Override
57 | public void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 | intent = getIntent();
60 | setResult(RESULT_CANCELED, intent);
61 | setContentView(R.layout.file_dialog_main);
62 | myPath = (TextView) findViewById(R.id.path);
63 | String startPath = intent.getStringExtra(START_PATH);
64 | selectedFile = new File(startPath);
65 | acceptFolder = intent.getBooleanExtra(ACCEPT_FOLDER, false);
66 | acceptFile = intent.getBooleanExtra(ACCEPT_FILE, true);
67 | String regExp = intent.getStringExtra(SELECT_PATTERN);
68 | pattern = regExp != null ? Pattern.compile(regExp) : null;
69 | getDir(startPath);
70 | }
71 |
72 | private void getDir(String dirPath) {
73 | boolean useAutoSelection = dirPath.length() < currentPath.length();
74 | Integer position = lastPositions.get(parentPath);
75 | getDirImpl(dirPath);
76 | if (position != null && useAutoSelection) {
77 | getListView().setSelection(position);
78 | }
79 | }
80 |
81 | private void getDirImpl(String dirPath) {
82 | File f = new File(dirPath);
83 | File[] files = f.listFiles();
84 | if (files == null) {
85 | dirPath = "/";
86 | f = new File(dirPath);
87 | files = f.listFiles();
88 | }
89 | myPath.setText(getText(R.string.location) + ": " + dirPath);
90 | currentPath = dirPath;
91 | item = new ArrayList();
92 | path = new ArrayList();
93 | mList = new ArrayList>();
94 | if (!dirPath.equals(root)) {
95 | item.add(root);
96 | addItem(root, R.drawable.folder);
97 | path.add(root);
98 | item.add("../");
99 | addItem("../", R.drawable.folder);
100 | path.add(f.getParent());
101 | parentPath = f.getParent();
102 | }
103 | TreeMap dirsMap = new TreeMap();
104 | TreeMap dirsPathMap = new TreeMap();
105 | TreeMap filesMap = new TreeMap();
106 | TreeMap filesPathMap = new TreeMap();
107 | for (File file : files) {
108 | if (file.isDirectory()) {
109 | String dirName = file.getName();
110 | dirsMap.put(dirName, dirName);
111 | dirsPathMap.put(dirName, file.getPath());
112 | } else if (acceptFile && matches(file)) {
113 | filesMap.put(file.getName(), file.getName());
114 | filesPathMap.put(file.getName(), file.getPath());
115 | }
116 | }
117 | item.addAll(dirsMap.tailMap("").values());
118 | item.addAll(filesMap.tailMap("").values());
119 | path.addAll(dirsPathMap.tailMap("").values());
120 | path.addAll(filesPathMap.tailMap("").values());
121 | SimpleAdapter fileList = new SimpleAdapter(this, mList,
122 | R.layout.file_dialog_row,
123 | new String[] { ITEM_KEY, ITEM_IMAGE }, new int[] {
124 | R.id.fdrowtext, R.id.fdrowimage });
125 | for (String dir : dirsMap.tailMap("").values()) {
126 | addItem(dir, R.drawable.folder);
127 | }
128 | for (String file : filesMap.tailMap("").values()) {
129 | addItem(file, R.drawable.file);
130 | }
131 | fileList.notifyDataSetChanged();
132 | setListAdapter(fileList);
133 | }
134 |
135 | private boolean matches(File file) {
136 | return pattern == null || pattern.matcher(file.getName()).matches();
137 | }
138 |
139 | private void addItem(String fileName, int imageId) {
140 | HashMap item = new HashMap();
141 | item.put(ITEM_KEY, fileName);
142 | item.put(ITEM_IMAGE, imageId);
143 | mList.add(item);
144 | }
145 |
146 | @Override
147 | protected void onListItemClick(ListView l, View v, int position, long id) {
148 | selectedFile = new File(path.get(position));
149 | if (selectedFile.isDirectory()) {
150 | if (acceptFolder && pattern != null && matches(selectedFile)) {
151 | setResult(selectedFile);
152 | return;
153 | }
154 | if (selectedFile.canRead()) {
155 | lastPositions.put(currentPath, position);
156 | getDir(path.get(position));
157 | } else {
158 | new AlertDialog.Builder(this)
159 | .setIcon(org.puredata.android.service.R.drawable.icon)
160 | .setTitle(
161 | "[" + selectedFile.getName() + "] "
162 | + getText(R.string.cant_read_folder))
163 | .setPositiveButton("OK",
164 | new DialogInterface.OnClickListener() {
165 |
166 | @Override
167 | public void onClick(DialogInterface dialog,
168 | int which) {
169 |
170 | }
171 | }).show();
172 | }
173 | } else if (acceptFile && matches(selectedFile)) {
174 | setResult(selectedFile);
175 | return;
176 | }
177 | v.setSelected(true);
178 | }
179 |
180 | private void setResult(File file) {
181 | intent.putExtra(RESULT_PATH, file.getPath());
182 | setResult(RESULT_OK, getIntent());
183 | finish();
184 | }
185 | }
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/ImageOverlay.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import android.graphics.Bitmap;
13 | import android.graphics.BitmapFactory;
14 | import android.graphics.Canvas;
15 | import android.graphics.Paint;
16 | import android.graphics.Rect;
17 |
18 | public class ImageOverlay extends Overlay {
19 |
20 | private final Bitmap image;
21 | private boolean centered = true;
22 | private float scaleX = 1.0f;
23 | private float scaleY = 1.0f;
24 | private float angle = 0.0f;
25 | private final Paint paint = new Paint();
26 |
27 | public ImageOverlay(String filename) {
28 | image = BitmapFactory.decodeFile(filename);
29 | }
30 |
31 | public void setCentered(boolean flag) {
32 | centered = flag;
33 | invalidate();
34 | }
35 |
36 | public void setScale(float valx, float valy) {
37 | scaleX = valx;
38 | scaleY = valy;
39 | invalidate();
40 |
41 | }
42 |
43 | public void setAngle(float val) {
44 | angle = val;
45 | invalidate();
46 | }
47 |
48 | public void setAlpha(float val) {
49 | paint.setAlpha((int) (val * 255));
50 | invalidate();
51 | }
52 |
53 | @Override
54 | protected void drawImpl(Canvas canvas) {
55 | canvas.save();
56 | int cw = container.getWidth();
57 | int ch = container.getHeight();
58 | int xm = (int) (x * cw / SceneView.SIZE);
59 | int ym = (int) (y * ch / SceneView.SIZE);
60 | canvas.translate(xm, ym);
61 | canvas.rotate(angle);
62 | canvas.scale(scaleX, scaleY);
63 | int xd = image.getWidth() * cw / SceneView.SIZE / 2;
64 | int yd = image.getHeight() * ch / SceneView.SIZE / 2;
65 | Rect rect = centered ? new Rect(-xd, -yd, xd, yd)
66 | : new Rect(0, 0, 2 * xd, 2 * yd);
67 | canvas.drawBitmap(image, null, rect, paint);
68 | canvas.restore();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/Overlay.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import android.graphics.Canvas;
13 | import android.widget.ImageView;
14 |
15 | public abstract class Overlay implements Runnable {
16 |
17 | protected volatile ImageView container;
18 | protected volatile float x = 0, y = 0;
19 | private volatile boolean visible = true;
20 |
21 | public void setContainer(ImageView container) {
22 | this.container = container;
23 | }
24 |
25 | public void setVisible(boolean visible) {
26 | this.visible = visible;
27 | invalidate();
28 | }
29 |
30 | public void setPosition(float x, float y) {
31 | this.x = x;
32 | this.y = y;
33 | invalidate();
34 | }
35 |
36 | protected void invalidate() {
37 | container.getHandler().post(this);
38 | }
39 |
40 | // override this for more sophisticated choice of invalidation
41 | @Override
42 | public void run() {
43 | container.invalidate();
44 | }
45 |
46 | public void draw(Canvas canvas) {
47 | if (visible) drawImpl(canvas);
48 | }
49 |
50 | protected abstract void drawImpl(Canvas canvas);
51 | }
52 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/RecordingListCursorAdapter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Martin Roth (mhroth@rjdj.me)
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import java.io.File;
13 |
14 | import org.puredata.android.scenes.SceneDataBase.RecordingColumn;
15 | import org.puredata.android.scenes.SceneDataBase.SceneColumn;
16 |
17 | import android.content.Context;
18 | import android.database.Cursor;
19 | import android.graphics.drawable.Drawable;
20 | import android.text.format.DateFormat;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 | import android.widget.CursorAdapter;
24 | import android.widget.ImageView;
25 | import android.widget.TextView;
26 |
27 | /**
28 | * Simple adapter for displaying recordings.
29 | */
30 | public class RecordingListCursorAdapter extends CursorAdapter {
31 |
32 | private final SceneDataBase db;
33 |
34 | public RecordingListCursorAdapter(Context context, Cursor cursor, SceneDataBase db) {
35 | super(context, cursor);
36 | this.db = db;
37 | }
38 |
39 | @Override
40 | public void bindView(View view, Context context, Cursor cursor) {
41 | TextView textView;
42 | long sceneId = SceneDataBase.getLong(cursor, RecordingColumn.SCENE_ID);
43 | textView = (TextView) view.findViewById(R.id.timeInfo);
44 | long timestamp = SceneDataBase.getLong(cursor, RecordingColumn.RECORDING_TIMESTAMP);
45 | textView.setText(DateFormat.format(context.getResources().getString(R.string.date_format), timestamp));
46 | textView = (TextView) view.findViewById(R.id.durationInfo);
47 | long duration = SceneDataBase.getLong(cursor, RecordingColumn.RECORDING_DURATION);
48 | textView.setText(DateFormat.format(context.getResources().getString(R.string.duration_format), duration));
49 | ImageView imageView = (ImageView) view.findViewById(R.id.sceneIcon);
50 | Cursor sceneCursor = db.getScene(sceneId);
51 | if (sceneCursor.getCount() > 0) {
52 | textView = (TextView) view.findViewById(R.id.sceneInfo);
53 | textView.setText(SceneDataBase.getString(sceneCursor, SceneColumn.SCENE_TITLE));
54 | String sceneFolder = SceneDataBase.getString(sceneCursor, SceneColumn.SCENE_DIRECTORY);
55 | File file = new File(sceneFolder, "thumb.jpg");
56 | Drawable icon = Drawable.createFromPath(file.getAbsolutePath());
57 | if (icon == null) {
58 | file = new File(sceneFolder, "image.jpg");
59 | icon = Drawable.createFromPath(file.getAbsolutePath());
60 | }
61 | if (icon != null) {
62 | imageView.setImageDrawable(icon);
63 | } else {
64 | imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.default_thumb));
65 | }
66 | }
67 | sceneCursor.close();
68 | }
69 |
70 | @Override
71 | public View newView(Context context, Cursor cursor, ViewGroup parent) {
72 | View view = View.inflate(context, R.layout.recording_item, null);
73 | bindView(view, context, cursor);
74 | return view;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/RecordingSelection.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import java.io.IOException;
13 |
14 | import org.puredata.android.scenes.SceneDataBase.RecordingColumn;
15 |
16 | import android.app.Activity;
17 | import android.app.AlertDialog;
18 | import android.content.DialogInterface;
19 | import android.content.Intent;
20 | import android.database.Cursor;
21 | import android.os.Bundle;
22 | import android.view.View;
23 | import android.widget.AdapterView;
24 | import android.widget.AdapterView.OnItemClickListener;
25 | import android.widget.AdapterView.OnItemLongClickListener;
26 | import android.widget.ListView;
27 | import android.widget.Toast;
28 |
29 | public class RecordingSelection extends Activity implements OnItemClickListener, OnItemLongClickListener {
30 |
31 | private ListView recordingView;
32 | private SceneDataBase db;
33 | private Cursor cursor = null;
34 |
35 | private Toast toast = null;
36 |
37 | private void toast(final String msg) {
38 | runOnUiThread(new Runnable() {
39 | @Override
40 | public void run() {
41 | if (toast == null) {
42 | toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);
43 | }
44 | toast.setText(msg);
45 | toast.show();
46 | }
47 | });
48 | }
49 |
50 | @Override
51 | protected void onCreate(Bundle savedInstanceState) {
52 | super.onCreate(savedInstanceState);
53 | initGui();
54 | db = new SceneDataBase(this);
55 | }
56 |
57 | private void initGui() {
58 | setContentView(R.layout.recording_selection);
59 | recordingView = (ListView) findViewById(R.id.recording_selection);
60 | recordingView.setEmptyView(findViewById(R.id.no_recordings));
61 | recordingView.setOnItemClickListener(this);
62 | recordingView.setOnItemLongClickListener(this);
63 | }
64 |
65 | @Override
66 | protected void onResume() {
67 | super.onResume();
68 | updateList();
69 | }
70 |
71 | @Override
72 | protected void onDestroy() {
73 | super.onDestroy();
74 | cursor.close();
75 | db.close();
76 | }
77 |
78 | private void updateList() {
79 | if (cursor != null) {
80 | cursor.close();
81 | }
82 | cursor = db.getAllRecordings();
83 | RecordingListCursorAdapter adapter = new RecordingListCursorAdapter(RecordingSelection.this, cursor, db);
84 | recordingView.setAdapter(adapter);
85 | }
86 |
87 | @Override
88 | public void onItemClick(AdapterView> arg0, View v, int position, long id) {
89 | Intent intent = new Intent(this, RecordingPlayer.class);
90 | intent.putExtra(RecordingColumn.ID.getLabel(), id);
91 | startActivity(intent);
92 | }
93 |
94 | @Override
95 | public boolean onItemLongClick(AdapterView> arg0, View v, int position, final long id) {
96 | AlertDialog.Builder dialog = new AlertDialog.Builder(this);
97 | dialog.setIcon(android.R.drawable.ic_dialog_alert);
98 | dialog.setTitle(getResources().getString(R.string.delete_recording_title));
99 | dialog.setMessage(getResources().getString(R.string.delete_recording_message));
100 | dialog.setPositiveButton(getResources().getString(android.R.string.yes), new DialogInterface.OnClickListener() {
101 | @Override
102 | public void onClick(DialogInterface dialog, int which) {
103 | try {
104 | db.deleteRecording(id);
105 | } catch (IOException e) {
106 | toast(getResources().getString(R.string.delete_recording_fail));
107 | }
108 | updateList();
109 | }
110 | });
111 | dialog.setNegativeButton(getResources().getString(android.R.string.no), null);
112 | dialog.show();
113 | return true;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/SceneListCursorAdapter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Martin Roth (mhroth@rjdj.me)
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import java.io.File;
13 |
14 | import org.puredata.android.scenes.SceneDataBase.SceneColumn;
15 |
16 | import android.content.Context;
17 | import android.database.Cursor;
18 | import android.graphics.drawable.Drawable;
19 | import android.view.View;
20 | import android.view.ViewGroup;
21 | import android.widget.CursorAdapter;
22 | import android.widget.ImageView;
23 | import android.widget.TextView;
24 |
25 | /**
26 | * Simple adapter for displaying icons, titles, and authors of scenes in a list.
27 | */
28 | public class SceneListCursorAdapter extends CursorAdapter {
29 |
30 | public SceneListCursorAdapter(Context context, Cursor cursor) {
31 | super(context, cursor);
32 | }
33 |
34 | @Override
35 | public void bindView(View view, Context context, Cursor cursor) {
36 | TextView textView = (TextView) view.findViewById(android.R.id.text1);
37 | textView.setText(SceneDataBase.getString(cursor, SceneColumn.SCENE_TITLE));
38 | textView = (TextView) view.findViewById(android.R.id.text2);
39 | textView.setText(SceneDataBase.getString(cursor, SceneColumn.SCENE_ARTIST));
40 | ImageView imageView = (ImageView) view.findViewById(android.R.id.selectedIcon);
41 | String sceneFolder = SceneDataBase.getString(cursor, SceneColumn.SCENE_DIRECTORY);
42 | File file = new File(sceneFolder, "thumb.jpg");
43 | Drawable icon = Drawable.createFromPath(file.getAbsolutePath());
44 | if (icon == null) {
45 | file = new File(sceneFolder, "image.jpg");
46 | icon = Drawable.createFromPath(file.getAbsolutePath());
47 | }
48 | if (icon != null) {
49 | imageView.setImageDrawable(icon);
50 | } else {
51 | imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.default_thumb));
52 | }
53 | }
54 |
55 | @Override
56 | public View newView(Context context, Cursor cursor, ViewGroup parent) {
57 | View view = View.inflate(context, R.layout.two_line_list_item, null);
58 | bindView(view, context, cursor);
59 | return view;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/SceneTabs.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 |
15 | import org.puredata.core.PdBase;
16 | import org.puredata.core.utils.IoUtils;
17 |
18 | import android.app.TabActivity;
19 | import android.content.Intent;
20 | import android.content.res.Resources;
21 | import android.net.Uri;
22 | import android.os.Bundle;
23 | import android.util.Log;
24 | import android.widget.TabHost;
25 |
26 | public class SceneTabs extends TabActivity {
27 |
28 | private static final String RECORDINGS_TAG = "recordings";
29 | private static final String SCENES_TAG = "scenes";
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | unpackResources();
35 | Resources res = getResources();
36 | TabHost tabHost = getTabHost();
37 | TabHost.TabSpec spec;
38 | Intent intent;
39 | intent = new Intent().setClass(this, SceneSelection.class);
40 | spec = tabHost.newTabSpec(SCENES_TAG).setIndicator("Scenes", res.getDrawable(R.drawable.tab_scenes_selector)).setContent(intent);
41 | tabHost.addTab(spec);
42 | intent = new Intent().setClass(this, RecordingSelection.class);
43 | spec = tabHost.newTabSpec(RECORDINGS_TAG).setIndicator("Recordings", res.getDrawable(R.drawable.tab_recordings_selector)).setContent(intent);
44 | tabHost.addTab(spec);
45 | tabHost.setCurrentTab(0);
46 | }
47 |
48 | private void unpackResources() {
49 | Resources res = getResources();
50 | File libDir = getFilesDir();
51 | try {
52 | IoUtils.extractZipResource(res.openRawResource(R.raw.abstractions), libDir, true);
53 | } catch (IOException e) {
54 | Log.e("Scene Player", e.toString());
55 | }
56 | PdBase.addToSearchPath(libDir.getAbsolutePath());
57 | }
58 |
59 | @Override
60 | protected void onStart() {
61 | super.onStart();
62 | Uri uri = getIntent().getData();
63 | if (uri != null) {
64 | getIntent().setData(null);
65 | Intent intent = new Intent().setClass(this, SceneSelection.class);
66 | intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
67 | intent.setData(uri);
68 | getLocalActivityManager().startActivity(SCENES_TAG, intent);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/SceneView.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import android.content.Context;
16 | import android.graphics.Canvas;
17 | import android.util.AttributeSet;
18 | import android.widget.ImageView;
19 |
20 | public class SceneView extends ImageView {
21 |
22 | public final static int SIZE = 320;
23 |
24 | public SceneView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | }
27 |
28 | private final List overlays = new ArrayList();
29 |
30 | public synchronized void addOverlay(Overlay overlay) {
31 | overlay.setContainer(this);
32 | overlays.add(overlay);
33 | }
34 |
35 | public synchronized void removeOverlay(Overlay overlay) {
36 | overlays.remove(overlay);
37 | }
38 |
39 | @Override
40 | protected synchronized void onDraw(Canvas canvas) {
41 | super.onDraw(canvas);
42 | for (Overlay overlay: overlays) {
43 | overlay.draw(canvas);
44 | }
45 | }
46 |
47 | @Override
48 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
49 | int xDim = getDim(widthMeasureSpec);
50 | int yDim = getDim(heightMeasureSpec);
51 | int dim = Math.min(xDim, yDim);
52 | setMeasuredDimension(dim, dim);
53 | }
54 |
55 | private int getDim(int widthMeasureSpec) {
56 | int mode = MeasureSpec.getMode(widthMeasureSpec);
57 | int size = MeasureSpec.getSize(widthMeasureSpec);
58 | return (mode == MeasureSpec.UNSPECIFIED) ? SIZE : size;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/TextOverlay.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import android.graphics.Canvas;
13 | import android.graphics.Paint;
14 | import android.graphics.Rect;
15 |
16 |
17 | public class TextOverlay extends Overlay {
18 |
19 | private volatile String text = "";
20 | private final Paint paint;
21 |
22 | public TextOverlay(String text) {
23 | this.text = text;
24 | paint = new Paint();
25 | }
26 |
27 | public void setText(String text) {
28 | this.text = text;
29 | invalidate();
30 | }
31 |
32 | public void setSize(float size) {
33 | paint.setTextSize(size);
34 | invalidate();
35 | }
36 |
37 | @Override
38 | protected void drawImpl(Canvas canvas) {
39 | int cw = container.getWidth();
40 | int ch = container.getHeight();
41 | int xm = (int) (x * cw / SceneView.SIZE);
42 | int ym = (int) (y * ch / SceneView.SIZE);
43 | Rect bounds = new Rect();
44 | paint.getTextBounds(text, 0, text.length(), bounds);
45 | int xd = (bounds.right + bounds.left) / 2; // the sign looks wrong, but it turns out to be correct
46 | int yd = (bounds.top + bounds.bottom) / 2;
47 | canvas.drawText(text, xm - xd, ym - yd, paint);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ScenePlayer/src/org/puredata/android/scenes/VersionedTouch.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package org.puredata.android.scenes;
11 |
12 | import org.puredata.android.utils.Properties;
13 | import org.puredata.core.PdBase;
14 |
15 | import android.view.MotionEvent;
16 |
17 |
18 | // Cute little hack to support multiple versions of the Android API, based on an idea
19 | // from http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html
20 | public final class VersionedTouch {
21 |
22 | private static final String TOUCH_SYMBOL = "#touch", DOWN = "down", UP = "up", XY = "xy";
23 | private static final boolean hasEclair = Properties.version >= 5;
24 | private static final float XS = 319.0f, YS = 319.0f;
25 |
26 | private VersionedTouch() {
27 | // do nothing
28 | }
29 |
30 | public static boolean evaluateTouch(MotionEvent event, int xImg, int yImg) {
31 | return (hasEclair) ? TouchEclair.evaluateTouch(event, xImg, yImg) : TouchCupcake.evaluateTouch(event, xImg, yImg);
32 | }
33 |
34 | private static class TouchEclair {
35 |
36 | public static boolean evaluateTouch(MotionEvent event, int xImg, int yImg) {
37 | int action = event.getAction();
38 | String actionTag = null;
39 | switch (action & MotionEvent.ACTION_MASK) {
40 | case MotionEvent.ACTION_POINTER_DOWN:
41 | actionTag = DOWN;
42 | case MotionEvent.ACTION_POINTER_UP:
43 | if (actionTag == null) actionTag = UP;
44 | int pointerIndex = (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; // funny misnomer in Eclair...
45 | int pointerId = event.getPointerId(pointerIndex);
46 | float x = normalize(event.getX(pointerIndex), XS, xImg);
47 | float y = normalize(event.getY(pointerIndex), YS, yImg);
48 | sendMessage(actionTag, pointerId, x, y);
49 | break;
50 | case MotionEvent.ACTION_DOWN:
51 | actionTag = DOWN;
52 | case MotionEvent.ACTION_MOVE:
53 | if (actionTag == null) actionTag = XY;
54 | default:
55 | if (actionTag == null) actionTag = UP;
56 | for (int i = 0; i < event.getPointerCount(); i++) {
57 | x = normalize(event.getX(i), XS, xImg);
58 | y = normalize(event.getY(i), YS, yImg);
59 | sendMessage(actionTag, event.getPointerId(i), x, y);
60 | }
61 | break;
62 | }
63 | return true;
64 | }
65 | }
66 |
67 | private static class TouchCupcake {
68 |
69 | public static boolean evaluateTouch(MotionEvent event, int xImg, int yImg) {
70 | String actionTag;
71 | switch (event.getAction()) {
72 | case MotionEvent.ACTION_DOWN:
73 | actionTag = DOWN;
74 | break;
75 | case MotionEvent.ACTION_MOVE:
76 | actionTag = XY;
77 | break;
78 | default:
79 | actionTag = UP;
80 | break;
81 | }
82 | float x = normalize(event.getX(), XS, xImg);
83 | float y = normalize(event.getY(), YS, yImg);
84 | sendMessage(actionTag, 0, x, y);
85 | return true;
86 | }
87 | }
88 |
89 | private static float normalize(float v, float vm, int dim) {
90 | float t = v * vm / dim;
91 | if (t < 0) t = 0;
92 | else if (t > vm) t = vm;
93 | return t;
94 | }
95 |
96 | private static void sendMessage(String actionTag, int pointerId, float x, float y) {
97 | PdBase.sendMessage(TOUCH_SYMBOL, actionTag, pointerId + 1, x, y);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Voice-O-Rama/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Voice-O-Rama/LICENSE.txt:
--------------------------------------------------------------------------------
1 | This software is copyrighted by Miller Puckette and others. The following
2 | terms (the "Standard Improved BSD License") apply to all files associated with
3 | the software unless explicitly disclaimed in individual files:
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 | 3. The name of the author may not be used to endorse or promote
16 | products derived from this software without specific prior
17 | written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
25 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 | THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/Voice-O-Rama/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | dependencies {
4 | implementation project(':PdCore')
5 | }
6 |
7 | android {
8 | compileSdkVersion rootProject.compileSdkVersion
9 | buildToolsVersion rootProject.buildToolsVersion
10 | namespace = 'at.or.at.voiceorama'
11 |
12 | defaultConfig {
13 | minSdkVersion rootProject.minSdkVersion
14 | targetSdkVersion 28
15 | versionCode 11
16 | versionName "1.0"
17 | }
18 |
19 | sourceSets {
20 | main {
21 | manifest.srcFile 'AndroidManifest.xml'
22 | java.srcDirs = ['src']
23 | resources.srcDirs = ['src']
24 | aidl.srcDirs = ['src']
25 | renderscript.srcDirs = ['src']
26 | res.srcDirs = ['res']
27 | assets.srcDirs = ['assets']
28 | }
29 |
30 | // Move the build types to build-types/
31 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
32 | // This moves them out of them default location under src//... which would
33 | // conflict with src/ being used by the main source set.
34 | // Adding new build types or product flavors should be accompanied
35 | // by a similar customization.
36 | debug.setRoot('build-types/debug')
37 | release.setRoot('build-types/release')
38 | }
39 |
40 | lintOptions {
41 | ignore 'ExpiredTargetSdkVersion'
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Voice-O-Rama/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/Voice-O-Rama/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/Voice-O-Rama/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/Voice-O-Rama/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/Voice-O-Rama/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/Voice-O-Rama/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/Voice-O-Rama/res/layout-land/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
13 |
16 |
19 |
22 |
24 |
25 |
26 |
28 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Voice-O-Rama/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/Voice-O-Rama/res/menu/pd_test_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/Voice-O-Rama/res/raw/test.pd:
--------------------------------------------------------------------------------
1 | #N canvas 444 430 605 405 10;
2 | #X obj 29 16 loadbang;
3 | #X obj 29 59 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 1
4 | ;
5 | #X obj 29 103 realtime;
6 | #X obj 29 126 print PD_RUNS;
7 | #X obj 29 80 sel 0;
8 | #X obj 74 81 sel 1;
9 | #X obj 29 38 metro 5000;
10 | #X obj 163 43 receive #touch;
11 | #X obj 163 66 route xy up down;
12 | #X obj 348 335 dac~;
13 | #X obj 240 255 line~;
14 | #X obj 226 276 *~;
15 | #X obj 206 253 osc~;
16 | #X obj 240 187 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
17 | -1 -1;
18 | #X obj 369 242 line~;
19 | #X obj 355 263 *~;
20 | #X obj 368 198 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
21 | -1 -1;
22 | #X obj 473 254 line~;
23 | #X obj 459 275 *~;
24 | #X obj 472 210 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
25 | -1 -1;
26 | #X obj 418 247 osc~ 500;
27 | #X obj 312 241 osc~ 300;
28 | #X obj 56 172 unpack float float float;
29 | #X obj 253 209 delay 100;
30 | #X msg 271 234 0 100;
31 | #X obj 122 271 line~;
32 | #X obj 108 292 *~;
33 | #X obj 88 269 osc~;
34 | #X obj 122 203 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
35 | -1 -1;
36 | #X obj 135 225 delay 100;
37 | #X msg 153 250 0 100;
38 | #X msg 474 230 0.3 \, 0 100;
39 | #X msg 370 218 0.3 \, 0 100;
40 | #X msg 239 233 0.3;
41 | #X msg 121 249 0.3;
42 | #X obj 79 240 + 200;
43 | #X obj 201 225 + 200;
44 | #X connect 0 0 6 0;
45 | #X connect 1 0 4 0;
46 | #X connect 1 0 5 0;
47 | #X connect 2 0 3 0;
48 | #X connect 4 0 2 0;
49 | #X connect 5 0 2 1;
50 | #X connect 6 0 1 0;
51 | #X connect 7 0 8 0;
52 | #X connect 8 0 22 0;
53 | #X connect 8 1 16 0;
54 | #X connect 8 2 19 0;
55 | #X connect 10 0 11 1;
56 | #X connect 11 0 9 1;
57 | #X connect 12 0 11 0;
58 | #X connect 13 0 33 0;
59 | #X connect 13 0 23 0;
60 | #X connect 14 0 15 1;
61 | #X connect 15 0 9 0;
62 | #X connect 16 0 32 0;
63 | #X connect 17 0 18 1;
64 | #X connect 18 0 9 1;
65 | #X connect 19 0 31 0;
66 | #X connect 20 0 18 0;
67 | #X connect 21 0 15 0;
68 | #X connect 22 1 28 0;
69 | #X connect 22 1 35 0;
70 | #X connect 22 2 13 0;
71 | #X connect 22 2 36 0;
72 | #X connect 23 0 24 0;
73 | #X connect 24 0 10 0;
74 | #X connect 25 0 26 1;
75 | #X connect 26 0 9 0;
76 | #X connect 27 0 26 0;
77 | #X connect 28 0 34 0;
78 | #X connect 28 0 29 0;
79 | #X connect 29 0 30 0;
80 | #X connect 30 0 25 0;
81 | #X connect 31 0 17 0;
82 | #X connect 32 0 14 0;
83 | #X connect 33 0 10 0;
84 | #X connect 34 0 25 0;
85 | #X connect 35 0 27 0;
86 | #X connect 36 0 12 0;
87 |
--------------------------------------------------------------------------------
/Voice-O-Rama/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Voice-O-Rama
4 | Sine wave in left channel
5 | Sine wave in right channel
6 | Patch mic to both channels
7 | Enter message to Pure Data
8 | Preferences
9 | About Voice-O-Rama
10 | Thick Goth Sound at your Fingertips!
11 |
12 |
--------------------------------------------------------------------------------
/Voice-O-Rama/src/at/or/at/voiceorama/VersionedTouch.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Peter Brinkmann (peter.brinkmann@gmail.com)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | */
9 |
10 | package at.or.at.voiceorama;
11 |
12 | import org.puredata.android.utils.Properties;
13 | import org.puredata.core.PdBase;
14 |
15 | import android.view.MotionEvent;
16 |
17 |
18 | // Cute little hack to support multiple versions of the Android API, based on an idea
19 | // from http://android-developers.blogspot.com/2010/07/how-to-have-your-cupcake-and-eat-it-too.html
20 | public final class VersionedTouch {
21 |
22 | private static final String TOUCH_SYMBOL = "#touch", DOWN = "down", UP = "up", XY = "xy";
23 | private static final boolean hasEclair = Properties.version >= 5;
24 | private static final float XS = 319.0f, YS = 319.0f;
25 |
26 | private VersionedTouch() {
27 | // do nothing
28 | }
29 |
30 | public static boolean evaluateTouch(MotionEvent event, int xImg, int yImg) {
31 | return (hasEclair) ? TouchEclair.evaluateTouch(event, xImg, yImg) : TouchCupcake.evaluateTouch(event, xImg, yImg);
32 | }
33 |
34 | private static class TouchEclair {
35 |
36 | public static boolean evaluateTouch(MotionEvent event, int xImg, int yImg) {
37 | int action = event.getAction();
38 | String actionTag = null;
39 | switch (action & MotionEvent.ACTION_MASK) {
40 | case MotionEvent.ACTION_POINTER_DOWN:
41 | actionTag = DOWN;
42 | case MotionEvent.ACTION_POINTER_UP:
43 | if (actionTag == null) actionTag = UP;
44 | int pointerIndex = (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; // funny misnomer in Eclair...
45 | int pointerId = event.getPointerId(pointerIndex);
46 | float x = normalize(event.getX(pointerIndex), XS, xImg);
47 | float y = normalize(event.getY(pointerIndex), YS, yImg);
48 | sendMessage(actionTag, pointerId, x, y);
49 | break;
50 | case MotionEvent.ACTION_DOWN:
51 | actionTag = DOWN;
52 | case MotionEvent.ACTION_MOVE:
53 | if (actionTag == null) actionTag = XY;
54 | default:
55 | if (actionTag == null) actionTag = UP;
56 | for (int i = 0; i < event.getPointerCount(); i++) {
57 | x = normalize(event.getX(i), XS, xImg);
58 | y = normalize(event.getY(i), YS, yImg);
59 | sendMessage(actionTag, event.getPointerId(i), x, y);
60 | }
61 | break;
62 | }
63 | return true;
64 | }
65 | }
66 |
67 | private static class TouchCupcake {
68 |
69 | public static boolean evaluateTouch(MotionEvent event, int xImg, int yImg) {
70 | String actionTag;
71 | switch (event.getAction()) {
72 | case MotionEvent.ACTION_DOWN:
73 | actionTag = DOWN;
74 | break;
75 | case MotionEvent.ACTION_MOVE:
76 | actionTag = XY;
77 | break;
78 | default:
79 | actionTag = UP;
80 | break;
81 | }
82 | float x = normalize(event.getX(), XS, xImg);
83 | float y = normalize(event.getY(), YS, yImg);
84 | sendMessage(actionTag, 0, x, y);
85 | return true;
86 | }
87 | }
88 |
89 | private static float normalize(float v, float vm, int dim) {
90 | float t = v * vm / dim;
91 | if (t < 0) t = 0;
92 | else if (t > vm) t = vm;
93 | return t;
94 | }
95 |
96 | private static void sendMessage(String actionTag, int pointerId, float x, float y) {
97 | PdBase.sendMessage(TOUCH_SYMBOL, actionTag, pointerId + 1, x, y);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Voice-O-Rama/src/at/or/at/voiceorama/VoiceORama.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @author Hans-Christoph Steiner (hans@at.or.at)
4 | *
5 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL
6 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution.
7 | *
8 | * fun with Pd and your voice
9 | *
10 | */
11 |
12 | package at.or.at.voiceorama;
13 |
14 | import java.io.File;
15 | import java.io.IOException;
16 | import java.io.InputStream;
17 | import java.util.Arrays;
18 |
19 | import org.puredata.android.service.PdPreferences;
20 | import org.puredata.android.service.PdService;
21 | import org.puredata.core.PdBase;
22 | import org.puredata.core.PdReceiver;
23 | import org.puredata.core.utils.IoUtils;
24 |
25 | import android.app.Activity;
26 | import android.app.AlertDialog;
27 | import android.content.ComponentName;
28 | import android.content.Intent;
29 | import android.content.ServiceConnection;
30 | import android.content.SharedPreferences;
31 | import android.content.res.Configuration;
32 | import android.content.res.Resources;
33 | import android.os.IBinder;
34 | import android.preference.PreferenceManager;
35 | import android.text.method.ScrollingMovementMethod;
36 | import android.util.Log;
37 | import android.view.Menu;
38 | import android.view.MenuInflater;
39 | import android.view.MenuItem;
40 | import android.view.MotionEvent;
41 | import android.view.View;
42 | import android.view.View.OnTouchListener;
43 | import android.widget.TextView;
44 | import android.widget.Toast;
45 |
46 | public class VoiceORama extends Activity implements OnTouchListener, SharedPreferences.OnSharedPreferenceChangeListener {
47 |
48 | private static final String TAG = "Voice-O-Rama";
49 |
50 | private TextView logs;
51 |
52 | private PdService pdService = null;
53 |
54 | private Toast toast = null;
55 |
56 | private void toast(final String msg) {
57 | runOnUiThread(new Runnable() {
58 | @Override
59 | public void run() {
60 | if (toast == null) {
61 | toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);
62 | }
63 | toast.setText(TAG + ": " + msg);
64 | toast.show();
65 | }
66 | });
67 | }
68 |
69 | private void post(final String s) {
70 | runOnUiThread(new Runnable() {
71 | @Override
72 | public void run() {
73 | logs.append(s + ((s.endsWith("\n")) ? "" : "\n"));
74 | }
75 | });
76 | }
77 |
78 | private PdReceiver receiver = new PdReceiver() {
79 |
80 | private void pdPost(String msg) {
81 | toast("Pure Data says, \"" + msg + "\"");
82 | }
83 |
84 | @Override
85 | public void print(String s) {
86 | post(s);
87 | }
88 |
89 | @Override
90 | public void receiveBang(String source) {
91 | pdPost("bang");
92 | }
93 |
94 | @Override
95 | public void receiveFloat(String source, float x) {
96 | pdPost("float: " + x);
97 | }
98 |
99 | @Override
100 | public void receiveList(String source, Object... args) {
101 | pdPost("list: " + Arrays.toString(args));
102 | }
103 |
104 | @Override
105 | public void receiveMessage(String source, String symbol, Object... args) {
106 | pdPost("message: " + Arrays.toString(args));
107 | }
108 |
109 | @Override
110 | public void receiveSymbol(String source, String symbol) {
111 | pdPost("symbol: " + symbol);
112 | }
113 | };
114 |
115 | private final ServiceConnection connection = new ServiceConnection() {
116 | @Override
117 | public void onServiceConnected(ComponentName name, IBinder service) {
118 | pdService = ((PdService.PdBinder)service).getService();
119 | initPd();
120 | }
121 |
122 | @Override
123 | public void onServiceDisconnected(ComponentName name) {
124 | // this method will never be called
125 | }
126 | };
127 |
128 | @Override
129 | protected void onCreate(android.os.Bundle savedInstanceState) {
130 | super.onCreate(savedInstanceState);
131 | PdPreferences.initPreferences(getApplicationContext());
132 | PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
133 | initGui();
134 | bindService(new Intent(this, PdService.class), connection, BIND_AUTO_CREATE);
135 | //requestWindowFeature(Window.FEATURE_NO_TITLE);
136 | };
137 |
138 | @Override
139 | protected void onDestroy() {
140 | super.onDestroy();
141 | cleanup();
142 | }
143 |
144 | @Override
145 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
146 | startAudio();
147 | }
148 |
149 | @Override
150 | public void onConfigurationChanged(Configuration newConfig) {
151 | super.onConfigurationChanged(newConfig);
152 | CharSequence logsc = logs.getText();
153 | initGui();
154 | logs.setText(logsc);
155 | }
156 |
157 | private void initGui() {
158 | setContentView(R.layout.main);
159 | logs = (TextView) findViewById(R.id.log_box);
160 | logs.setOnTouchListener(this);
161 | logs.setMovementMethod(new ScrollingMovementMethod());
162 | }
163 |
164 | private void initPd() {
165 | Resources res = getResources();
166 | File patchFile = null;
167 | try {
168 | PdBase.setReceiver(receiver);
169 | PdBase.subscribe("android");
170 | InputStream in = res.openRawResource(R.raw.test);
171 | patchFile = IoUtils.extractResource(in, "test.pd", getCacheDir());
172 | PdBase.openPatch(patchFile);
173 | startAudio();
174 | } catch (IOException e) {
175 | Log.e(TAG, e.toString());
176 | finish();
177 | } finally {
178 | if (patchFile != null) patchFile.delete();
179 | }
180 | }
181 |
182 | private void startAudio() {
183 | String name = getResources().getString(R.string.app_name);
184 | try {
185 | pdService.initAudio(-1, -1, -1, -1); // negative values will be replaced with defaults/preferences
186 | pdService.startAudio(new Intent(this, VoiceORama.class), R.drawable.icon, name, "Return to " + name + ".");
187 | } catch (IOException e) {
188 | toast(e.toString());
189 | }
190 | }
191 |
192 | private void cleanup() {
193 | try {
194 | unbindService(connection);
195 | } catch (IllegalArgumentException e) {
196 | // already unbound
197 | pdService = null;
198 | }
199 | }
200 |
201 | @Override
202 | public boolean onCreateOptionsMenu(Menu menu) {
203 | MenuInflater inflater = getMenuInflater();
204 | inflater.inflate(R.menu.pd_test_menu, menu);
205 | return true;
206 | }
207 |
208 | @Override
209 | public boolean onOptionsItemSelected(MenuItem item) {
210 | if (item.getItemId() == R.id.about_item) {
211 | AlertDialog.Builder ad = new AlertDialog.Builder(this);
212 | ad.setTitle(R.string.about_title);
213 | ad.setMessage(R.string.about_msg);
214 | ad.setNeutralButton(android.R.string.ok, null);
215 | ad.setCancelable(true);
216 | ad.show();
217 | }
218 | return true;
219 | }
220 |
221 |
222 | @Override
223 | public boolean onTouch(View v, MotionEvent event) {
224 | return (v == logs) && VersionedTouch.evaluateTouch(event, logs.getWidth(), logs.getHeight());
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:8.0.2'
8 | }
9 | }
10 |
11 | plugins {
12 | // must be applied to root project
13 | id 'io.github.gradle-nexus.publish-plugin' version '1.0.0'
14 | }
15 |
16 | // These are specific to PdCode, but nexusPublishing needs them here:
17 | // https://github.com/gradle-nexus/publish-plugin/issues/84
18 | group = 'io.github.libpd.android'
19 | version = '1.2.1-SNAPSHOT'
20 |
21 | // Create a Sonatype user token for these environment variables:
22 | // export ORG_GRADLE_PROJECT_sonatypeUsername=""
23 | // export ORG_GRADLE_PROJECT_sonatypePassword=""
24 | nexusPublishing {
25 | repositories {
26 | sonatype {
27 | nexusUrl.set(uri('https://s01.oss.sonatype.org/service/local/'))
28 | snapshotRepositoryUrl.set(uri('https://s01.oss.sonatype.org/content/repositories/snapshots/'))
29 | }
30 | }
31 | }
32 |
33 | allprojects {
34 | repositories {
35 | google()
36 | mavenCentral()
37 | jcenter() // FIXME: com.noisepages.nettoyeur:midi
38 | }
39 | }
40 |
41 | ext {
42 | minSdkVersion = 28
43 | compileSdkVersion = 34
44 | buildToolsVersion = '34.0.0'
45 | androidxLegacySupportVersion = '1.0.0'
46 | ndkVersion = '25.2.9519653' // https://developer.android.com/ndk/downloads#lts-downloads
47 | }
48 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.useAndroidX=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libpd/pd-for-android/f52051edc4da2d12333afe5303c4df82385dc19f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':CircleOfFifths'
2 | include ':PdCore'
3 | include ':PdTest'
4 | include ':ScenePlayer'
5 | include ':Voice-O-Rama'
6 |
--------------------------------------------------------------------------------