From 076ab6eab8dcf610c32d30a88aa894d2ab0b5461 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Mon, 4 Jul 2016 10:43:07 -0700 Subject: [PATCH] Convert to Android Studio This commit makes the project build on Android Studio. It also deletes a whole lot of unused code. Further, in this patch, the NEON code is not build, just C++. --- .gitignore | 8 + .idea/.name | 1 + .idea/compiler.xml | 22 + .idea/copyright/profiles_settings.xml | 3 + .idea/encodings.xml | 6 + .idea/gradle.xml | 23 + .idea/misc.xml | 46 ++ .idea/modules.xml | 9 + .idea/runConfigurations.xml | 12 + .idea/vcs.xml | 6 + android/.classpath | 13 - .../.externalToolBuilders/NDK Builder.launch | 10 - .../Proto Builder.launch | 10 - android/.gitignore | 3 - android/.project | 75 -- android/.settings/org.eclipse.jdt.core.prefs | 280 ------- android/.settings/org.eclipse.jdt.ui.prefs | 8 - android/AndroidManifest.xml | 84 -- android/default.properties | 11 - android/jni/Android.mk | 88 -- android/jni/Application.mk | 2 - android/project.properties | 14 - .../levien/synthesizer/android/Storage.java | 279 ------- .../android/ui/AmplificationActivity.java | 61 -- .../android/ui/ChordGridActivity.java | 73 -- .../android/ui/EditInstrumentActivity.java | 141 ---- .../android/ui/EffectsActivity.java | 52 -- .../android/ui/InstrumentListActivity.java | 81 -- .../android/ui/KarplusStrongActivity.java | 59 -- .../android/ui/LowPassFilterActivity.java | 67 -- .../synthesizer/android/ui/MainActivity.java | 107 --- .../android/ui/OscillatorActivity.java | 66 -- .../synthesizer/android/ui/PianoActivity.java | 79 -- .../synthesizer/android/ui/ScoreActivity.java | 141 ---- .../android/ui/SynthesizerActivity.java | 189 ----- .../android/ui/TremoloActivity.java | 68 -- .../android/ui/VibratoActivity.java | 65 -- .../android/widgets/ChordGridView.java | 329 -------- .../android/widgets/piano/BlackPianoKey.java | 95 --- .../android/widgets/piano/NotePianoKey.java | 52 -- .../android/widgets/piano/OctavePianoKey.java | 111 --- .../android/widgets/piano/PianoKey.java | 179 ---- .../android/widgets/piano/PianoView.java | 458 ----------- .../widgets/piano/PianoViewListener.java | 32 - .../android/widgets/piano/WhitePianoKey.java | 72 -- .../android/widgets/score/EditEventTool.java | 490 ----------- .../widgets/score/HideChannelButton.java | 97 --- .../android/widgets/score/NewEventTool.java | 118 --- .../android/widgets/score/NewLoopTool.java | 118 --- .../android/widgets/score/PlayButton.java | 156 ---- .../android/widgets/score/PlayTool.java | 231 ------ .../android/widgets/score/ScoreView.java | 767 ------------------ .../widgets/score/ScoreViewListener.java | 27 - .../android/widgets/score/ScoreViewTool.java | 81 -- .../widgets/score/ScoreViewToolbar.java | 222 ----- .../widgets/score/SelectChannelButton.java | 100 --- .../android/widgets/score/SnapTool.java | 134 --- .../android/widgets/score/ViewportTool.java | 259 ------ .../widgets/waveform/WaveformListener.java | 27 - .../widgets/waveform/WaveformRowView.java | 167 ---- .../widgets/waveform/WaveformView.java | 470 ----------- app/.gitignore | 1 + app/build.gradle | 41 + app/proguard-rules.pro | 17 + .../levien/synthesizer/ApplicationTest.java | 13 + app/src/main/AndroidManifest.xml | 76 ++ .../synthesizer/android/AndroidGlue.java | 0 .../android/service/SynthesizerService.java | 10 - .../android/service/SynthesizerThread.java | 20 +- .../android/stats/JitterStats.java | 0 .../android/ui/PianoActivity2.java | 2 + .../android/ui/SettingsActivity.java | 0 .../synthesizer/android/ui/SynthActivity.java | 0 .../android/usb/UsbMidiDevice.java | 0 .../android/widgets/keyboard/KeySpec.java | 0 .../widgets/keyboard/KeyboardSpec.java | 0 .../widgets/keyboard/KeyboardView.java | 0 .../widgets/keyboard/ScrollStripView.java | 0 .../android/widgets/knob/KnobListener.java | 0 .../widgets/knob/KnobPlaceholderView.java | 0 .../android/widgets/knob/KnobPreference.java | 0 .../android/widgets/knob/KnobView.java | 33 - .../core/midi/MessageFromBytes.java | 0 .../core/midi/MessageInputProcessor.java | 0 .../core/midi/MessageOutputProcessor.java | 0 .../synthesizer/core/midi/MessageTee.java | 0 .../synthesizer/core/midi/MidiAdapter.java | 0 .../core/midi/MidiChannelFilter.java | 0 .../synthesizer/core/midi/MidiEvent.java | 0 .../synthesizer/core/midi/MidiFile.java | 0 .../synthesizer/core/midi/MidiFilePlayer.java | 0 .../synthesizer/core/midi/MidiHeader.java | 0 .../synthesizer/core/midi/MidiListener.java | 0 .../core/midi/MidiListenerProxy.java | 0 .../synthesizer/core/midi/MidiReader.java | 0 .../synthesizer/core/midi/MidiTrack.java | 0 .../synthesizer/core/midi/MidiUtil.java | 0 {cpp/src => app/src/main/jni}/SynthApp.gyp | 0 .../jni}/SynthApp.xcodeproj/project.pbxproj | 0 .../SynthApp/English.lproj/InfoPlist.strings | 0 .../jni}/SynthApp/English.lproj/MainMenu.xib | 0 .../src/main/jni}/SynthApp/Synth-Info.plist | 0 .../src/main/jni}/SynthApp/SynthAppDelegate.h | 0 .../main/jni}/SynthApp/SynthAppDelegate.mm | 0 .../main/jni}/SynthApp/SynthApp_Prefix.pch | 0 .../src/main/jni}/SynthApp/SynthMain.h | 0 .../src/main/jni}/SynthApp/SynthMain.mm | 0 {cpp/src => app/src/main/jni}/SynthApp/main.m | 0 .../src/main/jni}/SynthApp/midi_in_mac.cc | 0 .../src/main/jni}/SynthApp/midi_in_mac.h | 0 {cpp/src => app/src/main/jni}/aligned_buf.h | 0 {cpp/src => app/src/main/jni}/android_glue.cc | 0 {cpp/src => app/src/main/jni}/controllers.h | 0 {cpp/src => app/src/main/jni}/core.gyp | 0 .../main/jni}/core.xcodeproj/project.pbxproj | 0 {cpp/src => app/src/main/jni}/dx7note.cc | 0 {cpp/src => app/src/main/jni}/dx7note.h | 0 {cpp/src => app/src/main/jni}/env.cc | 0 {cpp/src => app/src/main/jni}/env.h | 0 {cpp/src => app/src/main/jni}/exp2.cc | 0 {cpp/src => app/src/main/jni}/exp2.h | 0 {cpp/src => app/src/main/jni}/fir.cc | 0 {cpp/src => app/src/main/jni}/fir.h | 0 {cpp/src => app/src/main/jni}/fm_core.cc | 0 {cpp/src => app/src/main/jni}/fm_core.h | 0 {cpp/src => app/src/main/jni}/fm_op_kernel.cc | 0 {cpp/src => app/src/main/jni}/fm_op_kernel.h | 0 {cpp/src => app/src/main/jni}/freqlut.cc | 0 {cpp/src => app/src/main/jni}/freqlut.h | 0 {cpp/src => app/src/main/jni}/lfo.cc | 0 {cpp/src => app/src/main/jni}/lfo.h | 0 {cpp/src => app/src/main/jni}/log2.cc | 0 {cpp/src => app/src/main/jni}/log2.h | 0 {cpp/src => app/src/main/jni}/main.cc | 0 {cpp/src => app/src/main/jni}/main.gyp | 0 {cpp/src => app/src/main/jni}/module.h | 0 {cpp/src => app/src/main/jni}/neon_fir.s | 0 .../src => app/src/main/jni}/neon_fm_kernel.s | 0 {cpp/src => app/src/main/jni}/neon_iir.s | 0 {cpp/src => app/src/main/jni}/neon_ladder.s | 0 {cpp/src => app/src/main/jni}/patch.cc | 0 {cpp/src => app/src/main/jni}/patch.h | 0 {cpp/src => app/src/main/jni}/pitchenv.cc | 0 {cpp/src => app/src/main/jni}/pitchenv.h | 0 {cpp/src => app/src/main/jni}/resofilter.cc | 0 {cpp/src => app/src/main/jni}/resofilter.h | 0 {cpp/src => app/src/main/jni}/ringbuffer.cc | 0 {cpp/src => app/src/main/jni}/ringbuffer.h | 0 {cpp/src => app/src/main/jni}/sawtooth.cc | 0 {cpp/src => app/src/main/jni}/sawtooth.h | 0 {cpp/src => app/src/main/jni}/sin.cc | 0 {cpp/src => app/src/main/jni}/sin.h | 0 {cpp/src => app/src/main/jni}/synth.h | 0 {cpp/src => app/src/main/jni}/synth_unit.cc | 0 {cpp/src => app/src/main/jni}/synth_unit.h | 0 {cpp/src => app/src/main/jni}/test_filter.cc | 0 {cpp/src => app/src/main/jni}/test_neon.cc | 0 .../src/main/jni}/test_ringbuffer.cc | 0 {cpp/src => app/src/main/jni}/wavout.cc | 0 {cpp/src => app/src/main/jni}/wavout.h | 0 .../src/main}/res/drawable-hdpi/add.png | Bin .../src/main}/res/drawable-hdpi/arrow.png | Bin .../src/main}/res/drawable-hdpi/bass.png | Bin .../main}/res/drawable-hdpi/closed_eye.png | Bin .../src/main}/res/drawable-hdpi/down.png | Bin .../src/main}/res/drawable-hdpi/drums.png | Bin .../main}/res/drawable-hdpi/eighth_note.png | Bin .../src/main}/res/drawable-hdpi/flute.png | Bin .../src/main}/res/drawable-hdpi/guitar.png | Bin .../src/main}/res/drawable-hdpi/half_note.png | Bin .../src/main}/res/drawable-hdpi/icon.png | Bin .../src/main}/res/drawable-hdpi/loop.png | Bin .../src/main}/res/drawable-hdpi/no_note.png | Bin .../src/main}/res/drawable-hdpi/open_eye.png | Bin .../src/main}/res/drawable-hdpi/play.png | Bin .../main}/res/drawable-hdpi/play_piano.png | Bin .../main}/res/drawable-hdpi/quarter_note.png | Bin .../res/drawable-hdpi/sixteenth_note.png | Bin .../src/main}/res/drawable-hdpi/stop.png | Bin .../res/drawable-hdpi/thirtysecond_note.png | Bin .../src/main}/res/drawable-hdpi/trash.png | Bin .../main}/res/drawable-hdpi/unknown_note.png | Bin .../src/main}/res/drawable-hdpi/up.png | Bin .../src/main}/res/drawable-hdpi/voice.png | Bin .../main}/res/drawable-hdpi/whole_note.png | Bin .../src/main}/res/drawable-hdpi/zoom.png | Bin .../src/main}/res/drawable-ldpi/icon.png | Bin .../src/main}/res/drawable-mdpi/icon.png | Bin .../src/main}/res/layout-sw600dp/piano2.xml | 0 .../src/main}/res/layout/amplification.xml | 0 .../src/main}/res/layout/chord_grid.xml | 0 .../src/main}/res/layout/effects.xml | 0 .../src/main}/res/layout/karplus_strong.xml | 0 .../main}/res/layout/knobpreflayout_va.xml | 0 .../main}/res/layout/knobpreflayout_vs.xml | 0 .../src/main}/res/layout/low_pass_filter.xml | 0 {android => app/src/main}/res/layout/main.xml | 0 .../src/main}/res/layout/oscillator.xml | 0 .../src/main}/res/layout/piano.xml | 0 .../src/main}/res/layout/piano2.xml | 0 .../src/main}/res/layout/score.xml | 0 .../src/main}/res/layout/tremolo.xml | 0 .../src/main}/res/layout/vibrato.xml | 0 .../src/main}/res/menu/options_menu.xml | 0 .../src/main}/res/menu/score_menu.xml | 0 .../src/main}/res/menu/synth_menu.xml | 0 {android => app/src/main}/res/raw/presets.txt | 0 {android => app/src/main}/res/raw/rom1a.syx | Bin .../src/main}/res/values-sw600dp/dimens.xml | 0 .../src/main}/res/values-v11/styles.xml | 0 .../src/main}/res/values/attrs.xml | 0 .../src/main}/res/values/dimens.xml | 0 .../src/main}/res/values/strings.xml | 0 .../src/main}/res/values/styles.xml | 0 .../src/main}/res/xml/device_filter.xml | 0 .../src/main}/res/xml/preferences.xml | 0 .../levien/synthesizer/ExampleUnitTest.java | 15 + build.gradle | 23 + build.xml | 62 -- core/.gitignore | 4 - core/build.xml | 73 -- .../core/model/CachedFrequencyProvider.java | 47 -- .../core/model/CachedSignalProvider.java | 48 -- .../synthesizer/core/model/Envelope.java | 35 - .../core/model/FrequencyProvider.java | 24 - .../core/model/SignalProvider.java | 27 - .../synthesizer/core/model/SynthesisTime.java | 75 -- .../core/model/SynthesizerInput.java | 75 -- .../synthesizer/core/model/WaveformInput.java | 123 --- .../core/model/composite/MidiSynthesizer.java | 79 -- .../composite/MultiChannelSynthesizer.java | 145 ---- .../composite/MultiTouchSynthesizer.java | 638 --------------- .../core/model/composite/Presets.proto | 115 --- .../core/model/modules/AdsrEnvelope.java | 178 ---- .../core/model/modules/Amplifier.java | 50 -- .../synthesizer/core/model/modules/Delay.java | 123 --- .../synthesizer/core/model/modules/Echo.java | 100 --- .../synthesizer/core/model/modules/Glide.java | 91 --- .../core/model/modules/LowPassFilter.java | 56 -- .../synthesizer/core/model/modules/Mixer.java | 58 -- .../core/model/modules/Tremolo.java | 48 -- .../synthesizer/core/model/modules/Tuner.java | 48 -- .../core/model/modules/WaveformSelector.java | 84 -- .../core/model/oscillator/DrawbarOrgan.java | 129 --- .../core/model/oscillator/KarplusStrong.java | 138 ---- .../core/model/oscillator/Noise.java | 33 - .../core/model/oscillator/Oscillator.java | 35 - .../core/model/oscillator/Sawtooth.java | 51 -- .../core/model/oscillator/Sine.java | 61 -- .../core/model/oscillator/Square.java | 41 - .../core/model/oscillator/Triangle.java | 37 - .../core/music/EventComparator.java | 80 -- .../levien/synthesizer/core/music/Music.proto | 75 -- .../levien/synthesizer/core/music/Note.java | 94 --- .../synthesizer/core/music/ScorePlayer.java | 292 ------- .../core/music/ScorePlayerListener.java | 39 - .../synthesizer/core/soundfont/Bag.java | 96 --- .../synthesizer/core/soundfont/Generator.java | 62 -- .../core/soundfont/Instrument.java | 78 -- .../synthesizer/core/soundfont/Modulator.java | 53 -- .../core/soundfont/ModulatorSource.java | 50 -- .../synthesizer/core/soundfont/Operator.java | 146 ---- .../synthesizer/core/soundfont/Preset.java | 93 --- .../synthesizer/core/soundfont/Sample.java | 119 --- .../core/soundfont/SampleLink.java | 60 -- .../core/soundfont/SoundFontOscillator.java | 216 ----- .../core/soundfont/SoundFontReader.java | 337 -------- .../synthesizer/core/soundfont/Zone.java | 530 ------------ .../core/wave/RiffInputStream.java | 180 ---- .../synthesizer/core/wave/WaveAdapter.java | 120 --- .../synthesizer/core/wave/WaveReader.java | 151 ---- .../synthesizer/core/wave/WaveWriter.java | 230 ------ cpp/README | 24 - gradle.properties | 18 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 160 ++++ gradlew.bat | 90 ++ j2se/.classpath | 11 - .../Proto Builder.launch | 10 - j2se/.gitignore | 2 - j2se/.project | 49 -- j2se/build.xml | 58 -- .../src/com/levien/synthesizer/j2se/Midi.java | 116 --- .../synthesizer/j2se/MidiDeviceBinder.java | 116 --- .../com/levien/synthesizer/j2se/Perform.java | 212 ----- .../synthesizer/j2se/SynthesizerThread.java | 263 ------ settings.gradle | 1 + test/.gitignore | 2 - test/build.xml | 71 -- test/lib/junit-4.8.2.jar | Bin 253160 -> 0 bytes .../model/modules/test/AdsrEnvelopeTest.java | 251 ------ .../model/modules/test/AmplifierTest.java | 39 - .../core/model/modules/test/DelayTest.java | 109 --- .../core/model/modules/test/EchoTest.java | 70 -- .../core/model/modules/test/GlideTest.java | 78 -- .../core/model/modules/test/MixerTest.java | 60 -- .../core/model/modules/test/TremoloTest.java | 163 ---- .../core/model/modules/test/TunerTest.java | 74 -- .../model/oscillator/test/OscillatorTest.java | 39 - .../model/oscillator/test/SawtoothTest.java | 94 --- .../core/model/oscillator/test/SineTest.java | 87 -- .../model/oscillator/test/SquareTest.java | 93 --- .../model/oscillator/test/TriangleTest.java | 94 --- .../test/CachedFrequencyProviderTest.java | 61 -- .../model/test/CachedSignalProviderTest.java | 61 -- .../core/model/test/SynthesisTimeTest.java | 88 -- .../core/model/test/SynthesizerInputTest.java | 84 -- 308 files changed, 603 insertions(+), 15488 deletions(-) create mode 100644 .gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml delete mode 100644 android/.classpath delete mode 100644 android/.externalToolBuilders/NDK Builder.launch delete mode 100644 android/.externalToolBuilders/Proto Builder.launch delete mode 100644 android/.gitignore delete mode 100644 android/.project delete mode 100644 android/.settings/org.eclipse.jdt.core.prefs delete mode 100644 android/.settings/org.eclipse.jdt.ui.prefs delete mode 100644 android/AndroidManifest.xml delete mode 100644 android/default.properties delete mode 100644 android/jni/Android.mk delete mode 100644 android/jni/Application.mk delete mode 100644 android/project.properties delete mode 100644 android/src/com/levien/synthesizer/android/Storage.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/EffectsActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/MainActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/PianoActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/ScoreActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/TremoloActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/ui/VibratoActivity.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/ChordGridView.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java delete mode 100644 android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java create mode 100644 app/src/main/AndroidManifest.xml rename {android/src => app/src/main/java}/com/levien/synthesizer/android/AndroidGlue.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/service/SynthesizerService.java (97%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/service/SynthesizerThread.java (90%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/stats/JitterStats.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/ui/PianoActivity2.java (99%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/ui/SettingsActivity.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/ui/SynthActivity.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/usb/UsbMidiDevice.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/knob/KnobListener.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/knob/KnobPreference.java (100%) rename {android/src => app/src/main/java}/com/levien/synthesizer/android/widgets/knob/KnobView.java (88%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MessageFromBytes.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MessageInputProcessor.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MessageOutputProcessor.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MessageTee.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiAdapter.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiChannelFilter.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiEvent.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiFile.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiFilePlayer.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiHeader.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiListener.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiListenerProxy.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiReader.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiTrack.java (100%) rename {core/src => app/src/main/java}/com/levien/synthesizer/core/midi/MidiUtil.java (100%) rename {cpp/src => app/src/main/jni}/SynthApp.gyp (100%) rename {cpp/src => app/src/main/jni}/SynthApp.xcodeproj/project.pbxproj (100%) rename {cpp/src => app/src/main/jni}/SynthApp/English.lproj/InfoPlist.strings (100%) rename {cpp/src => app/src/main/jni}/SynthApp/English.lproj/MainMenu.xib (100%) rename {cpp/src => app/src/main/jni}/SynthApp/Synth-Info.plist (100%) rename {cpp/src => app/src/main/jni}/SynthApp/SynthAppDelegate.h (100%) rename {cpp/src => app/src/main/jni}/SynthApp/SynthAppDelegate.mm (100%) rename {cpp/src => app/src/main/jni}/SynthApp/SynthApp_Prefix.pch (100%) rename {cpp/src => app/src/main/jni}/SynthApp/SynthMain.h (100%) rename {cpp/src => app/src/main/jni}/SynthApp/SynthMain.mm (100%) rename {cpp/src => app/src/main/jni}/SynthApp/main.m (100%) rename {cpp/src => app/src/main/jni}/SynthApp/midi_in_mac.cc (100%) rename {cpp/src => app/src/main/jni}/SynthApp/midi_in_mac.h (100%) rename {cpp/src => app/src/main/jni}/aligned_buf.h (100%) rename {cpp/src => app/src/main/jni}/android_glue.cc (100%) rename {cpp/src => app/src/main/jni}/controllers.h (100%) rename {cpp/src => app/src/main/jni}/core.gyp (100%) rename {cpp/src => app/src/main/jni}/core.xcodeproj/project.pbxproj (100%) rename {cpp/src => app/src/main/jni}/dx7note.cc (100%) rename {cpp/src => app/src/main/jni}/dx7note.h (100%) rename {cpp/src => app/src/main/jni}/env.cc (100%) rename {cpp/src => app/src/main/jni}/env.h (100%) rename {cpp/src => app/src/main/jni}/exp2.cc (100%) rename {cpp/src => app/src/main/jni}/exp2.h (100%) rename {cpp/src => app/src/main/jni}/fir.cc (100%) rename {cpp/src => app/src/main/jni}/fir.h (100%) rename {cpp/src => app/src/main/jni}/fm_core.cc (100%) rename {cpp/src => app/src/main/jni}/fm_core.h (100%) rename {cpp/src => app/src/main/jni}/fm_op_kernel.cc (100%) rename {cpp/src => app/src/main/jni}/fm_op_kernel.h (100%) rename {cpp/src => app/src/main/jni}/freqlut.cc (100%) rename {cpp/src => app/src/main/jni}/freqlut.h (100%) rename {cpp/src => app/src/main/jni}/lfo.cc (100%) rename {cpp/src => app/src/main/jni}/lfo.h (100%) rename {cpp/src => app/src/main/jni}/log2.cc (100%) rename {cpp/src => app/src/main/jni}/log2.h (100%) rename {cpp/src => app/src/main/jni}/main.cc (100%) rename {cpp/src => app/src/main/jni}/main.gyp (100%) rename {cpp/src => app/src/main/jni}/module.h (100%) rename {cpp/src => app/src/main/jni}/neon_fir.s (100%) rename {cpp/src => app/src/main/jni}/neon_fm_kernel.s (100%) rename {cpp/src => app/src/main/jni}/neon_iir.s (100%) rename {cpp/src => app/src/main/jni}/neon_ladder.s (100%) rename {cpp/src => app/src/main/jni}/patch.cc (100%) rename {cpp/src => app/src/main/jni}/patch.h (100%) rename {cpp/src => app/src/main/jni}/pitchenv.cc (100%) rename {cpp/src => app/src/main/jni}/pitchenv.h (100%) rename {cpp/src => app/src/main/jni}/resofilter.cc (100%) rename {cpp/src => app/src/main/jni}/resofilter.h (100%) rename {cpp/src => app/src/main/jni}/ringbuffer.cc (100%) rename {cpp/src => app/src/main/jni}/ringbuffer.h (100%) rename {cpp/src => app/src/main/jni}/sawtooth.cc (100%) rename {cpp/src => app/src/main/jni}/sawtooth.h (100%) rename {cpp/src => app/src/main/jni}/sin.cc (100%) rename {cpp/src => app/src/main/jni}/sin.h (100%) rename {cpp/src => app/src/main/jni}/synth.h (100%) rename {cpp/src => app/src/main/jni}/synth_unit.cc (100%) rename {cpp/src => app/src/main/jni}/synth_unit.h (100%) rename {cpp/src => app/src/main/jni}/test_filter.cc (100%) rename {cpp/src => app/src/main/jni}/test_neon.cc (100%) rename {cpp/src => app/src/main/jni}/test_ringbuffer.cc (100%) rename {cpp/src => app/src/main/jni}/wavout.cc (100%) rename {cpp/src => app/src/main/jni}/wavout.h (100%) rename {android => app/src/main}/res/drawable-hdpi/add.png (100%) rename {android => app/src/main}/res/drawable-hdpi/arrow.png (100%) rename {android => app/src/main}/res/drawable-hdpi/bass.png (100%) rename {android => app/src/main}/res/drawable-hdpi/closed_eye.png (100%) rename {android => app/src/main}/res/drawable-hdpi/down.png (100%) rename {android => app/src/main}/res/drawable-hdpi/drums.png (100%) rename {android => app/src/main}/res/drawable-hdpi/eighth_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/flute.png (100%) rename {android => app/src/main}/res/drawable-hdpi/guitar.png (100%) rename {android => app/src/main}/res/drawable-hdpi/half_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/icon.png (100%) rename {android => app/src/main}/res/drawable-hdpi/loop.png (100%) rename {android => app/src/main}/res/drawable-hdpi/no_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/open_eye.png (100%) rename {android => app/src/main}/res/drawable-hdpi/play.png (100%) rename {android => app/src/main}/res/drawable-hdpi/play_piano.png (100%) rename {android => app/src/main}/res/drawable-hdpi/quarter_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/sixteenth_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/stop.png (100%) rename {android => app/src/main}/res/drawable-hdpi/thirtysecond_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/trash.png (100%) rename {android => app/src/main}/res/drawable-hdpi/unknown_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/up.png (100%) rename {android => app/src/main}/res/drawable-hdpi/voice.png (100%) rename {android => app/src/main}/res/drawable-hdpi/whole_note.png (100%) rename {android => app/src/main}/res/drawable-hdpi/zoom.png (100%) rename {android => app/src/main}/res/drawable-ldpi/icon.png (100%) rename {android => app/src/main}/res/drawable-mdpi/icon.png (100%) rename {android => app/src/main}/res/layout-sw600dp/piano2.xml (100%) rename {android => app/src/main}/res/layout/amplification.xml (100%) rename {android => app/src/main}/res/layout/chord_grid.xml (100%) rename {android => app/src/main}/res/layout/effects.xml (100%) rename {android => app/src/main}/res/layout/karplus_strong.xml (100%) rename {android => app/src/main}/res/layout/knobpreflayout_va.xml (100%) rename {android => app/src/main}/res/layout/knobpreflayout_vs.xml (100%) rename {android => app/src/main}/res/layout/low_pass_filter.xml (100%) rename {android => app/src/main}/res/layout/main.xml (100%) rename {android => app/src/main}/res/layout/oscillator.xml (100%) rename {android => app/src/main}/res/layout/piano.xml (100%) rename {android => app/src/main}/res/layout/piano2.xml (100%) rename {android => app/src/main}/res/layout/score.xml (100%) rename {android => app/src/main}/res/layout/tremolo.xml (100%) rename {android => app/src/main}/res/layout/vibrato.xml (100%) rename {android => app/src/main}/res/menu/options_menu.xml (100%) rename {android => app/src/main}/res/menu/score_menu.xml (100%) rename {android => app/src/main}/res/menu/synth_menu.xml (100%) rename {android => app/src/main}/res/raw/presets.txt (100%) rename {android => app/src/main}/res/raw/rom1a.syx (100%) rename {android => app/src/main}/res/values-sw600dp/dimens.xml (100%) rename {android => app/src/main}/res/values-v11/styles.xml (100%) rename {android => app/src/main}/res/values/attrs.xml (100%) rename {android => app/src/main}/res/values/dimens.xml (100%) rename {android => app/src/main}/res/values/strings.xml (100%) rename {android => app/src/main}/res/values/styles.xml (100%) rename {android => app/src/main}/res/xml/device_filter.xml (100%) rename {android => app/src/main}/res/xml/preferences.xml (100%) create mode 100644 app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java create mode 100644 build.gradle delete mode 100644 build.xml delete mode 100644 core/.gitignore delete mode 100644 core/build.xml delete mode 100644 core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java delete mode 100644 core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java delete mode 100755 core/src/com/levien/synthesizer/core/model/Envelope.java delete mode 100644 core/src/com/levien/synthesizer/core/model/FrequencyProvider.java delete mode 100644 core/src/com/levien/synthesizer/core/model/SignalProvider.java delete mode 100644 core/src/com/levien/synthesizer/core/model/SynthesisTime.java delete mode 100644 core/src/com/levien/synthesizer/core/model/SynthesizerInput.java delete mode 100644 core/src/com/levien/synthesizer/core/model/WaveformInput.java delete mode 100644 core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java delete mode 100644 core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java delete mode 100644 core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java delete mode 100644 core/src/com/levien/synthesizer/core/model/composite/Presets.proto delete mode 100644 core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java delete mode 100755 core/src/com/levien/synthesizer/core/model/modules/Amplifier.java delete mode 100755 core/src/com/levien/synthesizer/core/model/modules/Delay.java delete mode 100755 core/src/com/levien/synthesizer/core/model/modules/Echo.java delete mode 100644 core/src/com/levien/synthesizer/core/model/modules/Glide.java delete mode 100644 core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java delete mode 100755 core/src/com/levien/synthesizer/core/model/modules/Mixer.java delete mode 100644 core/src/com/levien/synthesizer/core/model/modules/Tremolo.java delete mode 100644 core/src/com/levien/synthesizer/core/model/modules/Tuner.java delete mode 100644 core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java delete mode 100644 core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java delete mode 100644 core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java delete mode 100755 core/src/com/levien/synthesizer/core/model/oscillator/Noise.java delete mode 100755 core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java delete mode 100755 core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java delete mode 100755 core/src/com/levien/synthesizer/core/model/oscillator/Sine.java delete mode 100755 core/src/com/levien/synthesizer/core/model/oscillator/Square.java delete mode 100755 core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java delete mode 100644 core/src/com/levien/synthesizer/core/music/EventComparator.java delete mode 100644 core/src/com/levien/synthesizer/core/music/Music.proto delete mode 100755 core/src/com/levien/synthesizer/core/music/Note.java delete mode 100644 core/src/com/levien/synthesizer/core/music/ScorePlayer.java delete mode 100644 core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Bag.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Generator.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Instrument.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Modulator.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Operator.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Preset.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Sample.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/SampleLink.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java delete mode 100644 core/src/com/levien/synthesizer/core/soundfont/Zone.java delete mode 100644 core/src/com/levien/synthesizer/core/wave/RiffInputStream.java delete mode 100644 core/src/com/levien/synthesizer/core/wave/WaveAdapter.java delete mode 100644 core/src/com/levien/synthesizer/core/wave/WaveReader.java delete mode 100644 core/src/com/levien/synthesizer/core/wave/WaveWriter.java delete mode 100644 cpp/README create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat delete mode 100644 j2se/.classpath delete mode 100644 j2se/.externalToolBuilders/Proto Builder.launch delete mode 100644 j2se/.gitignore delete mode 100644 j2se/.project delete mode 100644 j2se/build.xml delete mode 100755 j2se/src/com/levien/synthesizer/j2se/Midi.java delete mode 100644 j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java delete mode 100644 j2se/src/com/levien/synthesizer/j2se/Perform.java delete mode 100755 j2se/src/com/levien/synthesizer/j2se/SynthesizerThread.java create mode 100644 settings.gradle delete mode 100644 test/.gitignore delete mode 100644 test/build.xml delete mode 100644 test/lib/junit-4.8.2.jar delete mode 100755 test/src/com/levien/synthesizer/core/model/modules/test/AdsrEnvelopeTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/modules/test/AmplifierTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/modules/test/DelayTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/modules/test/EchoTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/modules/test/GlideTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/modules/test/MixerTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/modules/test/TremoloTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/modules/test/TunerTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/oscillator/test/OscillatorTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/oscillator/test/SawtoothTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/oscillator/test/SineTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/oscillator/test/SquareTest.java delete mode 100755 test/src/com/levien/synthesizer/core/model/oscillator/test/TriangleTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/test/CachedFrequencyProviderTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/test/CachedSignalProviderTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/test/SynthesisTimeTest.java delete mode 100644 test/src/com/levien/synthesizer/core/model/test/SynthesizerInputTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..b608edd --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +Music Synthesizer \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..508b3d9 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..37a85bd --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/.classpath b/android/.classpath deleted file mode 100644 index bea3b48..0000000 --- a/android/.classpath +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/android/.externalToolBuilders/NDK Builder.launch b/android/.externalToolBuilders/NDK Builder.launch deleted file mode 100644 index 18993b1..0000000 --- a/android/.externalToolBuilders/NDK Builder.launch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/android/.externalToolBuilders/Proto Builder.launch b/android/.externalToolBuilders/Proto Builder.launch deleted file mode 100644 index 18b99a6..0000000 --- a/android/.externalToolBuilders/Proto Builder.launch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/android/.gitignore b/android/.gitignore deleted file mode 100644 index 67a5cb9..0000000 --- a/android/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Android NDK output files -obj/** -libs/** \ No newline at end of file diff --git a/android/.project b/android/.project deleted file mode 100644 index 6c6f44d..0000000 --- a/android/.project +++ /dev/null @@ -1,75 +0,0 @@ - - - MusicSynthesizer - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Proto Builder.launch - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/NDK Builder.launch - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - - - core - 2 - PARENT-1-PROJECT_LOC/core/src - - - core-gen - 2 - PARENT-1-PROJECT_LOC/core/gen - - - core-lib - 2 - PARENT-1-PROJECT_LOC/core/lib - - - test - 2 - PARENT-1-PROJECT_LOC/test/src - - - diff --git a/android/.settings/org.eclipse.jdt.core.prefs b/android/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 5c9506e..0000000 --- a/android/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,280 +0,0 @@ -#Thu Jan 27 01:33:26 PST 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 -org.eclipse.jdt.core.formatter.align_type_members_on_columns=false -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_assignment=0 -org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 -org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 -org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 -org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=0 -org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 -org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 -org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 -org.eclipse.jdt.core.formatter.blank_lines_before_method=1 -org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 -org.eclipse.jdt.core.formatter.blank_lines_before_package=0 -org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 -org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 -org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false -org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false -org.eclipse.jdt.core.formatter.comment.format_block_comments=true -org.eclipse.jdt.core.formatter.comment.format_header=false -org.eclipse.jdt.core.formatter.comment.format_html=true -org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true -org.eclipse.jdt.core.formatter.comment.format_line_comments=true -org.eclipse.jdt.core.formatter.comment.format_source_code=true -org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true -org.eclipse.jdt.core.formatter.comment.indent_root_tags=true -org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert -org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert -org.eclipse.jdt.core.formatter.comment.line_length=100 -org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true -org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true -org.eclipse.jdt.core.formatter.compact_else_if=true -org.eclipse.jdt.core.formatter.continuation_indentation=4 -org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 -org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off -org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on -org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true -org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true -org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_empty_lines=false -org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true -org.eclipse.jdt.core.formatter.indentation.size=2 -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=do not insert -org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert -org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert -org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert -org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert -org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert -org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert -org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.jdt.core.formatter.join_lines_in_comments=true -org.eclipse.jdt.core.formatter.join_wrapped_lines=true -org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true -org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true -org.eclipse.jdt.core.formatter.lineSplit=100 -org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false -org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false -org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 -org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.jdt.core.formatter.tabulation.char=space -org.eclipse.jdt.core.formatter.tabulation.size=2 -org.eclipse.jdt.core.formatter.use_on_off_tags=false -org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true -org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/android/.settings/org.eclipse.jdt.ui.prefs b/android/.settings/org.eclipse.jdt.ui.prefs deleted file mode 100644 index a26edcc..0000000 --- a/android/.settings/org.eclipse.jdt.ui.prefs +++ /dev/null @@ -1,8 +0,0 @@ -#Thu Jan 27 01:35:20 PST 2011 -eclipse.preferences.version=1 -formatter_profile=_MusicSynthesizer -formatter_settings_version=11 -org.eclipse.jdt.ui.ignorelowercasenames=true -org.eclipse.jdt.ui.importorder=java;javax;org;com; -org.eclipse.jdt.ui.ondemandthreshold=99 -org.eclipse.jdt.ui.staticondemandthreshold=99 diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml deleted file mode 100644 index 82fc6fb..0000000 --- a/android/AndroidManifest.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/default.properties b/android/default.properties deleted file mode 100644 index 4686f7f..0000000 --- a/android/default.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Project target. -target=android-9 diff --git a/android/jni/Android.mk b/android/jni/Android.mk deleted file mode 100644 index 1c3e7ea..0000000 --- a/android/jni/Android.mk +++ /dev/null @@ -1,88 +0,0 @@ -LOCAL_PATH := $(call my-dir)/../../cpp/src - -include $(CLEAR_VARS) -LOCAL_MODULE := synth -LOCAL_CPP_EXTENSION := .cc -LOCAL_SRC_FILES := android_glue.cc \ - dx7note.cc \ - env.cc \ - exp2.cc \ - fir.cc \ - fm_core.cc \ - fm_op_kernel.cc \ - freqlut.cc \ - lfo.cc \ - patch.cc \ - pitchenv.cc \ - resofilter.cc \ - ringbuffer.cc \ - sawtooth.cc \ - sin.cc \ - synth_unit.cc - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS := -DHAVE_NEON=1 - LOCAL_SRC_FILES += neon_fm_kernel.s \ - neon_ladder.s \ - neon_fir.s -endif - -# for native audio -LOCAL_LDLIBS += -lOpenSLES -# for logging -LOCAL_LDLIBS += -llog - -LOCAL_STATIC_LIBRARIES += cpufeatures - -LOCAL_CFLAGS += -O3 - -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := test_neon.cc \ - resofilter.cc - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS := -DHAVE_NEON=1 - LOCAL_SRC_FILES += neon_fm_kernel.s \ - neon_ladder.s \ - neon_fir.s -endif - -LOCAL_CFLAGS += -O3 - -LOCAL_STATIC_LIBRARIES += cpufeatures - -LOCAL_MODULE := test_neon - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := test_filter.cc \ - fir.cc \ - sawtooth.cc \ - exp2.cc \ - sin.cc \ - fm_op_kernel.cc \ - resofilter.cc \ - freqlut.cc - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_ARM_NEON := true - LOCAL_CFLAGS := -DHAVE_NEON=1 - LOCAL_SRC_FILES += neon_fir.s \ - neon_iir.s \ - neon_fm_kernel.s \ - neon_ladder.s -endif - -LOCAL_CFLAGS += -O3 -LOCAL_STATIC_LIBRARIES += cpufeatures -LOCAL_MODULE := test_filter -include $(BUILD_EXECUTABLE) - - -$(call import-module,android/cpufeatures) diff --git a/android/jni/Application.mk b/android/jni/Application.mk deleted file mode 100644 index 3d53443..0000000 --- a/android/jni/Application.mk +++ /dev/null @@ -1,2 +0,0 @@ -APP_ABI := all - diff --git a/android/project.properties b/android/project.properties deleted file mode 100644 index a3ee5ab..0000000 --- a/android/project.properties +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 diff --git a/android/src/com/levien/synthesizer/android/Storage.java b/android/src/com/levien/synthesizer/android/Storage.java deleted file mode 100644 index de4cf81..0000000 --- a/android/src/com/levien/synthesizer/android/Storage.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Environment; -import android.widget.EditText; -import android.widget.Toast; - -import com.levien.synthesizer.core.music.Music.Score; - -/** - * A collection of functions for storing and retrieving scores. - */ -public class Storage { - /** - * Opens the score stored with the name "_default", which should always be the current score - * being edited. This may be called at any time to restore saved state, since Android Activities - * can come and go. - * - * @param score - The mutable score to populate with the stored data. - * @param context - Android application context. - */ - public static void openDefaultScore(Score.Builder score, Context context) throws IOException { - openScore(score, "_default", context); - } - - /** - * Saves a score with the name "_default", which should always be the current score being edited. - * This may be called at any time to save state, since Android Activities can come and go. - * - * @param score - The score data to save. - * @param context - Android application context. - */ - public static void saveDefaultScore(Score score, Context context) throws IOException { - saveScore(score, "_default", true, context); - } - - /** - * Opens the score with the given name. The name should be name of a valid score file in storage. - * The file must be in the root external files directory for the app. - * - * @param score - The mutable score to update with the data from storage. - * @param name - The name of the file, minus the ".pb" extension. - * @param context - The Android application context. - */ - public static void openScore(Score.Builder score, String name, Context context) throws IOException { - if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && - !Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())) { - throw new IOException("External storage is not readable."); - } - File path = context.getExternalFilesDir(null); - File file = new File(path, name + ".pb"); - FileInputStream in = new FileInputStream(file); - score.clear(); - score.mergeFrom(in); - in.close(); - } - - /** - * Saves the score with the given name. Files are stored in the root external files directory for - * the app. - * - * @param score - The score to save. - * @param name - The name of the file, without any extension. - * @param overwrite - If true, replace the existing file, if one already exists. - * @param context - The Android application context. - * @throws IOException - On any kind of IO error, or if name is "", or the file already exists. - */ - public static void saveScore(Score score, - String name, - boolean overwrite, - Context context) throws IOException { - if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { - throw new IOException("External storage is not writeable."); - } - File path = context.getExternalFilesDir(null); - name = cleanupName(name); - if (name.length() == 0) { - throw new IOException("Can't save score without a name."); - } - File file = new File(path, name + ".pb"); - if (!overwrite && file.exists()) { - throw new IOException("File already exists."); - } - FileOutputStream out = new FileOutputStream(file); - score.writeTo(out); - out.close(); - } - - /** - * Returns the list of all valid names of scores that are currently in storage. - */ - public static String[] getScoreNames(Context context) throws IOException { - if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && - !Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())) { - throw new IOException("External storage is not readable."); - } - File path = context.getExternalFilesDir(null); - File[] files = path.listFiles(); - ArrayList names = new ArrayList(); - for (File file : files) { - names.add(file.getName().replaceAll("\\.pb", "")); - } - return names.toArray(new String[0]); - } - - /** - * Returns true iff there is a score in storage with the given name. - */ - public static boolean scoreExists(String name, Context context) throws IOException { - String[] names = getScoreNames(context); - for (String existingName : names) { - if (name.equals(existingName)) { - return true; - } - } - return false; - } - - /** - * Interface used to notify callers of openScoreWithDialog() when the opening has completed. - */ - public interface OpenScoreListener { - void onOpenScore(Score.Builder score); - } - - /** - * Shows UI to allow the user to pick one of the current scores in storage, and then populates - * score with the data from that file. - * - * @param score - The mutable score to update. - * @param listener - A listener that is notified after the score is updated. Can be null. - * @param context - An Android application context. - */ - public static void openScoreWithDialog(final Score.Builder score, - final OpenScoreListener listener, - final Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Open score..."); - try { - final String[] scoreNames = getScoreNames(context); - builder.setItems(scoreNames, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - try { - openScore(score, scoreNames[which], context); - if (listener != null) { - listener.onOpenScore(score); - } - dialog.dismiss(); - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error opening score \"" + scoreNames[which] + "\" with dialog.", e); - Toast.makeText(context, - "Unable to open \"" + scoreNames[which] + "\".", - Toast.LENGTH_SHORT).show(); - } - } - }); - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error getting score names.", e); - Toast.makeText(context, - "Unable to get existing score names.", - Toast.LENGTH_SHORT).show(); - } - AlertDialog dialog = builder.create(); - dialog.show(); - } - - /** - * Shows UI to allow the user to pick a name and save the given score in storage. - * - * @param score - The score to save. - * @param context - An Android application context. - */ - public static void saveScoreWithDialog(final Score score, - final Context context) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Save score as..."); - builder.setMessage("Name: "); - final EditText input = new EditText(context); - builder.setView(input); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(final DialogInterface nameDialog, int which) { - final String name = cleanupName(input.getText().toString()); - if (name.length() == 0) { - Toast.makeText(context, - "Name must not be empty.", - Toast.LENGTH_SHORT).show(); - } else { - try { - if (scoreExists(name, context)) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle("Overwrite?"); - builder.setMessage( - "A score named " + name + " already exists. Would you like to overwrite it?"); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface confirmDialog, int which) { - try { - saveScore(score, name, true, context); - confirmDialog.dismiss(); - nameDialog.dismiss(); - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error saving score \"" + name + "\" with dialog.", e); - Toast.makeText(context, - "Unable to save \"" + name + "\".", - Toast.LENGTH_SHORT).show(); - } - } - }); - builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - AlertDialog confirmDialog = builder.create(); - confirmDialog.show(); - } else { - saveScore(score, name, false, context); - nameDialog.dismiss(); - } - } catch (IOException e) { - Logger logger = Logger.getLogger(Storage.class.getName()); - logger.log(Level.SEVERE, - "Error saving score \"" + name + "\" with dialog.", e); - Toast.makeText(context, - "Unable to save \"" + name + "\".", - Toast.LENGTH_SHORT).show(); - } - } - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - /** - * Internal method to turn a user input string into a valid file name. - */ - private static String cleanupName(String name) { - name = name.trim(); - name = name.replaceAll("[^A-Za-z0-9_-]", "_"); - return name; - } -} diff --git a/android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java b/android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java deleted file mode 100644 index f7ccd9e..0000000 --- a/android/src/com/levien/synthesizer/android/ui/AmplificationActivity.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying amplification/adsr envelope. - * TODO(klimt): Add the ability to switch channels. - */ -public class AmplificationActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.amplification); - - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - volumeKnob_ = (KnobView)findViewById(R.id.volumeKnob); - piano_ = (PianoView)findViewById(R.id.piano); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - attackKnob_.bindTo(synthesizer_, channel, Setting.ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.RELEASE); - volumeKnob_.bindTo(synthesizer_, channel, Setting.VOLUME); - piano_.bindTo(synthesizer_, channel); - } - - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; - private KnobView volumeKnob_; - private PianoView piano_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java b/android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java deleted file mode 100644 index d9195c6..0000000 --- a/android/src/com/levien/synthesizer/android/ui/ChordGridActivity.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Spinner; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.android.widgets.ChordGridView; - -/** - * Activity for playing whole chords at a time, arranged in a circle of fifths. - */ -public class ChordGridActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.chord_grid); - - chordGrid_ = (ChordGridView)findViewById(R.id.chord_grid); - presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); - - presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (synthesizer_ == null) { - return; - } - if (position > 0) { - chordGrid_.bindTo(synthesizer_, position - 1); - } - } - public void onNothingSelected(AdapterView parent) { - } - }); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - chordGrid_.bindTo(synthesizer_, 0); - - ArrayList presetNames = new ArrayList(); - presetNames.add(""); - synthesizer_.getPresetNames(presetNames); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_spinner_item, presetNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - presetSpinner_.setAdapter(adapter); - } - - private ChordGridView chordGrid_; - private Spinner presetSpinner_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java b/android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java deleted file mode 100644 index cc4a8e2..0000000 --- a/android/src/com/levien/synthesizer/android/ui/EditInstrumentActivity.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.IBinder; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.service.SynthesizerService; - -/** - * An Activity to let the user choose a subset of a presets settings in order to edit them. - */ -public class EditInstrumentActivity extends ListActivity { - @Override - protected void onCreate(Bundle savedInstanceState){ - super.onCreate(savedInstanceState); - String[] sections = getResources().getStringArray(R.array.sections); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_list_item_1, sections); - setListAdapter(adapter); - } - - @Override - protected void onStart() { - super.onStart(); - bindService(new Intent(this, SynthesizerService.class), - synthesizerConnection_, Context.BIND_AUTO_CREATE); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(synthesizerConnection_); - } - - @Override - protected void onListItemClick(ListView list, View view, int position, long id) { - int channel = SynthesizerActivity.getIntentChannel(this); - switch (position) { - case 0: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - VibratoActivity.class)); - break; - case 1: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_1_WAVEFORM, - Setting.OSCILLATOR_1_GLIDE, - Setting.OSCILLATOR_1_COARSE, - Setting.OSCILLATOR_1_FINE, - Setting.OSCILLATOR_1_VIBRATO, - Setting.BALANCE), - this, OscillatorActivity.class)); - break; - case 2: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_2_WAVEFORM, - Setting.OSCILLATOR_2_GLIDE, - Setting.OSCILLATOR_2_COARSE, - Setting.OSCILLATOR_2_FINE, - Setting.OSCILLATOR_2_VIBRATO, - Setting.BALANCE), - this, OscillatorActivity.class)); - break; - case 3: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_1_BLEND, - Setting.OSCILLATOR_1_STRETCH, - Setting.OSCILLATOR_1_EXCITEMENT), - this, KarplusStrongActivity.class)); - break; - case 4: - this.startActivity(new Intent(null, SynthesizerActivity.makeUri( - channel, - Setting.OSCILLATOR_2_BLEND, - Setting.OSCILLATOR_2_STRETCH, - Setting.OSCILLATOR_2_EXCITEMENT), - this, KarplusStrongActivity.class)); - break; - case 5: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - TremoloActivity.class)); - break; - case 6: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - LowPassFilterActivity.class)); - break; - case 7: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - AmplificationActivity.class)); - break; - case 8: - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(channel), - this, - EffectsActivity.class)); - break; - } - } - - private ServiceConnection synthesizerConnection_ = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - } - public void onServiceDisconnected(ComponentName className) { - } - }; -} diff --git a/android/src/com/levien/synthesizer/android/ui/EffectsActivity.java b/android/src/com/levien/synthesizer/android/ui/EffectsActivity.java deleted file mode 100644 index 6d0c17f..0000000 --- a/android/src/com/levien/synthesizer/android/ui/EffectsActivity.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying effects like echo. - * TODO(klimt): Add the ability to switch channels. - */ -public class EffectsActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.effects); - - piano_ = (PianoView)findViewById(R.id.piano); - echoMixKnob_ = (KnobView)findViewById(R.id.echoMixKnob); - echoDelayKnob_ = (KnobView)findViewById(R.id.echoDelayKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - echoMixKnob_.bindTo(synthesizer_, channel, Setting.ECHO_MIX); - echoDelayKnob_.bindTo(synthesizer_, channel, Setting.ECHO_DELAY); - } - - private PianoView piano_; - private KnobView echoMixKnob_; - private KnobView echoDelayKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java b/android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java deleted file mode 100644 index 1941c95..0000000 --- a/android/src/com/levien/synthesizer/android/ui/InstrumentListActivity.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.android.service.SynthesizerService; - -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -/** - * An activity that shows the list of available presets (aka instruments), and let's the user click - * on one of them to begin editing it. - */ -public class InstrumentListActivity extends ListActivity { - @Override - protected void onStart() { - super.onStart(); - bindService(new Intent(this, SynthesizerService.class), - synthesizerConnection_, Context.BIND_AUTO_CREATE); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(synthesizerConnection_); - } - - @Override - protected void onListItemClick(ListView list, View view, int position, long id) { - this.startActivity(new Intent(null, - SynthesizerActivity.makeUri(position), - this, - EditInstrumentActivity.class)); - } - - private ServiceConnection synthesizerConnection_ = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - MultiChannelSynthesizer synthesizer = - ((SynthesizerService.LocalBinder)service).getSynthesizer(); - ArrayList presets = new ArrayList(); - synthesizer.getPresetNames(presets); - final ArrayAdapter adapter = new ArrayAdapter( - InstrumentListActivity.this, - android.R.layout.simple_list_item_1, - presets.toArray(new String[0])); - InstrumentListActivity.this.runOnUiThread(new Runnable() { - public void run() { - InstrumentListActivity.this.setListAdapter(adapter); - InstrumentListActivity.this.getListView().invalidate(); - } - }); - - } - public void onServiceDisconnected(ComponentName className) { - } - }; -} diff --git a/android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java b/android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java deleted file mode 100644 index 0ba5ee8..0000000 --- a/android/src/com/levien/synthesizer/android/ui/KarplusStrongActivity.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying Karplus-Strong parameters. - * TODO(klimt): Add the ability to switch channels. - */ -public class KarplusStrongActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.karplus_strong); - - piano_ = (PianoView)findViewById(R.id.piano); - blendKnob_ = (KnobView)findViewById(R.id.blendKnob); - stretchKnob_ = (KnobView)findViewById(R.id.stretchKnob); - excitementKnob_ = (KnobView)findViewById(R.id.excitementKnob); - - PianoView piano = (PianoView)findViewById(R.id.piano); - piano.bindTo(synthesizer_, 0); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - Setting[] settings = getIntentSettings(this); - piano_.bindTo(synthesizer_, channel); - blendKnob_.bindTo(synthesizer_, channel, settings[0]); - stretchKnob_.bindTo(synthesizer_, channel, settings[1]); - excitementKnob_.bindTo(synthesizer_, channel, settings[2]); - } - - private PianoView piano_; - private KnobView blendKnob_; - private KnobView stretchKnob_; - private KnobView excitementKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java b/android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java deleted file mode 100644 index d517c0b..0000000 --- a/android/src/com/levien/synthesizer/android/ui/LowPassFilterActivity.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for modifying low-pass filter settings. - * TODO(klimt): Add the ability to switch channels. - */ -public class LowPassFilterActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.low_pass_filter); - - piano_ = (PianoView)findViewById(R.id.piano); - cutoffKnob_ = (KnobView)findViewById(R.id.cutoffKnob); - depthKnob_ = (KnobView)findViewById(R.id.depthKnob); - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - - PianoView piano = (PianoView)findViewById(R.id.piano); - piano.bindTo(synthesizer_, 0); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - cutoffKnob_.bindTo(synthesizer_, channel, Setting.FILTER_CUTOFF); - depthKnob_.bindTo(synthesizer_, channel, Setting.FILTER_DEPTH); - attackKnob_.bindTo(synthesizer_, channel, Setting.FILTER_ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.FILTER_DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.FILTER_SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.FILTER_RELEASE); - } - - private PianoView piano_; - private KnobView cutoffKnob_; - private KnobView depthKnob_; - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/MainActivity.java b/android/src/com/levien/synthesizer/android/ui/MainActivity.java deleted file mode 100644 index caf802f..0000000 --- a/android/src/com/levien/synthesizer/android/ui/MainActivity.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.Spinner; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -// TODO(klimt): Add the ability to switch channels. - -public class MainActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - piano_ = (PianoView)findViewById(R.id.piano); - presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); - - final Button playButton = (Button)findViewById(R.id.playButton); - final Button recordButton = (Button)findViewById(R.id.recordButton); - - playButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - if (synthesizer_.getChannel(0).isPlaying()) { - synthesizer_.getChannel(0).stopPlaying(); - playButton.setText(R.string.play); - recordButton.setText(R.string.record); - } else { - synthesizer_.getChannel(0).startPlaying(); - playButton.setText(R.string.stop); - recordButton.setText(R.string.record); - } - } - }); - - recordButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - if (synthesizer_.getChannel(0).isRecording()) { - synthesizer_.getChannel(0).stopRecording(); - playButton.setText(R.string.play); - recordButton.setText(R.string.record); - } else { - synthesizer_.getChannel(0).startRecording(); - playButton.setEnabled(true); - playButton.setText(R.string.play); - recordButton.setText(R.string.stop); - } - } - }); - - presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (synthesizer_ == null) { - return; - } - String preset = presetSpinner_.getItemAtPosition(position).toString(); - if (!preset.equals("")) { - synthesizer_.getChannel(0).setPreset(preset); - } - } - public void onNothingSelected(AdapterView parent) { - } - }); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - piano_.bindTo(synthesizer_, 0); - - ArrayList presetNames = new ArrayList(); - presetNames.add(""); - synthesizer_.getPresetNames(presetNames); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_spinner_item, presetNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - presetSpinner_.setAdapter(adapter); - } - - private PianoView piano_; - private Spinner presetSpinner_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java b/android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java deleted file mode 100644 index 57eb91f..0000000 --- a/android/src/com/levien/synthesizer/android/ui/OscillatorActivity.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; -import com.levien.synthesizer.android.widgets.waveform.WaveformRowView; - -/** - * Activity for modifying oscillator parameters. - * TODO(klimt): Add the ability to switch channels. - */ -public class OscillatorActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.oscillator); - - piano_ = (PianoView)findViewById(R.id.piano); - waveformView_ = (WaveformRowView)findViewById(R.id.waveform); - glideKnob_ = (KnobView)findViewById(R.id.glideKnob); - coarseKnob_ = (KnobView)findViewById(R.id.coarseKnob); - fineKnob_ = (KnobView)findViewById(R.id.fineKnob); - vibratoDepthKnob_ = (KnobView)findViewById(R.id.vibratoDepthKnob); - balanceKnob_ = (KnobView)findViewById(R.id.balanceKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - Setting[] settings = getIntentSettings(this); - piano_.bindTo(synthesizer_, channel); - waveformView_.bindTo(synthesizer_, channel, settings[0]); - glideKnob_.bindTo(synthesizer_, channel, settings[1]); - coarseKnob_.bindTo(synthesizer_, channel, settings[2]); - fineKnob_.bindTo(synthesizer_, channel, settings[3]); - vibratoDepthKnob_.bindTo(synthesizer_, channel, settings[4]); - balanceKnob_.bindTo(synthesizer_, channel, settings[5]); - } - - private PianoView piano_; - private WaveformRowView waveformView_; - private KnobView glideKnob_; - private KnobView coarseKnob_; - private KnobView fineKnob_; - private KnobView vibratoDepthKnob_; - private KnobView balanceKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/PianoActivity.java b/android/src/com/levien/synthesizer/android/ui/PianoActivity.java deleted file mode 100644 index 2bc6bef..0000000 --- a/android/src/com/levien/synthesizer/android/ui/PianoActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; -import android.widget.AdapterView.OnItemSelectedListener; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; - -/** - * Activity for simply playing the piano. - */ -public class PianoActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.piano); - - piano_ = (PianoView)findViewById(R.id.piano); - volumeKnob_ = (KnobView)findViewById(R.id.volumeKnob); - presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner); - - presetSpinner_.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView parent, View view, int position, long id) { - if (synthesizer_ == null) { - return; - } - if (position > 0) { - piano_.bindTo(synthesizer_, position - 1); - volumeKnob_.bindTo(synthesizer_, position - 1, Setting.VOLUME); - } - } - public void onNothingSelected(AdapterView parent) { - } - }); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - piano_.bindTo(synthesizer_, 0); - volumeKnob_.bindTo(synthesizer_, 0, Setting.VOLUME); - - ArrayList presetNames = new ArrayList(); - presetNames.add(""); - synthesizer_.getPresetNames(presetNames); - ArrayAdapter adapter = new ArrayAdapter( - this, android.R.layout.simple_spinner_item, presetNames); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - presetSpinner_.setAdapter(adapter); - } - - private PianoView piano_; - private KnobView volumeKnob_; - private Spinner presetSpinner_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/ScoreActivity.java b/android/src/com/levien/synthesizer/android/ui/ScoreActivity.java deleted file mode 100644 index a39f130..0000000 --- a/android/src/com/levien/synthesizer/android/ui/ScoreActivity.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.android.Storage; -import com.levien.synthesizer.android.widgets.score.ScoreView; -import com.levien.synthesizer.android.widgets.score.ScoreViewToolbar; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.music.Music.Score.Builder; - -/** - * An Activity for editing or playing a score. - */ -public class ScoreActivity extends SynthActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.score); - - logger_ = Logger.getLogger(getClass().getName()); - - scoreView_ = (ScoreView)findViewById(R.id.score); - scoreViewToolbar_ = (ScoreViewToolbar)findViewById(R.id.toolbar); - - scoreViewToolbar_.setScoreView(scoreView_); - } - - @Override - protected void onStart() { - super.onStart(); - try { - Storage.openDefaultScore(scoreView_.getScore(), this.getApplicationContext()); - scoreView_.invalidate(); - scoreViewToolbar_.invalidate(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to open score.", e); - } - } - - @Override - protected void onStop() { - try { - Storage.saveDefaultScore(scoreView_.getScore().build(), this.getApplicationContext()); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to save score.", e); - } - super.onStop(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.score_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.new_score: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("New score..."); - builder.setMessage("This will erase any unsaved work. Are you sure?"); - builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - scoreView_.getScore().clear(); - scoreView_.invalidate(); - scoreViewToolbar_.invalidate(); - dialog.dismiss(); - } - }); - builder.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - return true; - case R.id.open_score: - Storage.openScoreWithDialog(scoreView_.getScore(), new Storage.OpenScoreListener() { - public void onOpenScore(Builder score) { - scoreView_.invalidate(); - scoreViewToolbar_.invalidate(); - } - }, this); - return true; - case R.id.save_score: - Storage.saveScoreWithDialog(scoreView_.getScore().build(), this); - return true; - case R.id.piano: - this.startActivity(new Intent(this, PianoActivity.class)); - return true; - case R.id.chord_grid: - this.startActivity(new Intent(this, ChordGridActivity.class)); - return true; - case R.id.edit_instrument: - this.startActivity(new Intent(this, InstrumentListActivity.class)); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - protected void onSynthConnected() { - final MidiListener synthMidi = synthesizerService_.getMidiListener(); - scoreView_.bindTo(synthMidi); - } - - private ScoreView scoreView_; - private ScoreViewToolbar scoreViewToolbar_; - - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java b/android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java deleted file mode 100644 index 06d96eb..0000000 --- a/android/src/com/levien/synthesizer/android/ui/SynthesizerActivity.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.net.Uri; -import android.os.IBinder; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.service.SynthesizerService; - -/** - * A base class for any Android Activity that wants to interact with the SynthesizerService. - */ -public abstract class SynthesizerActivity extends Activity { - /** - * Called when the synthesizer model changes. - */ - protected abstract void onSynthesizerUpdate(MultiChannelSynthesizer synth); - - /** - * Creates a URI for a specific synthesizer path. - * @param path - The absolute path of the component. - */ - public static Uri makeUri(int channel, Setting... settings) { - StringBuilder uri = new StringBuilder("content://com.levien.synthesizer/" + channel + "/"); - boolean first = true; - for (Setting setting : settings) { - if (!first) { - uri.append(','); - } - uri.append(setting.getNumber()); - first = false; - } - return Uri.parse(uri.toString()); - } - - /** - * Returns the path part of the URI that invoked an activity. - */ - private static String getPath(Activity activity) { - Intent intent = activity.getIntent(); - if (intent == null) { - Log.e(SynthesizerActivity.class.getName(), - "Attempted to get Intent module for SynthesizerActivity with no Intent."); - return null; - } - Uri uri = intent.getData(); - if (uri == null) { - Log.e(SynthesizerActivity.class.getName(), - "Attempted to get Intent module for Intent with no URI: " + intent); - return null; - } - String path = uri.getPath(); - if (path == null) { - Log.e(SynthesizerActivity.class.getName(), - "Attempted to get Intent module for URI with no path: " + uri); - return null; - } - if (path.startsWith("/")) { - path = path.substring(1); - } - return path; - } - - /** - * Gets the modules specified by the URI for the intent given to this Activity. - * @return - The list of settings found, if any. Otherwise, null. - */ - public static Setting[] getIntentSettings(Activity activity) { - Setting[] settings = null; - String path = getPath(activity); - // Clip off the channel, if it's there... - if (path.indexOf('/') >= 0) { - path = path.substring(path.indexOf('/') + 1); - } - String[] parts = path.split(", *"); - settings = new Setting[parts.length]; - for (int i = 0; i < parts.length; ++i) { - try { - int id = Integer.parseInt(parts[i]); - settings[i] = Setting.valueOf(id); - } catch (NumberFormatException e) { - Log.e(SynthesizerActivity.class.getName(), - "Unable to convert number \"" + parts[i] + "\" in path: " + path); - } - } - return settings; - } - - /** - * Gets the channel specified by the URI for the intent given to this Activity. - * @return - The channel in the intent, or 0 if none was found. - */ - public static int getIntentChannel(Activity activity) { - String path = getPath(activity); - int firstSlash = path.indexOf('/'); - if (firstSlash < 0) { - Log.e(SynthesizerActivity.class.getName(), - "Unable to find channel number in path: " + path); - return 0; - } - String channelString = path.substring(0, firstSlash); - try { - return Integer.parseInt(channelString); - } catch (NumberFormatException e) { - Log.e(SynthesizerActivity.class.getName(), - "Unable to convert channel number \"" + channelString + "\" in path: " + path); - return 0; - } - } - - @Override - protected void onStart() { - super.onStart(); - bindService(new Intent(this, SynthesizerService.class), - synthesizerConnection_, Context.BIND_AUTO_CREATE); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(synthesizerConnection_); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.options_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.piano: - this.startActivity(new Intent(this, PianoActivity.class)); - return true; - case R.id.chord_grid: - this.startActivity(new Intent(this, ChordGridActivity.class)); - return true; - case R.id.edit_instrument: - this.startActivity(new Intent(this, InstrumentListActivity.class)); - return true; - case R.id.compose: - this.startActivity(new Intent(this, ScoreActivity.class)); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - private ServiceConnection synthesizerConnection_ = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - // synthesizer_ = ISynthesizerService.Stub.asInterface(service); - synthesizer_ = ((SynthesizerService.LocalBinder)service).getSynthesizer(); - SynthesizerActivity.this.onSynthesizerUpdate(synthesizer_); - } - public void onServiceDisconnected(ComponentName className) { - synthesizer_ = null; - SynthesizerActivity.this.onSynthesizerUpdate(synthesizer_); - } - }; - - protected MultiChannelSynthesizer synthesizer_ = null; -} diff --git a/android/src/com/levien/synthesizer/android/ui/TremoloActivity.java b/android/src/com/levien/synthesizer/android/ui/TremoloActivity.java deleted file mode 100644 index d5a0060..0000000 --- a/android/src/com/levien/synthesizer/android/ui/TremoloActivity.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; -import com.levien.synthesizer.android.widgets.waveform.WaveformRowView; - -/** - * Activity for modifying tremolo. - * TODO(klimt): Add the ability to switch channels. - */ -public class TremoloActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.tremolo); - - piano_ = (PianoView)findViewById(R.id.piano); - waveformView_ = (WaveformRowView)findViewById(R.id.waveform); - rateKnob_ = (KnobView)findViewById(R.id.rateKnob); - depthKnob_ = (KnobView)findViewById(R.id.depthKnob); - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - waveformView_.bindTo(synthesizer_, channel, Setting.TREMOLO_WAVEFORM); - rateKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_RATE); - depthKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_DEPTH); - attackKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.TREMOLO_RELEASE); - } - - private PianoView piano_; - private WaveformRowView waveformView_; - private KnobView rateKnob_; - private KnobView depthKnob_; - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/ui/VibratoActivity.java b/android/src/com/levien/synthesizer/android/ui/VibratoActivity.java deleted file mode 100644 index 6c48e50..0000000 --- a/android/src/com/levien/synthesizer/android/ui/VibratoActivity.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.ui; - -import android.os.Bundle; -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.android.widgets.knob.KnobView; -import com.levien.synthesizer.android.widgets.piano.PianoView; -import com.levien.synthesizer.android.widgets.waveform.WaveformRowView; - -/** - * Activity for modifying vibrato. - * TODO(klimt): Add the ability to switch channels. - */ -public class VibratoActivity extends SynthesizerActivity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.vibrato); - - piano_ = (PianoView)findViewById(R.id.piano); - waveformView_ = (WaveformRowView)findViewById(R.id.waveform); - rateKnob_ = (KnobView)findViewById(R.id.rateKnob); - attackKnob_ = (KnobView)findViewById(R.id.attackKnob); - decayKnob_ = (KnobView)findViewById(R.id.decayKnob); - sustainKnob_ = (KnobView)findViewById(R.id.sustainKnob); - releaseKnob_ = (KnobView)findViewById(R.id.releaseKnob); - } - - @Override - protected void onSynthesizerUpdate(MultiChannelSynthesizer synth) { - int channel = getIntentChannel(this); - piano_.bindTo(synthesizer_, channel); - waveformView_.bindTo(synthesizer_, channel, Setting.VIBRATO_WAVEFORM); - rateKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_RATE); - attackKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_ATTACK); - decayKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_DECAY); - sustainKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_SUSTAIN); - releaseKnob_.bindTo(synthesizer_, channel, Setting.VIBRATO_RELEASE); - } - - private PianoView piano_; - private WaveformRowView waveformView_; - private KnobView rateKnob_; - private KnobView attackKnob_; - private KnobView decayKnob_; - private KnobView sustainKnob_; - private KnobView releaseKnob_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/ChordGridView.java b/android/src/com/levien/synthesizer/android/widgets/ChordGridView.java deleted file mode 100644 index 067893d..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/ChordGridView.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.music.Note; -import com.levien.synthesizer.android.widgets.piano.PianoViewListener; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.Paint.Style; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -/** - * ChordGridView is an alternative interface for performing that has keys for chords amongst - * fundamentals arranged in a circle of fifths. - */ -public class ChordGridView extends View { - /** - * Basic android widget constructor. - */ - public ChordGridView(Context context, AttributeSet attrs) { - super(context, attrs); - - // Get the xml attributes for this instance. - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChordGridView); - firstOctave_ = a.getInteger(R.styleable.ChordGridView_octave, 4); - - pressedRow_ = -1; - pressedColumn_ = -1; - - drawingRect_ = new Rect(); - path_ = new Path(); - strokePaint_ = new Paint(); - fillPaint_ = new Paint(); - strokePaint_.setStyle(Style.STROKE); - fillPaint_.setStyle(Style.FILL); - } - - /** - * Sets the listener that will receive events from this widget. - */ - public void setPianoViewListener(PianoViewListener pianoViewListener) { - pianoViewListener_ = pianoViewListener; - } - - /** - * Signals the listener that a new note was pressed. - * @param logFrequency - the log frequency of the new note. - * @param retriggerIfOn - true if this is a new touch, rather than just moving. - */ - private void notifyNoteDown(double logFrequency, int finger, boolean retriggerIfOn) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteDown(logFrequency, finger, retriggerIfOn, 1.0f); - } - } - - /** - * Signals the listener that a note was released. - */ - private void notifyNoteUp(int finger) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteUp(finger); - } - } - - /** - * Handler for all touch events. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - boolean redraw = false; - if (actionCode == MotionEvent.ACTION_DOWN) { - int tileWidth = drawingRect_.width() / COLUMNS; - int tileHeight = drawingRect_.height() / ROWS; - pressedColumn_ = (int)(event.getX() - drawingRect_.left) / tileWidth; - pressedRow_ = (int)(event.getY() - drawingRect_.top) / tileHeight; - redraw = true; - - getTileInfo(pressedRow_, pressedColumn_); - notifyNoteDown(Note.computeLog12TET(tileNote1_, tileOctave1_), 0, true); - notifyNoteDown(Note.computeLog12TET(tileNote2_, tileOctave2_), 1, true); - notifyNoteDown(Note.computeLog12TET(tileNote3_, tileOctave3_), 2, true); - } else if (actionCode == MotionEvent.ACTION_MOVE) { - int tileWidth = drawingRect_.width() / COLUMNS; - int tileHeight = drawingRect_.height() / ROWS; - int newPressedColumn_ = (int)(event.getX() - drawingRect_.left) / tileWidth; - int newPressedRow_ = (int)(event.getY() - drawingRect_.top) / tileHeight; - if (pressedColumn_ != newPressedColumn_ || pressedRow_ != newPressedRow_) { - pressedColumn_ = newPressedColumn_; - pressedRow_ = newPressedRow_; - redraw = true; - - getTileInfo(pressedRow_, pressedColumn_); - notifyNoteDown(Note.computeLog12TET(tileNote1_, tileOctave1_), 0, false); - notifyNoteDown(Note.computeLog12TET(tileNote2_, tileOctave2_), 1, false); - notifyNoteDown(Note.computeLog12TET(tileNote3_, tileOctave3_), 2, false); - } - } else if (actionCode == MotionEvent.ACTION_UP) { - pressedColumn_ = -1; - pressedRow_ = -1; - - notifyNoteUp(0); - notifyNoteUp(1); - notifyNoteUp(2); - redraw = true; - } else { - return super.onTouchEvent(event); - } - if (redraw) { - invalidate(); - } - return true; - } - - /** - * Draws the widget. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - getDrawingRect(drawingRect_); - int tileWidth = drawingRect_.width() / COLUMNS; - int tileHeight = drawingRect_.height() / ROWS; - for (int row = 0; row < ROWS; ++row) { - for (int column = 0; column < COLUMNS; ++column) { - getTileInfo(row, column); - int foreground; - int background; - if (Note.isNatural(tileNote1_)) { - if (row == pressedRow_ && column == pressedColumn_) { - foreground = Color.GREEN; - } else { - foreground = Color.WHITE; - } - background = Color.BLACK; - } else { - foreground = Color.BLACK; - if (row == pressedRow_ && column == pressedColumn_) { - background = Color.GREEN; - } else { - background = Color.WHITE; - } - } - int textColor = background; - fillPaint_.setColor(foreground); - strokePaint_.setColor(background); - canvas.drawRect(tileWidth * column, - tileHeight * row, - tileWidth * (column + 1), - tileHeight * (row + 1), - fillPaint_); - canvas.drawRect(tileWidth * column + 1, - tileHeight * row + 1, - tileWidth * (column + 1) - 2, - tileHeight * (row + 1) - 2, - strokePaint_); - if (tileIsMajor_) { - textColor = foreground; - strokePaint_.setColor(foreground); - fillPaint_.setColor(background); - path_.reset(); - path_.moveTo(tileWidth * column + 15, tileHeight * (row + 1) - 15); - path_.lineTo(tileWidth * (column + 1) - 15, tileHeight * (row + 1) - 15); - path_.lineTo(tileWidth * column + tileWidth / 2, tileHeight * row + 15); - path_.close(); - canvas.drawPath(path_, fillPaint_); - } - if (tileIsMinor_) { - textColor = foreground; - strokePaint_.setColor(foreground); - fillPaint_.setColor(background); - path_.reset(); - path_.moveTo(tileWidth * column + 15, tileHeight * row + tileHeight / 2); - path_.lineTo(tileWidth * (column + 1) - 15, tileHeight * (row + 1) - 15); - path_.lineTo(tileWidth * (column + 1) - 15, tileHeight * row + 15); - path_.close(); - canvas.drawPath(path_, fillPaint_); - } - if (tileNote1_ == Note.C && !tileIsMinor_ && !tileIsMajor_) { - fillPaint_.setColor(background); - canvas.drawCircle(tileWidth * column + tileWidth / 2, - tileHeight * row + tileHeight / 2, - 10, - fillPaint_); - } - strokePaint_.setColor(textColor); - canvas.drawText(Note.getName(tileNote1_), - tileWidth * column + tileWidth / 2, - tileHeight * row + tileHeight / 2, - strokePaint_); - } - } - } - - /** - * Populates the tile* fields for the tile at the given row and column. - */ - private void getTileInfo(int row, int column) { - int startIndex = 5 + firstOctave_ * 36; - int absoluteIndex = startIndex + row + column * 14; - if (absoluteIndex % 3 == 0) { - // Fundamental key. - tileOctave1_ = absoluteIndex / 36; - tileNote1_ = (absoluteIndex % 36) / 3; - tileOctave2_ = tileOctave1_; - tileNote2_ = tileNote1_; - tileOctave3_ = tileOctave1_; - tileNote3_ = tileNote1_; - tileIsMajor_ = false; - tileIsMinor_ = false; - } else if (absoluteIndex % 3 == 1) { - // Minor chord key. - tileOctave3_ = (int)((absoluteIndex - 1) / 36) + 1; - tileNote3_ = ((absoluteIndex - 1) % 36) / 3; - if (tileNote3_ >= 4) { - tileOctave2_ = tileOctave3_; - tileNote2_ = tileNote3_ - 4; - } else { - tileOctave2_ = tileOctave3_ - 1; - tileNote2_ = tileNote3_ + 8; - } - if (tileNote3_ >= 7) { - tileOctave1_ = tileOctave3_; - tileNote1_ = tileNote3_ - 7; - } else { - tileOctave1_ = tileOctave3_ - 1; - tileNote1_ = tileNote3_ + 5; - } - tileIsMajor_ = false; - tileIsMinor_ = true; - } else if (absoluteIndex % 3 == 2) { - // Major chord key. - tileOctave1_ = (int)((absoluteIndex + 1) / 36); - tileNote1_ = ((absoluteIndex + 1) % 36) / 3; - if (tileNote1_ < 8) { - tileOctave2_ = tileOctave1_; - tileNote2_ = tileNote1_ + 4; - } else { - tileOctave2_ = tileOctave1_ + 1; - tileNote2_ = tileNote1_ - 8; - } - if (tileNote1_ >= 7) { - tileOctave3_ = tileOctave1_; - tileNote3_ = tileNote1_ + 7; - } else { - tileOctave3_ = tileOctave1_ + 1; - tileNote3_ = tileNote1_ - 5; - } - tileIsMajor_ = true; - tileIsMinor_ = false; - } - } - - /** - * Connects the ChordGridView to a Synthesizer. - * @synth - The synthesizer to connect to. - */ - public void bindTo(final MultiChannelSynthesizer synth, final int channel) { - this.setPianoViewListener(new PianoViewListener() { - public void noteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - synth.getChannel(channel).setPitch(logFrequency, finger); - synth.getChannel(channel).turnOn(retriggerIfOn, finger); - } - public void noteUp(int finger) { - synth.getChannel(channel).turnOff(finger); - } - }); - } - - /** - * Populated by getTileInfo, these fields will contain the info for a particular key. - */ - private int tileOctave1_; - private int tileOctave2_; - private int tileOctave3_; - private int tileNote1_; - private int tileNote2_; - private int tileNote3_; - private boolean tileIsMajor_; - private boolean tileIsMinor_; - - // The coordinates of the key currently being pressed. - private int pressedColumn_; - private int pressedRow_; - - // The current octave the keyboard is on. - private int firstOctave_; - - // The listener to receive key events. - private PianoViewListener pianoViewListener_; - - // These are basically stack variables for onDraw. They're member variables only so that we can - // avoid reallocating them every time the keyboard is redrawn. - // - // The most recent screen rect that this keyboard was drawn into. - private Rect drawingRect_; - private Path path_; - private Paint strokePaint_; - private Paint fillPaint_; - - private static final int ROWS = 8; - private static final int COLUMNS = 5; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java deleted file mode 100644 index d88da27..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/BlackPianoKey.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; - -import com.levien.synthesizer.core.music.Note; - -/** - * One of the black (non-natural) keys on the piano. - */ -public class BlackPianoKey extends NotePianoKey { - /** - * Creates a new key. - * @param piano - the piano this key is on. - * @param octaveOffset - octave of the key, relative to the leftmost octave of the piano. - * @param key - offset of the key from the start of the octave. - */ - public BlackPianoKey(PianoView piano, int octave, int key) { - super(piano, octave, key); - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - public void layout(Rect drawingRect, int octaves) { - int whiteKeyWidth = getWhiteKeyWidth(drawingRect, octaves); - int blackKeyWidth = getBlackKeyWidth(drawingRect, octaves); - rect_.top = 0; - rect_.bottom = rect_.top + getBlackKeyHeight(drawingRect); - rect_.left = ((octaveOffset_ * WHITE_KEYS.length + key_ + 2) * whiteKeyWidth) - - (blackKeyWidth/2); - rect_.right = rect_.left + blackKeyWidth; - } - - /** - * Returns the log frequency of the note of the key. - */ - public double getLogFrequency() { - return Note.computeLog12TET(BLACK_KEYS[key_], octaveOffset_ + piano_.getFirstOctave()); - } - - /** - * Draws the key in the current rect_. - */ - public void draw(Canvas canvas) { - strokePaint_.setColor(Color.BLACK); - if (isPressed()) { - fillPaint_.setColor(Color.GREEN); - } else { - fillPaint_.setColor(Color.BLACK); - } - canvas.drawRect(rect_, fillPaint_); - canvas.drawRect(rect_, strokePaint_); - } - - /** - * Returns true if this is one of the black key positions that should actually have a key. - */ - public static boolean isValid(int note) { - return BLACK_KEYS[note] != Note.NONE; - } - - /** - * Utility function to calculate the width that a standard black key on this keyboard should be. - */ - protected static int getBlackKeyWidth(Rect drawingRect, int octaves) { - return (getWhiteKeyWidth(drawingRect, octaves) * 2) / 3; - } - - /** - * Utility function to calculate the height that a standard black key on this keyboard should be. - */ - protected static int getBlackKeyHeight(Rect drawingRect) { - return getWhiteKeyHeight(drawingRect) / 2; - } -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java deleted file mode 100644 index 4980458..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/NotePianoKey.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - - -/** - * Abstract base class for keys on the piano that play a note when pressed. - */ -public abstract class NotePianoKey extends PianoKey { - /** - * Creates a new key. - * @param piano - the piano this key is on. - * @param octaveOffset - octave of the key, relative to the leftmost octave of the piano. - * @param key - offset of the key from the start of the octave. - */ - public NotePianoKey(PianoView piano, int octaveOffset, int key) { - super(piano); - octaveOffset_ = octaveOffset; - key_ = key; - } - - /** - * Called when the pressed_ state has changed. - */ - protected void onPressedChanged(boolean move) { - } - - /** - * Returns the log frequency of the note of the key. - */ - abstract protected double getLogFrequency(); - - // Octave of the key, relative to the leftmost octave of the piano. - protected int octaveOffset_; - - // Offset of the key from the start of the octave. - protected int key_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java deleted file mode 100644 index fe8c31c..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/OctavePianoKey.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Path; -import android.graphics.Rect; - -/** - * A key on the piano for changing the octave up or down. - */ -public class OctavePianoKey extends PianoKey { - /** - * Creates the key. - * @param piano - the piano this key is on. - * @param delta - how the octave should change when this key is pressed. - */ - public OctavePianoKey(PianoView piano, int delta) { - super(piano); - arrow_ = new Path(); - delta_ = delta; - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - public void layout(Rect drawingRect, int octaves) { - int whiteKeyWidth = getWhiteKeyWidth(drawingRect, octaves); - rect_.top = 0; - rect_.bottom = getWhiteKeyHeight(drawingRect); - if (delta_ <= 0) { - rect_.left = 0; - rect_.right = rect_.left + whiteKeyWidth; - } else { - rect_.right = drawingRect.right; - rect_.left = rect_.right - whiteKeyWidth; - } - } - - /** - * Returns true if the current octave of the piano could be changed by delta and still be valid. - */ - private boolean isValid() { - return (piano_.getFirstOctave() + delta_ >= 0 && - piano_.getFirstOctave() + piano_.getOctaves() + delta_ <= 8); - } - - /** - * Draws the key in the current rect_. - */ - public void draw(Canvas canvas) { - strokePaint_.setColor(Color.BLACK); - fillPaint_.setColor(Color.BLACK); - if (isPressed() && isValid()) { - fillPaint_.setColor(Color.GREEN); - } - canvas.drawRect(rect_, fillPaint_); - canvas.drawRect(rect_, strokePaint_); - - // Draw an arrow in the direction of the delta. - if (isValid()) { - arrow_.reset(); - if (delta_ <= 0) { - arrow_.moveTo(rect_.left + 2, rect_.height() / 2); - arrow_.lineTo(rect_.right - 2, rect_.height() / 2 - 20); - arrow_.lineTo(rect_.right - 2, rect_.height() / 2 + 20); - } else { - arrow_.moveTo(rect_.right - 2, rect_.height() / 2); - arrow_.lineTo(rect_.left + 2, rect_.height() / 2 - 20); - arrow_.lineTo(rect_.left + 2, rect_.height() / 2 + 20); - } - arrow_.close(); - fillPaint_.setColor(Color.WHITE); - canvas.drawPath(arrow_, fillPaint_); - } - } - - /** - * Called when the pressed_ state has changed. - */ - @Override - protected void onPressedChanged(boolean move) { - if (isPressed() && isValid()) { - piano_.changeOctave(delta_); - } - } - - // This is just used for drawing, but we don't want to pay to reallocate it every time. - private Path arrow_; - - // How the octave should change when this key is pressed. - private int delta_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java deleted file mode 100644 index 44e987b..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoKey.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.Log; - -import com.levien.synthesizer.core.music.Note; - -/** - * PianoKey is the abstract base class for any key on the piano. - * It keeps track of whether the key is currently being pressed. - */ -public abstract class PianoKey { - public PianoKey(PianoView piano) { - piano_ = piano; - pressed_ = new boolean[PianoView.FINGERS]; - rect_ = new Rect(); - - for (int i = 0; i < pressed_.length; ++i) { - pressed_[i] = false; - } - - // Set up some default objects for the key to draw itself with. - fillPaint_ = new Paint(); - strokePaint_ = new Paint(); - fillPaint_.setStyle(Paint.Style.FILL); - strokePaint_.setStyle(Paint.Style.STROKE); - strokePaint_.setColor(Color.BLACK); - float strokeWidth = 1.0f * piano.getResources().getDisplayMetrics().density; - strokePaint_.setStrokeWidth(strokeWidth); - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - abstract public void layout(Rect drawingRect, int octaves); - - /** - * Draws the key in the current rect_. - */ - abstract public void draw(Canvas canvas); - - /** - * Called when the key's pressed_ state has changed. - * @param move - true if the key became pressed because the touch moved onto it. - */ - abstract protected void onPressedChanged(boolean move); - - /** - * Returns true if the given co-ordinate is inside the key's current rect_. - */ - public boolean contains(int x_, int y_) { - return rect_.contains(x_, y_); - } - - /** - * Returns true if any finger is pressing this key. - */ - public boolean isPressed() { - for (int i = 0; i < pressed_.length; ++i) { - if (pressed_[i]) { - return true; - } - } - return false; - } - - /** - * Called when a finger has touched down onto this key. - * Returns true iff whether the pressed state changed. - */ - final public boolean onTouchDown(int finger) { - if (finger >= pressed_.length) { - Log.e(getClass().getName(), - "Finger " + finger + " was pressed down, but PianoKey only supports " + - pressed_.length + " fingers."); - } - boolean wasPressed = isPressed(); - pressed_[finger] = true; - if (!wasPressed) { - onPressedChanged(false); - return true; - } - return false; - } - - /** - * Called on a touch event where this key is not being touched. It may already be up. - * Returns true iff whether the pressed state changed. - */ - final public boolean onTouchUp(int finger) { - if (finger >= pressed_.length) { - Log.e(getClass().getName(), - "Finger " + finger + " was released, but PianoKey only supports " + - pressed_.length + " fingers."); - } - boolean wasPressed = isPressed(); - pressed_[finger] = false; - boolean isPressed = isPressed(); - if (wasPressed && !isPressed) { - onPressedChanged(false); - return true; - } - return false; - } - - /** - * Called when there's a touch event where the finger was moved onto this key. - * Returns true iff whether the pressed state changed. - */ - final public boolean onTouchMoved(int finger) { - if (finger >= pressed_.length) { - Log.e(getClass().getName(), - "Finger " + finger + " was pressed down, but PianoKey only supports " + - pressed_.length + " fingers."); - } - boolean wasPressed = isPressed(); - pressed_[finger] = true; - if (!wasPressed) { - onPressedChanged(true); - return true; - } - return false; - } - - /** - * Utility function to calculate the width that a standard white key on this keyboard should be. - */ - protected static int getWhiteKeyWidth(Rect drawingRect, int octaves) { - // It's +2 to reserve space for the octave-up/down buttons. - return drawingRect.width() / ((WHITE_KEYS.length * octaves) + 2); - } - - /** - * Utility function to calculate the height that a standard white key on this keyboard should be. - */ - protected static int getWhiteKeyHeight(Rect drawingRect) { - return drawingRect.height(); - } - - // The piano this key is on. - protected PianoView piano_; - - // Is each keys currently being pressed? - protected boolean[] pressed_; - - // The area this key occupies. - protected Rect rect_; - - // Objects for subclasses to use for painting, just so they don't have to reallocate every time. - protected Paint fillPaint_; - protected Paint strokePaint_; - - // Constants to map notes onto the keys. - protected static final int WHITE_KEYS[] = { - Note.C, Note.D, Note.E, Note.F, Note.G, Note.A, Note.B }; - protected static final int BLACK_KEYS[] = { - Note.C_SHARP, Note.E_FLAT, Note.NONE, Note.F_SHARP, Note.A_FLAT, Note.B_FLAT, Note.NONE }; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java deleted file mode 100644 index d1b9d62..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import java.util.HashMap; -import java.util.Map; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.music.Note; - -/** - * PianoView is a UI widget that simulates a music keyboard. - */ -public class PianoView extends View { - /** - * Basic android widget constructor. - */ - public PianoView(Context context, AttributeSet attrs) { - super(context, attrs); - - // Get the xml attributes for this instance. - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PianoView); - octaves_ = a.getInteger(R.styleable.PianoView_octaves, 1); - firstOctave_ = a.getInteger(R.styleable.PianoView_first_octave, 4); - a.recycle(); - - // Set up basic drawing structs, just so we don't have to allocate this later when we draw. - drawingRect_ = new Rect(); - - // Generate the set of keys. There are 12 music keys per octave, plus the octave change button - // on either end. - keys_ = new PianoKey[12 * octaves_ + 2]; - int key = 0; - - // Create the white keys. - for (int octave = 0; octave < octaves_; ++octave) { - for (int note = 0; note < 7; ++note) { - keys_[key++] = new WhitePianoKey(this, octave, note); - } - } - - // Create the black keys. - for (int octave = 0; octave < octaves_; ++octave) { - for (int note = 0; note < 7; ++note) { - if (BlackPianoKey.isValid(note)) { - keys_[key++] = new BlackPianoKey(this, octave, note); - } - } - } - - // Create the octave changing keys. - keys_[key++] = new OctavePianoKey(this, -1); - keys_[key++] = new OctavePianoKey(this, 1); - - // The listener will have to be set later. - pianoViewListener_ = null; - } - - /** - * Returns the absolute octave of the left-most key. - */ - public int getFirstOctave() { - return firstOctave_; - } - - /** - * Returns the number of octaves covered by all of the keys. - */ - public int getOctaves() { - return octaves_; - } - - /** - * Shifts the octave of all of the keys. - * @param delta - The number (and direction) of octaves to shift by. - */ - public void changeOctave(int delta) { - firstOctave_ += delta; - } - - /** - * Sets the listener that will receive events from this widget. - */ - public void setPianoViewListener(PianoViewListener pianoViewListener) { - pianoViewListener_ = pianoViewListener; - } - - /** - * Signals the listener that a new note was pressed. - * @param logFrequency - the log frequency of the new note. - * @param retriggerIfOn - true if this is a new touch, rather than just moving. - */ - private void notifyNoteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteDown(logFrequency, finger, retriggerIfOn, pressure); - } - } - - /** - * Signals the listener that a note was released. - */ - private void notifyNoteUp(int finger) { - if (pianoViewListener_ != null) { - pianoViewListener_.noteUp(finger); - } - } - - /** - * Draws the widget. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - getDrawingRect(drawingRect_); - for (int i = 0; i < keys_.length; ++i) { - keys_[i].layout(drawingRect_, octaves_); - } - for (int i = 0; i < keys_.length; ++i) { - keys_[i].draw(canvas); - } - } - - /** - * Called to handle touch down events. - * Returns true iff we need to redraw. - */ - protected boolean onTouchDown(int finger, int x, int y, float pressure) { - // Look through keys from top to bottom, and set the first one found as down, the rest as up. - PianoKey keyDown = null; - boolean redraw = false; - for (int i = keys_.length - 1; i >= 0; --i) { - if (keyDown != null) { - // If we already found a key that's being touched, then none of the rest can be. - redraw |= keys_[i].onTouchUp(finger); - } else if (keys_[i].contains(x, y)) { - // This key is being touched. - redraw |= keys_[i].onTouchDown(finger); - keyDown = keys_[i]; - } else { - // This key is not being touched. - redraw |= keys_[i].onTouchUp(finger); - } - } - if (!usePressure_) { - pressure = 0.5f; - } - if (keyDown instanceof NotePianoKey) { - notifyNoteDown(((NotePianoKey)keyDown).getLogFrequency(), finger, true, pressure); - } - return redraw; - } - - /** - * Called to handle touch move events. - */ - protected boolean onTouchMove(int finger, int x, int y, float pressure) { - // Look through keys from top to bottom, and set the first one found as moved, the rest as up. - PianoKey keyDown = null; - boolean redraw = false; - boolean wasPressed = false; - for (int i = keys_.length - 1; i >= 0; --i) { - if (keyDown != null) { - // If we already found a key that's being touched, then none of the rest can be. - redraw |= keys_[i].onTouchUp(finger); - } else if (keys_[i].contains(x, y)) { - // This key is being pressed. - wasPressed = keys_[i].isPressed(); - redraw |= keys_[i].onTouchMoved(finger); - keyDown = keys_[i]; - } else { - // This key is not being pressed. - redraw |= keys_[i].onTouchUp(finger); - } - } - if (keyDown instanceof NotePianoKey) { - if (!usePressure_) { - pressure = 0.5f; - } - if (!wasPressed) { - notifyNoteDown(((NotePianoKey)keyDown).getLogFrequency(), finger, false, pressure); - } - } else { - notifyNoteUp(finger); - } - return redraw; - } - - /** - * Called to handle touch up events. - */ - protected boolean onTouchUp(int finger) { - // Set all keys as up. - boolean redraw = false; - for (int i = 0; i < keys_.length; ++i) { - redraw |= keys_[i].onTouchUp(finger); - } - notifyNoteUp(finger); - return redraw; - } - - - /** - * Handler for all touch events. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - //Log.i("synth", "actionCode = " + actionCode); - boolean redraw = false; - if (actionCode == MotionEvent.ACTION_DOWN) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - int x = (int)event.getX(); - int y = (int)event.getY(); - float pressure = event.getPressure(); - redraw |= onTouchDown(pointerId, x, y, pressure); - } else { - Log.i("synth", "Discarded ACTION_DOWN pointerId=" + pointerId); - } - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - int pointerId = event.getPointerId(pointerIndex); - if (pointerId < FINGERS && pointerId >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - float pressure = event.getPressure(pointerIndex); - redraw |= onTouchDown(pointerId, x, y, pressure); - } else { - Log.i("synth", "Discarded ACTION_POINTER_DOWN pointerId=" + pointerId); - } - } else if (actionCode == MotionEvent.ACTION_MOVE) { - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= FINGERS) { - continue; - } - if (pointerIndex >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - float pressure = event.getPressure(pointerIndex); - redraw |= onTouchMove(pointerId, x, y, pressure); - } - } - } else if (actionCode == MotionEvent.ACTION_UP) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - redraw |= onTouchUp(pointerId); - } - // Clean up any other pointers that have disappeared. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - boolean thisRedraw = onTouchUp(pointerId); - if (thisRedraw) { - Log.i("synth", "ACTION_UP cleaned up pointerId=" + pointerId); - } - redraw |= thisRedraw; - } - } - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - int pointerId = event.getPointerId(pointerIndex); - if (pointerId < FINGERS) { - redraw |= onTouchUp(pointerId); - } - // Clean up any other pointers that have disappeared. Note: this is probably not necessary. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - boolean thisRedraw = onTouchUp(pointerId); - if (thisRedraw) { - Log.i("synth", "ACTION_POINTER_UP cleaned up pointerId=" + pointerId); - } - redraw |= thisRedraw; - } - } - } else { - return super.onTouchEvent(event); - } - if (redraw) { - invalidate(); - } - return true; - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the widget maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } - - /** - * Connects the PianoView to a Synthesizer. - * @synth - The synthesizer to connect to. - * @channel - Which of the synthesizer's channels to bind to. - */ - public void bindTo(final MultiChannelSynthesizer synth, final int channel) { - this.setPianoViewListener(new PianoViewListener() { - public void noteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - synth.getChannel(channel).setPitch(logFrequency, finger); - synth.getChannel(channel).turnOn(retriggerIfOn, finger); - } - public void noteUp(int finger) { - synth.getChannel(channel).turnOff(finger); - } - }); - } - - /** - * Connects the PianoView to an MidiListener. - */ - public void bindTo(final MidiListener midiListener) { - this.setPianoViewListener(new PianoViewListener() { - { - fingerMap_ = new HashMap(); - } - public void noteDown(double logFrequency, int finger, boolean retriggerIfOn, - float pressure) { - noteUp(finger); - int midiNote = Note.getKeyforLog12TET(logFrequency); - fingerMap_.put(finger, midiNote); - int midiPressure = Math.max(1, Math.min(127, (int)(127 * pressure))); - midiListener.onNoteOn(0, midiNote, midiPressure); - } - public void noteUp(int finger) { - if (fingerMap_.containsKey(finger)) { - int midiNote = fingerMap_.get(finger); - fingerMap_.remove(finger); - midiListener.onNoteOff(0, midiNote, 64); - } - } - private Map fingerMap_; - }); - } - - public void setNoteOn(int note, boolean on) { - // This is somewhat painful, hopefully can be done better. - for (int i = 0; i < keys_.length; i++) { - PianoKey key = keys_[i]; - if (key instanceof NotePianoKey) { - int midiNote = Note.getKeyforLog12TET(((NotePianoKey) key).getLogFrequency()); - if (midiNote == note) { - boolean redraw; - if (on) { - // using the last finger is something of a hack - redraw = key.onTouchDown(FINGERS - 1); - } else { - redraw = key.onTouchUp(FINGERS - 1); - } - if (redraw) { - invalidate(); - } - break; - } - } - } - } - - // The most recent screen rect that this keyboard was drawn into. - // - // This is basically a stack variable for onDraw. It's a member variable only so that we can - // avoid reallocating them every time the keyboard is redrawn. - private Rect drawingRect_; - - // The set of keys on the keyboard. - private PianoKey[] keys_; - - // The current octave the keyboard is on. - private int firstOctave_; - - // The total number of octaves the keyboard displays at any one time. - private final int octaves_; - - // The listener to receive key events. - private PianoViewListener pianoViewListener_; - - // The number of simultaneous fingers supported by this control. - protected static final int FINGERS = 10; - - // Whether to use pressure (doesn't work well on all hardware) - private boolean usePressure_ = false; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java deleted file mode 100644 index 258f422..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoViewListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -// Simple interface for listening to piano widget events. -public interface PianoViewListener { - /** - * A note was pressed. - * @param logFrequency - the log frequency of the note pressed. - * @param retriggerIfOn - true if this is a new touch, rather than just moving. - */ - void noteDown(double logFrequency, int finger, boolean retriggerIfOn, float pressure); - - /** - * The note was released. - */ - void noteUp(int finger); -} diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java b/android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java deleted file mode 100644 index 4ab7909..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/piano/WhitePianoKey.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.piano; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; - -import com.levien.synthesizer.core.music.Note; - -/** - * A white key on the piano. - */ -public class WhitePianoKey extends NotePianoKey { - /** - * Creates a new key. - * @param piano - the piano this key is on. - * @param octaveOffset - octave of the key, relative to the leftmost octave of the piano. - * @param key - offset of the key from the start of the octave. - */ - public WhitePianoKey(PianoView piano, int octave, int key) { - super(piano, octave, key); - } - - /** - * Sets rect_ to the position of this key, based on the drawing rect of the piano it's on. - * @param drawingRect - the position of the piano itself. - * @param octaves - the number of octaves visible on the piano keyboard. - */ - public void layout(Rect drawingRect, int octaves) { - int whiteKeyWidth = getWhiteKeyWidth(drawingRect, octaves); - rect_.top = 0; - rect_.bottom = getWhiteKeyHeight(drawingRect); - rect_.left = ((octaveOffset_ * WHITE_KEYS.length + key_ + 1) * whiteKeyWidth); - rect_.right = rect_.left + whiteKeyWidth; - } - - /** - * Returns the log frequency of the note of the key. - */ - public double getLogFrequency() { - return Note.computeLog12TET(WHITE_KEYS[key_], octaveOffset_ + piano_.getFirstOctave()); - } - - /** - * Draws the key in the current rect_. - */ - public void draw(Canvas canvas) { - strokePaint_.setColor(Color.BLACK); - if (isPressed()) { - fillPaint_.setColor(Color.GREEN); - } else { - fillPaint_.setColor(Color.WHITE); - } - canvas.drawRect(rect_, fillPaint_); - canvas.drawRect(rect_, strokePaint_); - } -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java b/android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java deleted file mode 100644 index b3ea9e4..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/EditEventTool.java +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Music.Event; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for editing the events in a score. If the user touches an event, they can move it or - * resize it. If the event is already selected, all selected events will be moved or resized in the - * same way. If the user touches outside any events, a selection rectangle allows them to select - * one or more events. - */ -public class EditEventTool extends ScoreViewTool { - /** - * Creates a new EditEventTool with the given context for loading resources. - */ - EditEventTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - // Set up basic drawing structs, just so we don't have to allocate this later when we draw. - paint_ = new Paint(); - path_ = new Path(); - - selection_ = new Rect(); - - trashVisible_ = false; - trashRect_ = new Rect(); - trashIcon_ = context.getResources().getDrawable(R.drawable.trash); - - icon_ = context.getResources().getDrawable(R.drawable.arrow); - } - - /** - * Starts this tool editing a particular event, and sets it to invoke another tool when done. - * Called by NewEventTool to handle sizing the tool as it's being created. - * @param view - The ScoreView for this tool. - * @param event - The event to start editing. - * @param physicalX - The current x of the user's finger, in screen coordinates. - * @param physicalY -The current y of the user's finger, in screen coordinates. - * @param nextTool - The tool to select when the user is done editing this event. (on touch up) - */ - public void pickupEvent(ScoreView view, - Event.Builder event, - int physicalX, - int physicalY, - ScoreViewTool nextTool) { - // Save the tool to bring up after this operation is complete. - nextTool_ = nextTool; - - // De-select everything. - for (int j = 0; j < view.getScore().getEventCount(); ++j) { - view.getScore().getEventBuilder(j).setSelected(false); - } - // Select just the one that was picked up. - event.setSelected(true); - mode_ = RESIZING_RIGHT; - - // Make sure to snap the event. - if (!event.hasUnsnappedStart()) { - event.setUnsnappedStart(event.getStart()); - } - if (!event.hasUnsnappedEnd()) { - event.setUnsnappedEnd(event.getEnd()); - } - if (view.getSnapTo() != 0) { - event.setStart(((int)(event.getUnsnappedStart() / view.getSnapTo())) * view.getSnapTo()); - event.setEnd(((int)(event.getUnsnappedEnd() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setStart(event.getUnsnappedStart()); - event.setEnd(event.getUnsnappedEnd()); - } - - // Store the coordinates where it was picked up. - double time = view.getTimeAt(physicalX); - double note = view.getNoteAt(physicalY); - previousTime_ = time; - previousNote_ = note; - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called on finger down. - */ - private void onTouchDown(ScoreView view, int physicalX, int physicalY) { - double time = view.getTimeAt(physicalX); - double note = view.getNoteAt(physicalY); - - // When we're done editing this item, this tool stays selected. - nextTool_ = this; - - // See if there's an event being touched. - Event.Builder event = view.getEventAt(physicalX, physicalY); - if (event != null) { - if (!event.getSelected()) { - // De-select everything. - for (int j = 0; j < view.getScore().getEventCount(); ++j) { - view.getScore().getEventBuilder(j).setSelected(false); - } - // Select just the one that was pressed. - event.setSelected(true); - } - - // Compute the handle size. - int physicalHandleSize = view.getNoteY(0) - view.getNoteY(1); - double handleWidth = view.getTimeAt(physicalHandleSize) - view.getTimeAt(0); - boolean largeEnough = event.getEnd() - event.getStart() > handleWidth * 2; - - // See if any handle was touched. - if (largeEnough && time <= event.getStart() + handleWidth) { - mode_ = RESIZING_LEFT; - } else if (largeEnough && time >= event.getEnd() - handleWidth) { - mode_ = RESIZING_RIGHT; - } else { - mode_ = MOVING; - } - } else { - // De-select everything. - for (int j = 0; j < view.getScore().getEventCount(); ++j) { - view.getScore().getEventBuilder(j).setSelected(false); - } - - selection_.left = physicalX; - selection_.right = physicalX; - selection_.top = physicalY; - selection_.bottom = physicalY; - - mode_ = SELECTING; - } - view.invalidate(); - previousTime_ = time; - previousNote_ = note; - } - - /** - * Called on finger movements. - */ - private void onTouchMove(ScoreView view, int physicalX, int physicalY) { - double time = view.getTimeAt(physicalX); - double note = view.getNoteAt(physicalY); - double deltaTime = time - previousTime_; - double deltaNote = note - previousNote_; - switch (mode_) { - case RESIZING_RIGHT: { - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (!event.getSelected()) { - continue; - } - - if (!event.hasUnsnappedEnd()) { - event.setUnsnappedEnd(event.getEnd()); - } - event.setUnsnappedEnd(event.getUnsnappedEnd() + deltaTime); - if (view.getSnapTo() != 0) { - event.setEnd(((int)(event.getUnsnappedEnd() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setEnd(event.getUnsnappedEnd()); - } - - if (event.getEnd() <= event.getStart()) { - event.setEnd(event.getStart() + 1/32.0f); - } - } - break; - } - case RESIZING_LEFT: { - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (!event.getSelected()) { - continue; - } - - if (!event.hasUnsnappedStart()) { - event.setUnsnappedStart(event.getStart()); - } - event.setUnsnappedStart(event.getUnsnappedStart() + deltaTime); - if (view.getSnapTo() != 0) { - event.setStart(((int)(event.getUnsnappedStart() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setStart(event.getUnsnappedStart()); - } - - if (event.getStart() >= event.getEnd()) { - event.setEnd(event.getEnd() - 1/32.0f); - } - } - break; - } - case MOVING: { - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (!event.getSelected()) { - continue; - } - - if (!event.hasUnsnappedStart()) { - event.setUnsnappedStart(event.getStart()); - } - event.setUnsnappedStart(event.getUnsnappedStart() + deltaTime); - if (view.getSnapTo() != 0) { - event.setStart(((int)(event.getUnsnappedStart() / view.getSnapTo())) * - view.getSnapTo()); - } else { - event.setStart(event.getUnsnappedStart()); - } - - if (!event.hasUnsnappedEnd()) { - event.setUnsnappedEnd(event.getEnd()); - } - event.setUnsnappedEnd(event.getUnsnappedEnd() + deltaTime); - if (view.getSnapTo() != 0) { - event.setEnd(((int)(event.getUnsnappedEnd() / view.getSnapTo())) * view.getSnapTo()); - } else { - event.setEnd(event.getUnsnappedEnd()); - } - - if (event.getEnd() <= event.getStart()) { - event.setEnd(event.getStart() + 1/32.0f); - } - - if (!event.hasUnsnappedKey()) { - event.setUnsnappedKey(event.getKey()); - } - event.setUnsnappedKey(event.getUnsnappedKey() + deltaNote); - event.setKey((int)event.getUnsnappedKey()); - - trashVisible_ = true; - trashRect_.top = view.getDrawingRect().top; - trashRect_.bottom = view.getDrawingRect().top + - Math.max(200, trashIcon_.getIntrinsicHeight()); - trashRect_.left = view.getDrawingRect().right - - Math.max(200, trashIcon_.getIntrinsicWidth()); - trashRect_.right = view.getDrawingRect().right; - trashIcon_.setBounds(trashRect_); - } - break; - } - case SELECTING: { - // Update the selection rectangle. - selection_.right = physicalX; - selection_.bottom = physicalY; - - // Update event selections. - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - if (selection_.intersects(view.getTimeX(event.getStart()), - view.getNoteY(event.getKey() + 1), - view.getTimeX(event.getEnd()), - view.getNoteY(event.getKey()))) { - view.getScore().getEventBuilder(i).setSelected(true); - } else { - view.getScore().getEventBuilder(i).setSelected(false); - } - } - - break; - } - } - view.invalidate(); - previousTime_ = time; - previousNote_ = note; - } - - /** - * Called on finger up. - */ - private void onTouchUp(ScoreView view, int physicalX, int physicalY) { - trashVisible_ = false; - - if (trashRect_.contains(physicalX, physicalY)) { - for (int i = view.getScore().getEventCount() - 1; i >= 0; --i) { - if (view.getScore().getEventBuilder(i).getSelected()) { - view.getScore().removeEvent(i); - } - } - } - - // Make all snapping permanent. - for (int i = 0; i < view.getScore().getEventCount(); ++i) { - Event.Builder event = view.getScore().getEventBuilder(i); - event.clearUnsnappedStart(); - event.clearUnsnappedEnd(); - event.clearUnsnappedKey(); - } - - mode_ = NONE; - view.setTool(nextTool_); - - view.invalidate(); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - pointerId_ = event.getPointerId(0); - onTouchDown(view, (int)event.getX(), (int)event.getY()); - return true; - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - return false; - } else if (actionCode == MotionEvent.ACTION_MOVE) { - // Find the current positions of the fingers. - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= 0 && pointerId == pointerId_) { - int physicalX = (int)event.getX(pointerIndex); - int physicalY = (int)event.getY(pointerIndex); - onTouchMove(view, physicalX, physicalY); - return true; - } - } - return false; - } else if (actionCode == MotionEvent.ACTION_UP) { - onTouchUp(view, (int)event.getX(), (int)event.getY()); - return true; - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - return false; - } else { - return false; - } - } - - /** - * Called after each event is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param event - The event that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - @Override - public void afterDrawEvent(Event event, - Canvas canvas, - Rect rect) { - if (rect.right >= rect.left + rect.height() * 2) { - // Draw left arrow. - float margin = 1.0f; - paint_.setStrokeWidth(1.0f); - paint_.setStyle(Paint.Style.STROKE); - if (event.hasKeyEvent()) { - paint_.setColor(Color.BLACK); - } else { - paint_.setColor(Color.WHITE); - } - canvas.drawRect(rect.left, rect.top, - rect.left + rect.height(), rect.top + rect.height(), - paint_); - paint_.setStyle(Paint.Style.FILL); - path_.reset(); - path_.moveTo(rect.left + rect.height() - margin, rect.top + margin); - path_.lineTo(rect.left + rect.height() - margin, rect.bottom - margin); - path_.lineTo(rect.left + margin, (rect.top + rect.bottom) / 2.0f); - path_.close(); - canvas.drawPath(path_, paint_); - - // Draw right arrow. - paint_.setStyle(Paint.Style.STROKE); - if (event.hasKeyEvent()) { - paint_.setColor(Color.BLACK); - } else { - paint_.setColor(Color.WHITE); - } - canvas.drawRect(rect.right - rect.height(), rect.top, rect.right, rect.bottom, paint_); - paint_.setStyle(Paint.Style.FILL); - path_.reset(); - path_.moveTo(rect.right - (rect.height() - (margin + 1)), rect.top + margin); - path_.lineTo(rect.right - (rect.height() - (margin + 1)), rect.bottom - margin); - path_.lineTo(rect.right - margin, (rect.top + rect.bottom) / 2.0f); - path_.close(); - canvas.drawPath(path_, paint_); - } - } - - /** - * Called after the entire score is drawn, to give this tool a chance to draw over it. - * Draws the selection box, and possibly the trash icon. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param view - The ScoreView being drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - @Override - public void afterDrawScore(ScoreView view, Canvas canvas, Rect rect) { - if (mode_ == SELECTING) { - paint_.setStyle(Paint.Style.FILL); - paint_.setColor(Color.CYAN); - paint_.setAlpha(127); - canvas.drawRect(selection_, paint_); - paint_.setAlpha(255); - } - - // Draw the trash can. - if (trashVisible_) { - trashIcon_.draw(canvas); - } - } - - // The id of the finger doing the editing. - private int pointerId_; - - // The most recent previous position of the finger. - private double previousTime_; - private double previousNote_; - - // A tool to select the next time the user finishes editing an event. - // Can be "this", but not null. - private ScoreViewTool nextTool_; - - // While the user is drawing a selection rectangle, this is it, in screen (physical) coordinates. - private Rect selection_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - protected Paint paint_; - protected Path path_; - private Drawable icon_; - - // The mode of the tool, depending mostly on where the user's finger was when they first touched. - private int mode_; - private static final int NONE = 0; - private static final int RESIZING_LEFT = 1; - private static final int RESIZING_RIGHT = 2; - private static final int MOVING = 3; - private static final int SELECTING = 4; - - // Members for controlling how the trash can icon gets drawn while moving events. - private boolean trashVisible_; - private Rect trashRect_; // in screen (physical) coordinates. - private Drawable trashIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java b/android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java deleted file mode 100644 index b8bd815..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/HideChannelButton.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A button that toggles between showing the events for all of the synthesizer channels or showing - * just the currently selected channel. - */ -public class HideChannelButton extends ScoreViewTool { - /** - * Creates a new HideChannelButton, using the given context for loading resources. - */ - HideChannelButton(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - visibleIcon_ = context.getResources().getDrawable(R.drawable.open_eye); - hiddenIcon_ = context.getResources().getDrawable(R.drawable.closed_eye); - paint_ = new Paint(); - } - - /** - * Called when this tool is selected. - * Changes the channel visibility and then reselects the previous tool. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - view.setOtherChannelsVisible(!view.getOtherChannelsVisible()); - view.setTool(previousTool); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - if (score.getOtherChannelsVisible()) { - visibleIcon_.setBounds(rect); - visibleIcon_.draw(canvas); - } else { - hiddenIcon_.setBounds(rect); - hiddenIcon_.draw(canvas); - } - } - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable visibleIcon_; - private Drawable hiddenIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java b/android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java deleted file mode 100644 index 3179a23..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/NewEventTool.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Music.Event; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for creating new events in the score. - */ -public class NewEventTool extends ScoreViewTool { - /** - * Creates a new NewEventTool. - * @param context - The context to use for loading resources. - * @param eventTool - The tool to use for editing the event as it's created. - */ - NewEventTool(Context context, EditEventTool eventTool) { - logger_ = Logger.getLogger(getClass().getName()); - eventTool_ = eventTool; - - icon_ = context.getResources().getDrawable(R.drawable.add); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - double time = view.getTimeAt((int)event.getX()); - double note = view.getNoteAt((int)event.getY()); - - if (view.getSnapTo() != 0) { - time = ((int)(time / view.getSnapTo())) * view.getSnapTo(); - } - - Event.Builder e = view.getScore().addEventBuilder(); - e.setStart(time); - e.setEnd(time + view.getSnapTo()); - e.setKey((int)note); - e.getKeyEventBuilder().setChannel(view.getCurrentChannel()); - - eventTool_.pickupEvent(view, e, (int)event.getX(), (int)event.getY(), this); - view.setTool(eventTool_); - return true; - } else { - return false; - } - } - - // The tool that's used to edit the event after it's created, but only until the finger is up. - // Then control returns back to this control. - private EditEventTool eventTool_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java b/android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java deleted file mode 100644 index 9df4e91..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/NewLoopTool.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Music.Event; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for creating new events in the score. - */ -public class NewLoopTool extends ScoreViewTool { - /** - * Creates a new NewEventTool. - * @param context - The context to use for loading resources. - * @param eventTool - The tool to use for editing the event as it's created. - */ - NewLoopTool(Context context, EditEventTool eventTool) { - logger_ = Logger.getLogger(getClass().getName()); - eventTool_ = eventTool; - - icon_ = context.getResources().getDrawable(R.drawable.loop); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - double time = view.getTimeAt((int)event.getX()); - double note = view.getNoteAt((int)event.getY()); - - if (view.getSnapTo() != 0) { - time = ((int)(time / view.getSnapTo())) * view.getSnapTo(); - } - - Event.Builder e = view.getScore().addEventBuilder(); - e.setStart(time); - e.setEnd(time + view.getSnapTo()); - e.setKey((int)note); - e.getLoopEventBuilder().setCount(1); - - eventTool_.pickupEvent(view, e, (int)event.getX(), (int)event.getY(), this); - view.setTool(eventTool_); - return true; - } else { - return false; - } - } - - // The tool that's used to edit the event after it's created, but only until the finger is up. - // Then control returns back to this control. - private EditEventTool eventTool_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java b/android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java deleted file mode 100644 index 594aa3c..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/PlayButton.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.ScorePlayer; -import com.levien.synthesizer.core.music.ScorePlayerListener; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A button to start the current score playing. - */ -public class PlayButton extends ScoreViewTool implements ScorePlayerListener { - /** - * Creates a new play button, loading resources from the given context. - */ - PlayButton(ScoreViewToolbar toolbar, Context context) { - toolbar_ = toolbar; - logger_ = Logger.getLogger(getClass().getName()); - player_ = new ScorePlayer(); - - playing_ = false; - - playingIcon_ = context.getResources().getDrawable(R.drawable.stop); - stoppedIcon_ = context.getResources().getDrawable(R.drawable.play); - paint_ = new Paint(); - } - - /** - * Called when this tool is selected. Starts the score playing. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - view_ = view; - if (playing_) { - player_.stopPlaying(); - } else { - player_.startPlaying(view.getSynthesizer(), view.getScore().build(), 120.0, 4, this); - } - view.setTool(previousTool); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - - if (playing_) { - playingIcon_.setBounds(rect); - playingIcon_.draw(canvas); - } else { - stoppedIcon_.setBounds(rect); - stoppedIcon_.draw(canvas); - } - } - - /** - * Called when the score starts playing. - */ - public void onStart() { - view_.post(new Thread("PlayButton.onStart()") { - public void run() { - playing_ = true; - view_.invalidate(); - toolbar_.invalidate(); - } - }); - } - - /** - * Called every so often during playback. - * @param time - the time in measures from the start of the song. - */ - public void onTimeUpdate(final double time) { - view_.post(new Thread("PlayButton.onTimeUpdate()") { - public void run() { - view_.setCursor(time); - view_.invalidate(); - toolbar_.invalidate(); - } - }); - } - - /** - * Called when the score stops playing. - */ - public void onStop() { - view_.post(new Thread("PlayButton.onStop()") { - public void run() { - playing_ = false; - view_.invalidate(); - } - }); - } - - // The ScoreView that this button controls. - private ScoreView view_; - private ScoreViewToolbar toolbar_; - - // ScorePlayer to play the score. - private ScorePlayer player_; - - // Is the score playing? - private boolean playing_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable playingIcon_; - private Drawable stoppedIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java b/android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java deleted file mode 100644 index 7ff5dc8..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/PlayTool.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.music.Note; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A button to enable "play" mode of the ScoreView. In play mode, pressing anywhere plays the note - * for the key that's being pressed. @see ScoreView. - */ -public class PlayTool extends ScoreViewTool { - /** - * Creates a new PlayTool, loading resources from the given context. - */ - PlayTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - keysDown_ = new int[FINGERS]; - for (int i = 0; i < keysDown_.length; ++i) { - keysDown_[i] = -1; - } - - icon_ = context.getResources().getDrawable(R.drawable.play_piano); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called after each key is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param key - The key that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - @Override - public void afterDrawKey(int key, - Canvas canvas, - Rect rect) { - for (int keyDown : keysDown_) { - if (key == keyDown) { - paint_.setColor(Color.GREEN); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - } - } - } - - /** - * Called to handle touch down events. - * Returns true iff we need to redraw. - */ - private boolean onTouchDown(ScoreView view, int finger, int physicalX, int physicalY) { - int note = (int)Math.floor(view.getNoteAt(physicalY)); - view.getSynthesizer().onNoteOn(view.getCurrentChannel(), note, 64); - keysDown_[finger] = note; - return true; - } - - /** - * Called to handle touch move events. - */ - private boolean onTouchMove(ScoreView view, int finger, int physicalX, int physicalY) { - int note = (int)Math.floor(view.getNoteAt(physicalY)); - int oldNote = keysDown_[finger]; - if (oldNote >= 0) { - view.getSynthesizer().onNoteOff(view.getCurrentChannel(), oldNote, 64); - } - view.getSynthesizer().onNoteOn(view.getCurrentChannel(), note, 64); - keysDown_[finger] = (int)note; - return true; - } - - /** - * Called to handle touch up events. - */ - protected boolean onTouchUp(ScoreView view, int finger) { - int note = keysDown_[finger]; - view.getSynthesizer().onNoteOff(view.getCurrentChannel(), note, 64); - keysDown_[finger] = -1; - return true; - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - boolean redraw = false; - if (actionCode == MotionEvent.ACTION_DOWN) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - int x = (int)event.getX(); - int y = (int)event.getY(); - redraw |= onTouchDown(view, pointerId, x, y); - } - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT; - if (pointerId < FINGERS) { - int pointerIndex = event.findPointerIndex(pointerId); - if (pointerIndex >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - redraw |= onTouchDown(view, pointerId, x, y); - } - } - } else if (actionCode == MotionEvent.ACTION_MOVE) { - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= FINGERS) { - continue; - } - if (pointerIndex >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - redraw |= onTouchMove(view, pointerId, x, y); - } - } - } else if (actionCode == MotionEvent.ACTION_UP) { - int pointerId = event.getPointerId(0); - if (pointerId < FINGERS) { - redraw |= onTouchUp(view, pointerId); - } - // Clean up any other pointers that have disappeared. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - redraw |= onTouchUp(view, pointerId); - } - } - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT; - if (pointerId < FINGERS) { - redraw |= onTouchUp(view, pointerId); - } - // Clean up any other pointers that have disappeared. - for (pointerId = 0; pointerId < FINGERS; ++pointerId) { - boolean found = false; - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - if (pointerId == event.getPointerId(pointerIndex)) { - found = true; - break; - } - } - if (!found) { - redraw |= onTouchUp(view, pointerId); - } - } - } else { - return false; - } - if (redraw) { - view.invalidate(); - } - return true; - } - - // The piano key each finger is holding down, or -1 if a finger is not pressing any key. - private int[] keysDown_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - // The number of simultaneous fingers supported by this control. - protected static final int FINGERS = 5; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java deleted file mode 100644 index 1d8ea5a..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreView.java +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -import com.levien.synthesizer.R; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.music.Music.Event; -import com.levien.synthesizer.core.music.Music.Score; -import com.levien.synthesizer.core.music.Note; - -/** - * ScoreView is a UI widget that allows editing a musical score, as well as live playing. The - * majority of the ScoreView area shows a subsequence of the current musical score. Along the - * y-axis are the keys of a piano. Time is along the x-axis. Along the bottom, there is a toolbar, - * which allows selecting various "tools" to use on the score. - * - * A score is composed of various "events", such as playing a note for a certain duration at a - * certain time, using a certain channel. A ScoreView lets the user create or edit these events. - * - * PlayTool - When selected, pressing plays the note at that x using the selected channel. - * ViewportTool - Sets the currently visible part of the score by touching or dragging. - * NewEventTool - Creates new events. - * EditEventTool - Edits an existing event. - * PlayButton - Starts the score playing audibly. - * SelectChannelButton - Selects a particular channel (instrument) for editing or playing. - * HideChannelButton - Toggles whether to show/hide the channels not currently being edited. - * SnapTool - Changes the "snap to" setting for this ScoreView. - */ -public class ScoreView extends View { - /** - * Basic android widget constructor. - */ - public ScoreView(Context context, AttributeSet attrs) { - super(context, attrs); - - logger_ = Logger.getLogger(getClass().getName()); - - // Set the default time to be 20 measures, and show 5 measures to start. - minTime_ = 0.0; - maxTime_ = 20.0; - timeZoom_ = 0.25; - timeOffset_ = 0.0; - - // Set the piano keys to the range of a normal piano, showing one octave to start. - minNote_ = Note.A; - maxNote_ = Note.A + 88.0; - noteZoom_ = 8.0 / 88.0; - noteOffset_ = 44.0; - - // Snap to eighth notes to start. - snapTo_ = 1.0 / 8.0; - - // Create the score to edit. - score_ = Score.newBuilder(); - - // Setup the channels. - currentChannel_ = 0; - showOtherChannels_ = true; - - // Load the icon to use for each channel. - iconForChannel_ = new Drawable[CHANNELS]; - iconForChannel_[0] = context.getResources().getDrawable(R.drawable.guitar); - iconForChannel_[1] = context.getResources().getDrawable(R.drawable.bass); - iconForChannel_[2] = context.getResources().getDrawable(R.drawable.voice); - iconForChannel_[3] = context.getResources().getDrawable(R.drawable.flute); - iconForChannel_[4] = context.getResources().getDrawable(R.drawable.drums); - - arrowsVisible_ = true; - upSelected_ = false; - downSelected_ = false; - upIcon_ = context.getResources().getDrawable(R.drawable.up); - downIcon_ = context.getResources().getDrawable(R.drawable.down); - - // Set up basic drawing structs, just so we don't have to allocate them later when we draw. - drawingRect_ = new Rect(); - keyRect_ = new Rect(); - eventRect_ = new Rect(); - fillPaint_ = new Paint(); - strokePaint_ = new Paint(); - marginPaint_ = new Paint(); - - fillPaint_.setStyle(Paint.Style.FILL); - strokePaint_.setStyle(Paint.Style.STROKE); - marginPaint_.setStyle(Paint.Style.FILL); - marginPaint_.setColor(Color.GRAY); - } - - /** - * Returns a mutable copy of the score being edited. - */ - public Score.Builder getScore() { - return score_; - } - - /** - * Returns the currently selected channel (instrument). - */ - public int getCurrentChannel() { - return currentChannel_; - } - - /** - * Selects the given channel. - * @param channel - The channel to select. - */ - public void setCurrentChannel(int channel) { - currentChannel_ = channel; - } - - /** - * Returns true iff the given channel is visible in the score. - */ - public boolean isChannelVisible(int channel) { - if (showOtherChannels_) { - return true; - } else { - return channel == currentChannel_; - } - } - - /** - * Returns true iff channels that aren't the current one are visible in the score. - */ - public boolean getOtherChannelsVisible() { - return showOtherChannels_; - } - - /** - * Sets whether channels that aren't the current one are visible in the score. - */ - public void setOtherChannelsVisible(boolean visible) { - showOtherChannels_ = visible; - } - - /** - * Returns the currently selected tool for this ScoreView. - */ - public ScoreViewTool getTool() { - return currentTool_; - } - - /** - * Sets a tool to be the current tool for this ScoreView. Informs listeners of the change. - */ - public void setTool(ScoreViewTool tool) { - ScoreViewTool previousTool = currentTool_; - currentTool_ = tool; - tool.onSelect(this, previousTool); - if (listener_ != null) { - listener_.onSetTool(tool); - } - invalidate(); - } - - /** - * Returns the "snap to" setting for this ScoreView. @see setSnapTo(). - * @return the note that should be snapped to. For example, if editing should snap to the nearest - * quarter note, then returns 0.25. For a whole note, 1.0. For no snapping, returns 0.0. - */ - public double getSnapTo() { - return snapTo_; - } - - /** - * Sets the "snap to" setting for this ScoreView. @see getSnapTo(). - * @param snapTo - the note that should be snapped to. For example, if editing should snap to the - * nearest quarter note, then 0.25. For a whole note, 1.0. For no snapping, 0.0. - */ - public void setSnapTo(double snapTo) { - snapTo_ = snapTo; - } - - /** - * Returns the zoom setting for this control on the x-axis. @see setTimeZoom(). - * @return the multiplier for the x-axis on the viewport. 1.0 means the entire time of the score - * is visible. 0.5 means only half of the score (time-wise) is visible. 2.0 means that the - * entire score is shown, but only takes up half the screen. Any excess space is just "margin". - */ - public double getTimeZoom() { - return timeZoom_; - } - - /** - * Sets the zoom level for this control on the x-axis. @see getTimeZoom(). - * @param zoom - the multiplier for the x-axis on the viewport. 1.0 means the entire time of the - * score is visible. 0.5 means only half of the score (time-wise) is visible. 2.0 means that the - * entire score is shown, but only takes up half the screen. Any excess space is just "margin". - */ - public void setTimeZoom(double zoom) { - timeZoom_ = zoom; - } - - /** - * Returns the zoom setting for this control on the y-axis. @see setNoteZoom(). - * @return the multiplier for the y-axis on the viewport, which controls how many note keys are - * visible. 1.0 means show the entire 88 keys of the piano are visible. N/88 means exactly N - * keys are visible. Values larger than 1.0 means extra "margin" is shown at the top and bottom. - */ - public double getNoteZoom() { - return noteZoom_; - } - - /** - * Sets the zoom setting for this control on the y-axis. @see getNoteZoom(). - * @param zoom - the multiplier for the y-axis on the viewport, which controls how many note keys - * are visible. 1.0 means show the entire 88 keys of the piano are visible. N/88 means exactly N - * keys are visible. Values larger than 1.0 means extra "margin" is shown at the top and bottom. - */ - public void setNoteZoom(double zoom) { - noteZoom_ = zoom; - } - - /** - * Returns the left-most time currently visible in this control. @see setTimeOffset(). - * @return the time, in measures, from the beginning of the score to the first visible time - * in the ScoreView. For example, 5.25 in 4/4 time would mean one quarter note past the end of - * the 5th measure. Negative values mean margin is shown on the left side. - */ - public double getTimeOffset() { - return timeOffset_; - } - - /** - * Sets the left-most time currently visible in this control. @see getTimeOffset(). - * @param offset - The time, in measures, from the beginning of the score to the first visible - * time in the ScoreView. For example, 5.25 in 4/4 time would mean one quarter note past the end - * of the 5th measure. Negative values mean margin is shown on the left side. - */ - public void setTimeOffset(double offset) { - timeOffset_ = offset; - } - - /** - * Returns the bottom-most note key currently visible in this control. @see setNoteOffset(). - * @return the note number of the bottom key visible on the screen. 0.0 means the lowest note is - * fully visible, with its bottom along the bottom edge of the screen. 1.0 means the lowest note - * is not visible, but its top edge is along the bottom of the screen. 88.0 means no keys are - * visible, but the top edge of the highest key is along the bottom of the screen. - */ - public double getNoteOffset() { - return noteOffset_; - } - - /** - * Sets the bottom-most note key currently visible in this control. @see getNoteOffset(). - * @param offset - the note number of the bottom key visible on the screen. 0.0 means the lowest - * note is fully visible, with its bottom along the bottom edge of the screen. 1.0 means the - * lowest note is not visible, but its top edge is along the bottom of the screen. 88.0 means no - * keys are visible, but the top edge of the highest key is along the bottom of the screen. - */ - public void setNoteOffset(double offset) { - noteOffset_ = offset; - } - - /** - * Returns the max time viewable or editable by this ScoreView. @see setMaxTime(). - * @return the time, where 0.0 means no time, 1.0 means one measure, and 10 means ten measures. - */ - public double getMaxTime() { - return maxTime_; - } - - /** - * Sets the max time viewable or editable by this ScoreView. @see getMaxTime(). - * @param max - the time, where 0.0 means no time, 1.0 means one measure, and 10 for ten measures. - */ - public void setMaxTime(double max) { - maxTime_ = max; - } - - /** - * Returns the max possible note viewable or editable by this ScoreView. @see setMaxNote(). - * @return the note number. For a normal piano layout, this method should always return 88.0. - */ - public double getMaxNote() { - return maxNote_; - } - - /** - * Sets the max possible note viewable or editable by this ScoreView. @see getMaxNote(). - * @param max - the note number. For a normal piano layout, this should always be 88.0. - */ - public void setMaxNote(double max) { - maxNote_ = max; - } - - /** - * Returns the rectangle, in screen coordinates, where this ScoreView was most recently drawn. - * @return a reference to the Rect. - */ - public Rect getDrawingRect() { - return drawingRect_; - } - - /** - * Returns the time (logical x) that corresponds to the given pixel (physical x). - * @param pixelX - the x in screen coordinates. - * @return the x in logical coordinates (the time, in measures, from the score start). - */ - public double getTimeAt(int pixelX) { - return timeOffset_ + ((double)(pixelX - drawingRect_.left) / drawingRect_.width()) / timeZoom_; - } - - /** - * Returns the pixel (physical x) that corresponds to the given time (logical x). - * @param time - the time, in measures, from the score start. - * @return the x offset of the given time, in screen coordinates. - */ - public int getTimeX(double time) { - return (int)(((time - timeOffset_) * timeZoom_) * drawingRect_.width() + - drawingRect_.left + 0.5); - } - - /** - * Returns the note (logical y) that corresponds to the given pixel (physical y). - * @param pixelY - the y in screen coordinates. - * @return the y in logical coordinates (the note key, typically from 0 to 88.0). - */ - public double getNoteAt(int pixelY) { - return ((double)(drawingRect_.bottom - pixelY) / drawingRect_.height()) / noteZoom_ + noteOffset_; - } - - /** - * Returns the pixel (physical y) that corresponds to the given note (logical y). - * @param note - the note key. - * @return the y offset of the given note, in screen coordinates. - */ - public int getNoteY(double note) { - return (int)(drawingRect_.bottom - (note - noteOffset_) * drawingRect_.height() * noteZoom_); - } - - /** - * Returns the top-most event at the given coordinates. - * @param physicalX - the x in screen coordinates. - * @param physicalY - the y in screen coordinates. - * @return the mutable event. - */ - public Event.Builder getEventAt(int physicalX, int physicalY) { - double time = getTimeAt(physicalX); - double note = getNoteAt(physicalY); - for (int i = score_.getEventCount() - 1; i >= 0; --i) { - double eventStartTime = score_.getEvent(i).getStart(); - double eventEndTime = score_.getEvent(i).getEnd(); - double eventMinNote = score_.getEvent(i).getKey(); - double eventMaxNote = score_.getEvent(i).getKey() + 1; - if (time >= eventStartTime && - time < eventEndTime && - note >= eventMinNote && - note < eventMaxNote) { - return score_.getEventBuilder(i); - } - } - return null; - } - - /** - * Sets the cursor position that shows where playback is in the score. - * This should only be called from the Android UI thread. - */ - public void setCursor(double cursor) { - cursor_ = cursor; - invalidate(); - } - - /** - * Returns the color to use for representing the given channel in this ScoreView. - * @param channel - the channel. - * @return the color to use, Android style. - */ - public int getColorForChannel(int channel) { - switch (channel % CHANNELS) { - case 0: return Color.rgb(0, 255, 255); - case 1: return Color.rgb(255, 0, 255); - case 2: return Color.rgb(255, 255, 0); - case 3: return Color.rgb(255, 0, 0); - case 4: return Color.rgb(0, 255, 0); - case 5: return Color.rgb(0, 0, 255); - } - return Color.BLACK; - } - - /** - * Returns the icon to use for representing the given channel in this ScoreView. - * @param channel - the channel. - * @return the icon to use, as a Drawable. - */ - public Drawable getIconForChannel(int channel) { - return iconForChannel_[channel % iconForChannel_.length]; - } - - /** - * Called to draw the ScoreView widget. - * @param canvas - the canvas to draw the widget on. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - getDrawingRect(drawingRect_); - - // Clear the rectangle. - fillPaint_.setColor(Color.WHITE); - canvas.drawRect(drawingRect_, fillPaint_); - strokePaint_.setStrokeWidth(1.0f); - - // Draw piano keys to mark the frequencies. - for (int note = (int)minNote_; note < (int)maxNote_; ++note) { - // Draw a single key that fills up a row. - keyRect_.bottom = getNoteY(note); - keyRect_.top = getNoteY(note + 1); - keyRect_.left = getTimeX(0.0); - keyRect_.right = getTimeX(maxTime_); - strokePaint_.setStrokeWidth(2.0f); - strokePaint_.setColor(Color.LTGRAY); - if (Note.isNatural(note)) { - fillPaint_.setColor(Color.WHITE); - } else { - fillPaint_.setColor(Color.LTGRAY); - } - canvas.drawRect(keyRect_, fillPaint_); - canvas.drawRect(keyRect_, strokePaint_); - - if (currentTool_ != null) { - currentTool_.afterDrawKey(note, canvas, keyRect_); - } - } - - // Draw lines to mark the measures. - for (double i = minTime_ + 1; i < maxTime_; ++i) { - strokePaint_.setColor(Color.LTGRAY); - int x = getTimeX(i - 0.75); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - - strokePaint_.setColor(Color.GRAY); - x = getTimeX(i - 0.5); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - - strokePaint_.setColor(Color.LTGRAY); - x = getTimeX(i - 0.25); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - - strokePaint_.setColor(Color.BLACK); - x = getTimeX(i); - canvas.drawLine(x, drawingRect_.top, x, drawingRect_.bottom, strokePaint_); - } - - // Draw the margins. - double leftMargin = getTimeX(minTime_); - if (leftMargin > drawingRect_.left) { - canvas.drawRect(drawingRect_.left, - drawingRect_.top, - (float)leftMargin, - drawingRect_.bottom, - marginPaint_); - } - double rightMargin = getTimeX(maxTime_); - if (rightMargin < drawingRect_.right) { - canvas.drawRect((float)rightMargin, - drawingRect_.top, - drawingRect_.right, - drawingRect_.bottom, - marginPaint_); - } - double topMargin = getNoteY(maxNote_); - if (topMargin > drawingRect_.top) { - canvas.drawRect(drawingRect_.left, - drawingRect_.top, - drawingRect_.right, - (float)topMargin, - marginPaint_); - } - double bottomMargin = getNoteY(minNote_); - if (bottomMargin < drawingRect_.bottom) { - canvas.drawRect(drawingRect_.left, - (float)bottomMargin, - drawingRect_.right, - drawingRect_.bottom, - marginPaint_); - } - - // Draw the sequence. - for (int i = 0; i < score_.getEventCount(); ++i) { - Event event = score_.getEvent(i); - eventRect_.left = getTimeX(event.getStart()); - eventRect_.top = getNoteY(event.getKey() + 1); - eventRect_.right = getTimeX(event.getEnd()); - eventRect_.bottom = getNoteY(event.getKey()); - - if (!event.hasKeyEvent() || isChannelVisible(event.getKeyEvent().getChannel())) { - if (event.getSelected()) { - if (event.hasKeyEvent()) { - fillPaint_.setColor(getColorForChannel(event.getKeyEvent().getChannel())); - strokePaint_.setColor(Color.BLACK); - } else { - fillPaint_.setColor(Color.BLACK); - strokePaint_.setColor(Color.WHITE); - } - fillPaint_.setAlpha(255); - strokePaint_.setStrokeWidth(5.0f); - } else { - if (event.hasKeyEvent()) { - fillPaint_.setColor(getColorForChannel(event.getKeyEvent().getChannel())); - strokePaint_.setColor(Color.BLACK); - } else { - fillPaint_.setColor(Color.BLACK); - strokePaint_.setColor(Color.WHITE); - } - fillPaint_.setAlpha(127); - strokePaint_.setStrokeWidth(1.0f); - } - canvas.drawRect(eventRect_, fillPaint_); - canvas.drawRect(eventRect_, strokePaint_); - - if (currentTool_ != null) { - currentTool_.afterDrawEvent(event, canvas, eventRect_); - } - } - } - - // Draw the cursor. - strokePaint_.setColor(Color.rgb(0, 175, 0)); - strokePaint_.setStrokeWidth(8.0f); - canvas.drawLine(getTimeX(cursor_), drawingRect_.top, - getTimeX(cursor_), drawingRect_.bottom, strokePaint_); - - // Draw the scroll arrows, if visible. - if (arrowsVisible_) { - upIcon_.setBounds(getDrawingRect().left + 50, - getDrawingRect().top + 50, - getDrawingRect().left + 50 + upIcon_.getIntrinsicWidth(), - getDrawingRect().top + 50 + downIcon_.getIntrinsicHeight()); - downIcon_.setBounds(getDrawingRect().left + 50, - (getDrawingRect().bottom - 50) - downIcon_.getIntrinsicHeight(), - getDrawingRect().left + 50 + upIcon_.getIntrinsicWidth(), - getDrawingRect().bottom - 50); - - if (upSelected_) { - fillPaint_.setColor(Color.WHITE); - } else { - fillPaint_.setColor(Color.BLACK); - } - canvas.drawCircle(upIcon_.getBounds().centerX(), - upIcon_.getBounds().centerY(), - upIcon_.getBounds().width(), - fillPaint_); - upIcon_.draw(canvas); - - if (downSelected_) { - fillPaint_.setColor(Color.WHITE); - } else { - fillPaint_.setColor(Color.BLACK); - } - canvas.drawCircle(downIcon_.getBounds().centerX(), - downIcon_.getBounds().centerY(), - downIcon_.getBounds().width(), - fillPaint_); - downIcon_.draw(canvas); - - // Make the bounds for the icons a little larger so they're easier to hit. - downIcon_.getBounds().inset(-50, -50); - upIcon_.getBounds().inset(-50, -50); - } - - if (currentTool_ != null) { - currentTool_.afterDrawScore(this, canvas, drawingRect_); - } - } - - /** - * Handler for all touch events. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - // Check if they touched the arrows. - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - if (actionCode == MotionEvent.ACTION_DOWN) { - if (upIcon_.getBounds().contains((int)event.getX(), (int)event.getY())) { - upSelected_ = true; - invalidate(); - return true; - } else if (downIcon_.getBounds().contains((int)event.getX(), (int)event.getY())) { - downSelected_ = true; - invalidate(); - return true; - } else { - arrowsVisible_ = false; - invalidate(); - } - } else if (actionCode == MotionEvent.ACTION_UP) { - arrowsVisible_ = true; - if (upSelected_) { - // Scroll up. - if (getNoteOffset() < maxNote_) { - setNoteOffset(getNoteOffset() + 1); - } - upSelected_ = false; - } - if (downSelected_) { - // Scroll down. - if (getNoteOffset() > minNote_) { - setNoteOffset(getNoteOffset() - 1); - } - downSelected_ = false; - } - invalidate(); - } - - // Delegate the touch to the current tool. - if (!upSelected_ && !downSelected_ && currentTool_ != null) { - return currentTool_.onTouch(this, event); - } else { - return false; - } - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the widget maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } - - /** - * Connects the ScoreView to a Synthesizer for playback. - * @synth - The synthesizer to connect to. - */ - public void bindTo(final MidiListener synth) { - synthesizer_ = synth; - } - - /** - * Returns the synthesizer connected to this ScoreView. - * @return the connected synthesizer. - */ - public MidiListener getSynthesizer() { - return synthesizer_; - } - - /** - * Sets the listener to notify of events in this control. - * @param listener - the listener to notify. - */ - public void setListener(ScoreViewListener listener) { - listener_ = listener; - } - - // The score being edited, played, etc by this control. - private Score.Builder score_; - - // The current tool being used. - private ScoreViewTool currentTool_; - - // The currently selected channel (instrument). - private int currentChannel_; - - // Whether to show channels other than the currently selected one. - private boolean showOtherChannels_; - - // The set of icons to use for each channel. - private Drawable[] iconForChannel_; - - // What granularity of note to snap to when editing. See getSnapTo and setSnapTo(). - private double snapTo_; - - // The min, max and current viewport for the x and y axes. - private double timeZoom_; - private double timeOffset_; - private double minTime_; - private double maxTime_; - private double noteZoom_; - private double noteOffset_; - private double minNote_; - private double maxNote_; - - // A cursor that indicates where playback is in the score, in logical coordinates. - private double cursor_; - - // The synthesizer this control is bound to. - private MidiListener synthesizer_; - - // The listener to notify of events in this control. - private ScoreViewListener listener_; - - // Buttons to let the user move up and down without switching to the viewport tool. - private boolean arrowsVisible_; - private boolean upSelected_; - private boolean downSelected_; - private Drawable upIcon_; - private Drawable downIcon_; - - // These are basically stack variables for onDraw. They're member variables only so that we can - // avoid reallocating them every time the keyboard is redrawn. - // - // The most recent screen rect that this keyboard was drawn into. - private Rect drawingRect_; - private Rect keyRect_; - private Rect eventRect_; - private Paint fillPaint_; - private Paint strokePaint_; - private Paint marginPaint_; - - // The number of channels (instruments) edittable by this control. - private static final int CHANNELS = 5; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java deleted file mode 100644 index 2dd5349..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -/** - * A listener for events happening in a ScoreView. - */ -public interface ScoreViewListener { - /** - * Called when a new tool is selected for the ScoreView. - */ - void onSetTool(ScoreViewTool tool); -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java deleted file mode 100644 index 5f5efb0..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewTool.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import com.levien.synthesizer.core.music.Music.Event; - -import android.graphics.Canvas; -import android.graphics.Rect; -import android.view.MotionEvent; - -/** - * A base class for tools on the ScoreView's toolbar. - */ -public abstract class ScoreViewTool { - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this tool is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - public abstract void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin); - - /** - * Called when this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - public void onSelect(ScoreView view, ScoreViewTool previousTool) {} - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - public boolean onTouch(ScoreView view, MotionEvent event) { - return false; - } - - /** - * Called after each key is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param key - The key that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - public void afterDrawKey(int key, Canvas canvas, Rect rect) {} - - /** - * Called after each event is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param event - The event that was drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - public void afterDrawEvent(Event event, Canvas canvas, Rect rect) {} - - /** - * Called after the entire score is drawn, to give this tool a chance to draw over it. - * See ScoreView.onDraw() for more information on how ScoreView is drawn. - * @param view - The ScoreView being drawn. - * @param canvas - The canvas the key is drawn into. - * @param rect - The area of the key on the canvas. - */ - public void afterDrawScore(ScoreView view, Canvas canvas, Rect rect) {} -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java b/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java deleted file mode 100644 index 2d97e51..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ScoreViewToolbar.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -/** - * A toolbar that goes in a ScoreView and lets the user choose which tool to use on it. - */ -public class ScoreViewToolbar extends View implements ScoreViewListener { - /** Basic constructor for an Android widget. */ - public ScoreViewToolbar(Context context, AttributeSet attrs) { - super(context, attrs); - - paint_ = new Paint(); - rect_ = new Rect(); - textRect_ = new Rect(); - - // Just hard-code the list of tools. - tool_ = new ScoreViewTool[13]; - tool_[0] = new PlayButton(this, context); - tool_[1] = new ViewportTool(context); - tool_[2] = new EditEventTool(context); - tool_[3] = new NewEventTool(context, (EditEventTool)tool_[2]); - tool_[4] = new NewLoopTool(context, (EditEventTool)tool_[2]); - tool_[5] = new HideChannelButton(context); - tool_[6] = new PlayTool(context); - tool_[7] = new SelectChannelButton(context, 0); - tool_[8] = new SelectChannelButton(context, 1); - tool_[9] = new SelectChannelButton(context, 2); - tool_[10] = new SelectChannelButton(context, 3); - tool_[11] = new SelectChannelButton(context, 4); - tool_[12] = new SnapTool(context); - - toolRect_ = new Rect[tool_.length]; - for (int i = 0; i < tool_.length; ++i) { - toolRect_[i] = new Rect(); - } - } - - /** - * Sets the ScoreView that this toolbar controls. - * @param score - the ScoreView. - */ - public void setScoreView(ScoreView score) { - score_ = score; - score_.setListener(this); - score_.setTool(tool_[1]); - invalidate(); - } - - /** - * Sets the current tool. - * @param tool - the tool to use. - */ - public void onSetTool(ScoreViewTool tool) { - invalidate(); - } - - /** - * Touch event handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - getDrawingRect(rect_); - for (int i = 0; i < tool_.length; ++i) { - if (toolRect_[i].contains((int)event.getX(), (int)event.getY())) { - score_.setTool(tool_[i]); - invalidate(); - break; - } - } - break; - } - - case MotionEvent.ACTION_MOVE: { - break; - } - - case MotionEvent.ACTION_UP: { - break; - } - } - return true; - } - - /** - * Drawing handler. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - getDrawingRect(rect_); - //rect_.set(rect_); - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect_, paint_); - - // Draw the buttons. - float margin = 15.0f; - float waveHeight = (rect_.height() - 2.0f * margin); - float waveWidth = waveHeight; - - float xOffset = margin; - float yOffset = margin; - for (int i = 0; i < tool_.length; ++i) { - paint_.setTextSize(24.0f); - paint_.setColor(Color.WHITE); - if (i == 1) { - xOffset += 2 * margin; - paint_.getTextBounds("Tools ", 0, 6, textRect_); - canvas.drawText("Tools ", xOffset, yOffset + (waveHeight + textRect_.height()) / 2, paint_); - xOffset += textRect_.width(); - xOffset += margin; - } else if (i == 7) { - xOffset += 2 * margin; - paint_.getTextBounds("Instruments ", 0, 12, textRect_); - canvas.drawText("Instruments ", xOffset, yOffset + (waveHeight + textRect_.height()) / 2, paint_); - xOffset += textRect_.width(); - xOffset += margin; - } else if (i == 12) { - xOffset += 2 * margin; - paint_.getTextBounds("Snap to ", 0, 8, textRect_); - canvas.drawText("Snap to ", xOffset, yOffset + (waveHeight + textRect_.height()) / 2, paint_); - xOffset += textRect_.width(); - xOffset += margin; - } - paint_.setColor(Color.BLACK); - - toolRect_[i].left = (int)xOffset; - toolRect_[i].top = (int)yOffset; - toolRect_[i].right = (int)(xOffset + waveWidth); - toolRect_[i].bottom = (int)(yOffset + waveHeight); - - tool_[i].drawButton(canvas, score_, toolRect_[i], margin); - - xOffset += waveWidth; - xOffset += margin; - } - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the width maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = 150; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } - - // The score being edited. - private ScoreView score_; - - // Structures used in drawing that we don't want to reallocate every time we draw. - private Paint paint_; - private Rect rect_; - private Rect textRect_; - - // The set of available tools. - private ScoreViewTool[] tool_; - - // The rect that each tool occupied the last time it was drawn. - private Rect[] toolRect_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java b/android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java deleted file mode 100644 index 4e653f2..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/SelectChannelButton.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A tool for selecting a particular channel in a ScoreView. - */ -public class SelectChannelButton extends ScoreViewTool { - /** - * Creates a tool for selecting the given channel, loading resources using the given context. - */ - SelectChannelButton(Context context, int channel) { - logger_ = Logger.getLogger(getClass().getName()); - channel_ = channel; - paint_ = new Paint(); - } - - /** - * Returns the channel that this control selects. - */ - public int getChannel() { - return channel_; - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - if (getChannel() == score.getCurrentChannel()) { - paint_.setColor(score.getColorForChannel(getChannel())); - } else { - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - Drawable icon = score.getIconForChannel(getChannel()); - icon.setBounds(rect); - icon.draw(canvas); - } - - /** - * Called when this tool is selected. - * Changes the selected channel for the view and then reselects the previously selected tool. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - view.setCurrentChannel(channel_); - view.setTool(previousTool); - } - - // The channel this control selects. - private int channel_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java b/android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java deleted file mode 100644 index 3805df6..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/SnapTool.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import com.levien.synthesizer.R; - -import java.util.logging.Logger; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; - -/** - * A control for selecting the "snap to" setting of a ScoreView. - * @see ScoreView - */ -public class SnapTool extends ScoreViewTool { - /** - * Creates a new SnapTool, loading resources from the given context. - */ - SnapTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - customIcon_ = context.getResources().getDrawable(R.drawable.unknown_note); - noneIcon_ = context.getResources().getDrawable(R.drawable.no_note); - thirtySecondIcon_ = context.getResources().getDrawable(R.drawable.thirtysecond_note); - sixteenthIcon_ = context.getResources().getDrawable(R.drawable.sixteenth_note); - eighthIcon_ = context.getResources().getDrawable(R.drawable.eighth_note); - quarterIcon_ = context.getResources().getDrawable(R.drawable.quarter_note); - halfIcon_ = context.getResources().getDrawable(R.drawable.half_note); - wholeIcon_ = context.getResources().getDrawable(R.drawable.whole_note); - - paint_ = new Paint(); - } - - /** - * Called when this tool is selected. Changes the "snap to" setting for the score view and then - * reselects the previously selected tool. - * @param view - The ScoreView that this toolbar is for. - * @param previousTool - The tool that was selected when this one was chosen. - */ - @Override - public void onSelect(ScoreView view, ScoreViewTool previousTool) { - if (view.getSnapTo() == 0.0) { - view.setSnapTo(1.0); - } else if (view.getSnapTo() <= 0.03125) { - view.setSnapTo(0.0); - } else { - view.setSnapTo(view.getSnapTo() / 2.0); - } - view.setTool(previousTool); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - if (score.getSnapTo() == 1.0) { - wholeIcon_.setBounds(rect); - wholeIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.5) { - halfIcon_.setBounds(rect); - halfIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.25) { - quarterIcon_.setBounds(rect); - quarterIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.125) { - eighthIcon_.setBounds(rect); - eighthIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.0625) { - sixteenthIcon_.setBounds(rect); - sixteenthIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.03125) { - thirtySecondIcon_.setBounds(rect); - thirtySecondIcon_.draw(canvas); - } else if (score.getSnapTo() == 0.0) { - noneIcon_.setBounds(rect); - noneIcon_.draw(canvas); - } else { - customIcon_.setBounds(rect); - customIcon_.draw(canvas); - } - } - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable customIcon_; - private Drawable noneIcon_; - private Drawable thirtySecondIcon_; - private Drawable sixteenthIcon_; - private Drawable eighthIcon_; - private Drawable quarterIcon_; - private Drawable halfIcon_; - private Drawable wholeIcon_; - - @SuppressWarnings("unused") - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java b/android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java deleted file mode 100644 index 19b16f4..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/score/ViewportTool.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.score; - -import java.util.logging.Logger; - -import com.levien.synthesizer.R; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; - -/** - * A tool for adjusting the visible logical area of a ScoreView. - * When this tool is selected, touching moves around the viewport, and pinching zooms in/out. - */ -public class ViewportTool extends ScoreViewTool { - /** - * Creates a new ViewportTool, loading resources from the given context. - */ - ViewportTool(Context context) { - logger_ = Logger.getLogger(getClass().getName()); - - startX1_ = 0; - startX2_ = 0; - startY1_ = 0; - startY2_ = 0; - - icon_ = context.getResources().getDrawable(R.drawable.zoom); - paint_ = new Paint(); - } - - /** - * Draws the button on the toolbar. - * @param canvas - The canvas to draw the button on. - * @param score - The ScoreView that this toolbar is for. - * @param rect - The area of the button to be drawn, including any margin. - * @param margin - The preferred margin around the button, in screen coordinates. - */ - @Override - public void drawButton(Canvas canvas, ScoreView score, Rect rect, float margin) { - if (score.getTool() == this) { - paint_.setColor(Color.WHITE); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect.left - margin / 2, - rect.top - margin / 2, - rect.right + margin / 2, - rect.bottom + margin / 2, - paint_); - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect, paint_); - icon_.setBounds(rect); - icon_.draw(canvas); - } - - /** - * Called when the user touches the ScoreView while this tool is selected. - * @param view - The ScoreView that this tool is for. - * @param event - The touch event that triggered this handler. - * @return true iff this tool handled the touch event. - */ - @Override - public boolean onTouch(ScoreView view, MotionEvent event) { - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - boolean redraw = false; - double timeZoom = view.getTimeZoom(); - double timeOffset = view.getTimeOffset(); - double noteZoom = view.getNoteZoom(); - double noteOffset = view.getNoteOffset(); - - if (actionCode == MotionEvent.ACTION_DOWN) { - int pointerId = event.getPointerId(0); - startX1_ = (int)event.getX(); - startY1_ = (int)event.getY(); - if (pointerId != 0) { - logger_.severe("Initial pointer has id " + pointerId); - } - } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { - int pointerId = action >> MotionEvent.ACTION_POINTER_ID_SHIFT; - int pointerIndex = event.findPointerIndex(pointerId); - if (pointerId == 1 && pointerIndex >= 0) { - startX2_ = (int)event.getX(pointerIndex); - startY2_ = (int)event.getY(pointerIndex); - } - } else if (actionCode == MotionEvent.ACTION_MOVE) { - double currentX1 = 0; - double currentX2 = 0; - double currentY1 = 0; - double currentY2 = 0; - boolean has1 = false; - boolean has2 = false; - - // Find the current positions of the fingers. - for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { - int pointerId = event.getPointerId(pointerIndex); - if (pointerId >= 0) { - int x = (int)event.getX(pointerIndex); - int y = (int)event.getY(pointerIndex); - if (pointerId == 0) { - currentX1 = x; - currentY1 = y; - has1 = true; - } else if (pointerId == 1) { - currentX2 = x; - currentY2 = y; - has2 = true; - } - } - } - - if (has1 && has2) { - // Enforce that finger 1 is to the left of and above finger 2. - if (currentX2 < currentX1) { - double temp = currentX1; - currentX1 = currentX2; - currentX2 = temp; - } - if (currentY2 < currentY1) { - double temp = currentY1; - currentY1 = currentY2; - currentY2 = temp; - } - if (startX2_ < startX1_) { - double temp = startX1_; - startX1_ = startX2_; - startX2_ = temp; - } - if (startY2_ < startY1_) { - double temp = startY1_; - startY1_ = startY2_; - startY2_ = temp; - } - - // Make sure the fingers aren't too close together. - if (startX2_ - startX1_ < 50.0) { - startX2_ = startX1_ + 50.0; - } - if (currentX2 - currentX1 < 50.0) { - currentX2 = currentX1 + 50.0; - } - if (startY2_ - startY1_ < 50.0) { - startY2_ = startY1_ + 50.0; - } - if (currentY2 - currentY1 < 50.0) { - currentY2 = currentY1 + 50.0; - } - - // Figure out the parameters of the new viewport. - double scaleXFactor = Math.abs((currentX1 - currentX2) / (startX1_ - startX2_)); - timeOffset += (startX1_ - currentX1 / scaleXFactor) / - (timeZoom * view.getDrawingRect().width()); - timeZoom *= scaleXFactor; - - double scaleYFactor = Math.abs((currentY1 - currentY2) / (startY1_ - startY2_)); - noteOffset -= (startY1_ - currentY1/scaleYFactor - - view.getDrawingRect().bottom * (1 - 1/scaleYFactor)) / - (noteZoom * view.getDrawingRect().height()); - - noteZoom *= scaleYFactor; - - // Update the tracking. - startX1_ = currentX1; - startX2_ = currentX2; - startY1_ = currentY1; - startY2_ = currentY2; - redraw = true; - } else if (has1) { - // Move the viewport. - timeOffset += (startX1_ - currentX1) / (timeZoom * view.getDrawingRect().width()); - startX1_ = currentX1; - noteOffset -= (startY1_ - currentY1) / (noteZoom * view.getDrawingRect().height()); - startY1_ = currentY1; - redraw = true; - } - } else if (actionCode == MotionEvent.ACTION_UP) { - // Snap back so we aren't showing much margin. - // This code is commented out because it's actually much more intuitive if it doesn't snap - // back but just shows some margin. - /* - if (scaleX < 1.0 / maxX) { - offsetX = 0.0; - scaleX = 1.0 / maxX; - redraw = true; - } - if (scaleY < 1.0 / maxY) { - offsetY = 0.0; - scaleY = 1.0 / maxY; - redraw = true; - } - if (offsetX < 0.0) { - offsetX = 0.0; - redraw = true; - } - if (offsetY < 0.0) { - offsetY = 0.0; - redraw = true; - } - if (offsetX > maxX - 1.0 / scaleX) { - offsetX = maxX - 1.0 / scaleX; - redraw = true; - } - if (offsetY > maxY - 1.0 / scaleY) { - offsetY = maxY - 1.0 / scaleY; - redraw = true; - } - */ - } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { - } else { - return view.onTouchEvent(event); - } - - view.setTimeZoom(timeZoom); - view.setTimeOffset(timeOffset); - view.setNoteZoom(noteZoom); - view.setNoteOffset(noteOffset); - - if (redraw) { - view.invalidate(); - } - - return true; - } - - // The screen coordinates of the first and second fingers pressed on the ScoreView. - // These are updated every time the viewport is updated. - private double startX1_; - private double startX2_; - private double startY1_; - private double startY2_; - - // Some objects used in drawing. They are owned here so that they don't have to be reallocated - // and garbage collected for every pass of drawing. - private Paint paint_; - private Drawable icon_; - - private Logger logger_; -} diff --git a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java b/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java deleted file mode 100644 index d8b9ebb..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.waveform; - -/** - * WaveformListener is an interface for getting events when a WaveformView's value changes. - */ -public interface WaveformListener { - /** - * Called when the value changes. - */ - void onWaveformChanged(String waveform); -} diff --git a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java b/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java deleted file mode 100644 index cd3b5a0..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformRowView.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.waveform; - -import com.levien.synthesizer.core.model.WaveformInput; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.MotionEvent; - -/** - * WaveformRowView is like a WaveformView, but it arranges its buttons in a row. - */ -public class WaveformRowView extends WaveformView { - /** Basic constructor for an Android widget. */ - public WaveformRowView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Touch event handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - getDrawingRect(rect_); - double x = (event.getX() - rect_.left) / rect_.width(); - if (x < 1.0/6.0f) { - setWaveform(WaveformInput.SINE); - } else if (x < 2.0/6.0f) { - setWaveform(WaveformInput.TRIANGLE); - } else if (x < 3.0/6.0f) { - setWaveform(WaveformInput.SQUARE); - } else if (x < 4.0/6.0f) { - setWaveform(WaveformInput.SAWTOOTH); - } else if (x < 5.0/6.0f) { - setWaveform(WaveformInput.NOISE); - } else { - CharSequence[] items = new CharSequence[input_.getWaveformCount()]; - for (int i = 0; i < items.length; ++i) { - items[i] = input_.getWaveform(i); - } - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setItems(items, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - setWaveform(input_.getWaveform(which)); - } - }); - builder.create().show(); - } - invalidate(); - break; - } - - case MotionEvent.ACTION_MOVE: { - break; - } - - case MotionEvent.ACTION_UP: { - break; - } - } - return true; - } - - /** - * Drawing handler. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - getDrawingRect(rect_); - rect_.set(rect_); - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect_, paint_); - - // Draw waveforms. - float lineWidth = 5.0f; - float margin = 15.0f; - float waveWidth = (rect_.width() - 7.0f * margin) / 6.0f; - float waveHeight = (rect_.height() - 2.0f * margin); - - float xOffset = margin; - float yOffset = margin; - drawSine(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawTriangle(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawSquare(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawSawtooth(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawNoise(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - xOffset += waveWidth; - xOffset += margin; - drawOther(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - } - - /** - * Layout measurement for this widget. - * This method just sets a basic minimum size and makes the width maximized otherwise. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width = 0; - int height = 0; - - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 10; - break; - } - - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = 150; - break; - case MeasureSpec.UNSPECIFIED: - height = 10; - break; - } - - setMeasuredDimension(width, height); - } -} diff --git a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java b/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java deleted file mode 100644 index 430c14c..0000000 --- a/android/src/com/levien/synthesizer/android/widgets/waveform/WaveformView.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.android.widgets.waveform; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import com.levien.synthesizer.core.model.WaveformInput; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; - -/** - * WaveformView is a control for selecting from among available waveforms. - * It's designed to occupy the same space as a KnobView. - */ -public class WaveformView extends View { - /** Basic constructor for an Android widget. */ - public WaveformView(Context context, AttributeSet attrs) { - super(context, attrs); - - waveform_ = WaveformInput.SINE; - - // Set up the drawing structures. - paint_ = new Paint(); - path_ = new Path(); - rect_ = new Rect(); - - // The listener has to be set later. - listener_ = null; - - setPadding(3, 3, 3, 3); - } - - /** - * Touch event handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_DOWN: { - getDrawingRect(rect_); - double x = (event.getX() - rect_.left) / rect_.width(); - double y = (event.getY() - rect_.top) / rect_.height(); - if (x < 0.5) { - if (y < 0.34) { - setWaveform(WaveformInput.SINE); - } else if (y < 0.67) { - setWaveform(WaveformInput.TRIANGLE); - } else { - setWaveform(WaveformInput.SQUARE); - } - } else { - if (y < 0.34) { - setWaveform(WaveformInput.SAWTOOTH); - } else if (y < 0.67) { - setWaveform(WaveformInput.NOISE); - } - } - invalidate(); - break; - } - - case MotionEvent.ACTION_MOVE: { - break; - } - - case MotionEvent.ACTION_UP: { - break; - } - } - return true; - } - - /** - * Sets the listener to receive events when the value changes. - */ - public void setWaveformListener(WaveformListener listener) { - listener_ = listener; - } - - /** - * Sets the current value of the knob. - */ - public void setWaveform(String waveform) { - waveform_ = waveform; - if (listener_ != null) { - listener_.onWaveformChanged(waveform); - } - invalidate(); - } - - /** - * Returns the current value of the knob. - */ - public String getWaveform() { - return waveform_; - } - - /** - * Draws a button for selecting a sine waveform. - */ - protected void drawSine(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - int steps = 12; - - // Sine wave. - path_.reset(); - path_.moveTo(x, y + (height / 2)); - for (int i = 0; i < steps + 1; i++) { - float x1 = x + (i / (float)steps) * width; - float y1 = y + -1 * (height/2) * (float)Math.sin(2.0f/steps * Math.PI * i) + height/2; - path_.lineTo(x1, y1); - } - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.SINE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a triangle waveform. - */ - protected void drawTriangle(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Triangle Wave. - path_.reset(); - path_.moveTo(x, y + (height / 2)); - path_.lineTo(x + width / 4, y); - path_.lineTo(x + width * (3.0f / 4.0f), y + height); - path_.lineTo(x + width, y + (height / 2)); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.TRIANGLE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a square waveform. - */ - protected void drawSquare(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Square Wave. - path_.reset(); - path_.moveTo(x, y + height); - path_.lineTo(x + width / 4, y + height); - path_.lineTo(x + width / 4, y); - path_.lineTo(x + width * (3.0f / 4.0f), y); - path_.lineTo(x + width * (3.0f / 4.0f), y + height); - path_.lineTo(x + width, y + height); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.SQUARE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a sawtooth waveform. - */ - protected void drawSawtooth(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Sawtooth Wave. - path_.reset(); - path_.moveTo(x, y + height); - path_.lineTo(x, y); - path_.lineTo(x + width / 2, y + height); - path_.lineTo(x + width / 2, y); - path_.lineTo(x + width, y + height); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.SAWTOOTH)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a noise waveform. - */ - protected void drawNoise(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - // Noise. - path_.reset(); - path_.moveTo(x, y + height * 0.5f); - path_.lineTo(x + 0.125f * width, y + height * 0.4f); - path_.lineTo(x + 0.25f * width, y + height * 1.0f); - path_.lineTo(x + 0.375f * width, y + height * 0.3f); - path_.lineTo(x + 0.5f * width, y + height * 0.7f); - path_.lineTo(x + 0.625f * width, y + height * 0.0f); - path_.lineTo(x + 0.75f * width, y + height * 0.8f); - path_.lineTo(x + 0.875f * width, y + height * 0.2f); - path_.lineTo(x + 1.0f * width, y + height * 0.5f); - paint_.setColor(Color.WHITE); - if (waveform_.equals(WaveformInput.NOISE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - canvas.drawPath(path_, paint_); - } - - /** - * Draws a button for selecting a Karplus-Strong waveform. - */ - protected void drawOther(Canvas canvas, - float x, float y, - float width, float height, - float margin, - float lineWidth) { - int steps = 12; - - paint_.setColor(Color.WHITE); - if (!waveform_.equals(WaveformInput.SINE) && - !waveform_.equals(WaveformInput.TRIANGLE) && - !waveform_.equals(WaveformInput.SAWTOOTH) && - !waveform_.equals(WaveformInput.SQUARE) && - !waveform_.equals(WaveformInput.NOISE)) { - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(x - margin / 2, - y - margin / 2, - x + width + margin / 2, - y + height + margin / 2, - paint_); - paint_.setColor(Color.BLACK); - } - paint_.setStyle(Paint.Style.STROKE); - paint_.setStrokeWidth(lineWidth); - paint_.setStrokeJoin(Paint.Join.ROUND); - - path_.reset(); - path_.moveTo(x, y + (height / 2)); - for (int i = 0; i < steps + 1; i++) { - float x1 = x + (i / (float)steps) * width; - float y1 = y + -1 * (height/2) * (float)Math.sin(2.0f/steps * Math.PI * i) + height/2; - path_.lineTo(x1, y1); - } - canvas.drawPath(path_, paint_); - - path_.reset(); - path_.moveTo(x, y + (height / 2)); - for (int i = 0; i < steps + 1; i++) { - float x1 = x + (i / (float)steps) * width; - float y1 = y + -0.6f * (height/2) * (float)Math.sin(2.0f/steps * Math.PI * (steps-i)) + height/2; - path_.lineTo(x1, y1); - } - canvas.drawPath(path_, paint_); - } - - /** - * Drawing handler. - */ - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - getDrawingRect(rect_); - rect_.set(rect_); - // Make it square. - if (rect_.height() > rect_.width()) { - int center = rect_.centerY(); - rect_.top = center - rect_.width() / 2; - rect_.bottom = center + rect_.width() / 2; - } else { - int center = rect_.centerX(); - rect_.left = center - rect_.height() / 2; - rect_.right = center + rect_.height() / 2; - } - - paint_.setColor(Color.BLACK); - paint_.setStyle(Paint.Style.FILL); - canvas.drawRect(rect_, paint_); - - // Draw waveforms. - float lineWidth = 5.0f; - float margin = 15.0f; - float waveWidth = (rect_.width() - 3.0f * margin) / 2.0f; - float waveHeight = (rect_.height() - 4.0f * margin) / 3.0f; - - float xOffset = margin; - float yOffset = margin; - drawSine(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawTriangle(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawSquare(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset = margin; - xOffset += waveWidth; - xOffset += margin; - drawSawtooth(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawNoise(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - yOffset += waveHeight; - yOffset += margin; - drawOther(canvas, xOffset, yOffset, waveWidth, waveHeight, margin, lineWidth); - } - - /** - * Controls how the knob is sized; it is square, and prefers to be 100x100 pixels. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - // Specify that 100 is preferred for both dimensions. - int width = 0; - int height = 0; - switch (widthMode) { - case MeasureSpec.EXACTLY: - width = widthSize; - break; - case MeasureSpec.AT_MOST: - width = widthSize; - break; - case MeasureSpec.UNSPECIFIED: - width = 100; - break; - } - switch (heightMode) { - case MeasureSpec.EXACTLY: - height = heightSize; - break; - case MeasureSpec.AT_MOST: - height = heightSize; - break; - case MeasureSpec.UNSPECIFIED: - height = 100; - break; - } - - // Make it square. - if (width > height && widthMode != MeasureSpec.EXACTLY) { - width = height; - } - if (height > width && heightMode != MeasureSpec.EXACTLY) { - height = width; - } - - setMeasuredDimension(width, height); - } - - /** - * Connects control to a WaveformInput. - * @input - The synthesizer input to connect to. - */ - public void bindTo(WaveformInput waveform) { - input_ = waveform; - setWaveform(waveform.getWaveform(waveform.getSelected())); - setWaveformListener(new WaveformListener() { - public void onWaveformChanged(String newValue) { - input_.select(newValue); - } - }); - } - - /** - * Connects control to a WaveformSelector module. - * @synth - The synthesizer to connect to. - * @setting - The setting to connect to. - * @return - True on success, false on failure. - */ - public boolean bindTo(final MultiChannelSynthesizer synth, int channel, Setting setting) { - WaveformInput input = synth.getChannel(0).getWaveformInput(setting); - if (input != null) { - bindTo(input); - return true; - } else { - Log.e(getClass().getName(), "Unable to bind to setting " + setting.name() + "."); - return false; - } - } - - // Currently selected waveform. - private String waveform_; - protected WaveformInput input_; - - // Structures used in drawing that we don't want to reallocate every time we draw. - protected Paint paint_; - protected Path path_; - protected Rect rect_; - - // Object listening for events when the knob's value changes. - private WaveformListener listener_; -} diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..d158a9e --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.model.application' + +model { + android { + compileSdkVersion 23 + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "com.levien.synthesizer" + minSdkVersion.apiLevel 16 + targetSdkVersion.apiLevel 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles.add(file('proguard-android.txt')) + } + } + ndk { + moduleName "synth" + ldLibs.addAll(['log', 'OpenSLES']) + } + sources { + main { + jni { + source { + excludes.addAll(["main.cc", "wavout.cc", "test_*.cc", "SynthApp/*"]) + } + } + } + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.4.0' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..0b51b5f --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/raph/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java b/app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java new file mode 100644 index 0000000..12634bc --- /dev/null +++ b/app/src/androidTest/java/com/levien/synthesizer/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.levien.synthesizer; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..f1b60d7 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/src/com/levien/synthesizer/android/AndroidGlue.java b/app/src/main/java/com/levien/synthesizer/android/AndroidGlue.java similarity index 100% rename from android/src/com/levien/synthesizer/android/AndroidGlue.java rename to app/src/main/java/com/levien/synthesizer/android/AndroidGlue.java diff --git a/android/src/com/levien/synthesizer/android/service/SynthesizerService.java b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerService.java similarity index 97% rename from android/src/com/levien/synthesizer/android/service/SynthesizerService.java rename to app/src/main/java/com/levien/synthesizer/android/service/SynthesizerService.java index e17c3b6..1aa7e42 100755 --- a/android/src/com/levien/synthesizer/android/service/SynthesizerService.java +++ b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerService.java @@ -43,7 +43,6 @@ import com.levien.synthesizer.android.AndroidGlue; import com.levien.synthesizer.android.usb.UsbMidiDevice; import com.levien.synthesizer.core.midi.MessageTee; import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; /** * An Android Service that plays audio from a synthesizer. @@ -56,15 +55,6 @@ public class SynthesizerService extends Service { public SynthesizerService getService() { return SynthesizerService.this; } - - /** - * Gets the underlying synthesizer powering this service. - * - * Obsolete, to be deleted. - */ - public MultiChannelSynthesizer getSynthesizer() { - return null; - } } /** diff --git a/android/src/com/levien/synthesizer/android/service/SynthesizerThread.java b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerThread.java similarity index 90% rename from android/src/com/levien/synthesizer/android/service/SynthesizerThread.java rename to app/src/main/java/com/levien/synthesizer/android/service/SynthesizerThread.java index ca1e816..a6765ce 100755 --- a/android/src/com/levien/synthesizer/android/service/SynthesizerThread.java +++ b/app/src/main/java/com/levien/synthesizer/android/service/SynthesizerThread.java @@ -14,14 +14,14 @@ * limitations under the License. */ +// This class is probably obsolete and should be deleted + package com.levien.synthesizer.android.service; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; import android.util.Log; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; /** * SynthesizerThread is a thread-safe interface to a thread that constantly plays sampled audio data @@ -30,18 +30,14 @@ import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; public class SynthesizerThread { /** * Creates a new SynthesizerThread that will play audio from synthesizer. - * @param synthesizer - the source of the audio data to output. */ - public SynthesizerThread(MultiChannelSynthesizer synthesizer, int sampleRateInHz) { + public SynthesizerThread(int sampleRateInHz) { playingLock_ = new Object(); playing_ = false; shouldDie_ = false; audioTrackLock_ = new Object(); audioTrack_ = null; - synthesizer_ = synthesizer; sampleRateInHz_ = sampleRateInHz; - time_ = new SynthesisTime(); - time_.setSampleRate(sampleRateInHz); } /** @@ -141,7 +137,6 @@ public class SynthesizerThread { bufferSizeInBytes, // int bufferSizeInBytes, AudioTrack.MODE_STREAM); // int mode); buffer_ = new short[bufferSizeInBytes / 8]; - time_.reset(); } } @@ -177,7 +172,7 @@ public class SynthesizerThread { for (int i = 0; i < buffer_.length; ++i) { // Change the output range from [-1, 1] to [-32767, 32767]. // 16-bit signed output is fairly standard, and hard-coded. - double output = synthesizer_.getValue(time_); + double output = 0; // Clamp values out of range. if (output < -1.0) { output = -1.0; @@ -186,7 +181,6 @@ public class SynthesizerThread { output = 1.0; } buffer_[i] = (short)(32767 * output); - time_.advance(); } synchronized (audioTrackLock_) { if (audioTrack_ != null) { @@ -221,10 +215,4 @@ public class SynthesizerThread { // The sample rate of the synthesizer. private int sampleRateInHz_; - - // Tracker for time since synthesis started. - private SynthesisTime time_; - - // Module to provide sampled audio data to be output. - private MultiChannelSynthesizer synthesizer_; } diff --git a/android/src/com/levien/synthesizer/android/stats/JitterStats.java b/app/src/main/java/com/levien/synthesizer/android/stats/JitterStats.java similarity index 100% rename from android/src/com/levien/synthesizer/android/stats/JitterStats.java rename to app/src/main/java/com/levien/synthesizer/android/stats/JitterStats.java diff --git a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java b/app/src/main/java/com/levien/synthesizer/android/ui/PianoActivity2.java similarity index 99% rename from android/src/com/levien/synthesizer/android/ui/PianoActivity2.java rename to app/src/main/java/com/levien/synthesizer/android/ui/PianoActivity2.java index 26da9c0..0008473 100644 --- a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java +++ b/app/src/main/java/com/levien/synthesizer/android/ui/PianoActivity2.java @@ -89,9 +89,11 @@ public class PianoActivity2 extends SynthActivity implements OnSharedPreferenceC case R.id.settings: startActivity(new Intent(this, SettingsActivity.class)); return true; + /* case R.id.compose: startActivity(new Intent(this, ScoreActivity.class)); return true; + */ default: return super.onOptionsItemSelected(item); } diff --git a/android/src/com/levien/synthesizer/android/ui/SettingsActivity.java b/app/src/main/java/com/levien/synthesizer/android/ui/SettingsActivity.java similarity index 100% rename from android/src/com/levien/synthesizer/android/ui/SettingsActivity.java rename to app/src/main/java/com/levien/synthesizer/android/ui/SettingsActivity.java diff --git a/android/src/com/levien/synthesizer/android/ui/SynthActivity.java b/app/src/main/java/com/levien/synthesizer/android/ui/SynthActivity.java similarity index 100% rename from android/src/com/levien/synthesizer/android/ui/SynthActivity.java rename to app/src/main/java/com/levien/synthesizer/android/ui/SynthActivity.java diff --git a/android/src/com/levien/synthesizer/android/usb/UsbMidiDevice.java b/app/src/main/java/com/levien/synthesizer/android/usb/UsbMidiDevice.java similarity index 100% rename from android/src/com/levien/synthesizer/android/usb/UsbMidiDevice.java rename to app/src/main/java/com/levien/synthesizer/android/usb/UsbMidiDevice.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeySpec.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardSpec.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/KeyboardView.java diff --git a/android/src/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/keyboard/ScrollStripView.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobListener.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobListener.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobListener.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobListener.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPlaceholderView.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobPreference.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPreference.java similarity index 100% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobPreference.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobPreference.java diff --git a/android/src/com/levien/synthesizer/android/widgets/knob/KnobView.java b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobView.java similarity index 88% rename from android/src/com/levien/synthesizer/android/widgets/knob/KnobView.java rename to app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobView.java index ece5e14..7f95c16 100644 --- a/android/src/com/levien/synthesizer/android/widgets/knob/KnobView.java +++ b/app/src/main/java/com/levien/synthesizer/android/widgets/knob/KnobView.java @@ -34,9 +34,6 @@ import android.view.MotionEvent; import android.view.View; import com.levien.synthesizer.R; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.model.composite.Presets.Setting; /** * KnobView is a widget for setting a real value by turning a virtual "knob". @@ -262,36 +259,6 @@ public class KnobView extends View { setMeasuredDimension(width, height); } - /** - * Connects knob to a SynthesizerInput. - * @input - The synthesizer input to connect to. - */ - public void bindTo(final SynthesizerInput input) { - setValue(input.getSynthesizerInputValue()); - setKnobListener(new KnobListener() { - public void onKnobChanged(double newValue) { - input.setValue(newValue); - } - }); - } - - /** - * Connects knob to a SynthesizerInput. - * @synth - The synthesizer to connect to. - * @path - The setting to connect to. - * @return - True on success, false on failure. - */ - public boolean bindTo(final MultiChannelSynthesizer synth, int channel, Setting setting) { - SynthesizerInput input = synth.getChannel(channel).getSynthesizerInput(setting); - if (input != null) { - bindTo(input); - return true; - } else { - Log.e(getClass().getName(), "Unable to bind to setting " + setting.name() + "."); - return false; - } - } - // Knob's current value, ranges from 0 - 1.0. private double knobValue_; private double min_; diff --git a/core/src/com/levien/synthesizer/core/midi/MessageFromBytes.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageFromBytes.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageFromBytes.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageFromBytes.java diff --git a/core/src/com/levien/synthesizer/core/midi/MessageInputProcessor.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageInputProcessor.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageInputProcessor.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageInputProcessor.java diff --git a/core/src/com/levien/synthesizer/core/midi/MessageOutputProcessor.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageOutputProcessor.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageOutputProcessor.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageOutputProcessor.java diff --git a/core/src/com/levien/synthesizer/core/midi/MessageTee.java b/app/src/main/java/com/levien/synthesizer/core/midi/MessageTee.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MessageTee.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MessageTee.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiAdapter.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiAdapter.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiAdapter.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiAdapter.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiChannelFilter.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiChannelFilter.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiChannelFilter.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiChannelFilter.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiEvent.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiEvent.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiEvent.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiEvent.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiFile.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiFile.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiFile.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiFile.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiFilePlayer.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiFilePlayer.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiFilePlayer.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiFilePlayer.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiHeader.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiHeader.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiHeader.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiHeader.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiListener.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiListener.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiListener.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiListener.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiListenerProxy.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiListenerProxy.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiListenerProxy.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiListenerProxy.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiReader.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiReader.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiReader.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiReader.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiTrack.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiTrack.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiTrack.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiTrack.java diff --git a/core/src/com/levien/synthesizer/core/midi/MidiUtil.java b/app/src/main/java/com/levien/synthesizer/core/midi/MidiUtil.java similarity index 100% rename from core/src/com/levien/synthesizer/core/midi/MidiUtil.java rename to app/src/main/java/com/levien/synthesizer/core/midi/MidiUtil.java diff --git a/cpp/src/SynthApp.gyp b/app/src/main/jni/SynthApp.gyp similarity index 100% rename from cpp/src/SynthApp.gyp rename to app/src/main/jni/SynthApp.gyp diff --git a/cpp/src/SynthApp.xcodeproj/project.pbxproj b/app/src/main/jni/SynthApp.xcodeproj/project.pbxproj similarity index 100% rename from cpp/src/SynthApp.xcodeproj/project.pbxproj rename to app/src/main/jni/SynthApp.xcodeproj/project.pbxproj diff --git a/cpp/src/SynthApp/English.lproj/InfoPlist.strings b/app/src/main/jni/SynthApp/English.lproj/InfoPlist.strings similarity index 100% rename from cpp/src/SynthApp/English.lproj/InfoPlist.strings rename to app/src/main/jni/SynthApp/English.lproj/InfoPlist.strings diff --git a/cpp/src/SynthApp/English.lproj/MainMenu.xib b/app/src/main/jni/SynthApp/English.lproj/MainMenu.xib similarity index 100% rename from cpp/src/SynthApp/English.lproj/MainMenu.xib rename to app/src/main/jni/SynthApp/English.lproj/MainMenu.xib diff --git a/cpp/src/SynthApp/Synth-Info.plist b/app/src/main/jni/SynthApp/Synth-Info.plist similarity index 100% rename from cpp/src/SynthApp/Synth-Info.plist rename to app/src/main/jni/SynthApp/Synth-Info.plist diff --git a/cpp/src/SynthApp/SynthAppDelegate.h b/app/src/main/jni/SynthApp/SynthAppDelegate.h similarity index 100% rename from cpp/src/SynthApp/SynthAppDelegate.h rename to app/src/main/jni/SynthApp/SynthAppDelegate.h diff --git a/cpp/src/SynthApp/SynthAppDelegate.mm b/app/src/main/jni/SynthApp/SynthAppDelegate.mm similarity index 100% rename from cpp/src/SynthApp/SynthAppDelegate.mm rename to app/src/main/jni/SynthApp/SynthAppDelegate.mm diff --git a/cpp/src/SynthApp/SynthApp_Prefix.pch b/app/src/main/jni/SynthApp/SynthApp_Prefix.pch similarity index 100% rename from cpp/src/SynthApp/SynthApp_Prefix.pch rename to app/src/main/jni/SynthApp/SynthApp_Prefix.pch diff --git a/cpp/src/SynthApp/SynthMain.h b/app/src/main/jni/SynthApp/SynthMain.h similarity index 100% rename from cpp/src/SynthApp/SynthMain.h rename to app/src/main/jni/SynthApp/SynthMain.h diff --git a/cpp/src/SynthApp/SynthMain.mm b/app/src/main/jni/SynthApp/SynthMain.mm similarity index 100% rename from cpp/src/SynthApp/SynthMain.mm rename to app/src/main/jni/SynthApp/SynthMain.mm diff --git a/cpp/src/SynthApp/main.m b/app/src/main/jni/SynthApp/main.m similarity index 100% rename from cpp/src/SynthApp/main.m rename to app/src/main/jni/SynthApp/main.m diff --git a/cpp/src/SynthApp/midi_in_mac.cc b/app/src/main/jni/SynthApp/midi_in_mac.cc similarity index 100% rename from cpp/src/SynthApp/midi_in_mac.cc rename to app/src/main/jni/SynthApp/midi_in_mac.cc diff --git a/cpp/src/SynthApp/midi_in_mac.h b/app/src/main/jni/SynthApp/midi_in_mac.h similarity index 100% rename from cpp/src/SynthApp/midi_in_mac.h rename to app/src/main/jni/SynthApp/midi_in_mac.h diff --git a/cpp/src/aligned_buf.h b/app/src/main/jni/aligned_buf.h similarity index 100% rename from cpp/src/aligned_buf.h rename to app/src/main/jni/aligned_buf.h diff --git a/cpp/src/android_glue.cc b/app/src/main/jni/android_glue.cc similarity index 100% rename from cpp/src/android_glue.cc rename to app/src/main/jni/android_glue.cc diff --git a/cpp/src/controllers.h b/app/src/main/jni/controllers.h similarity index 100% rename from cpp/src/controllers.h rename to app/src/main/jni/controllers.h diff --git a/cpp/src/core.gyp b/app/src/main/jni/core.gyp similarity index 100% rename from cpp/src/core.gyp rename to app/src/main/jni/core.gyp diff --git a/cpp/src/core.xcodeproj/project.pbxproj b/app/src/main/jni/core.xcodeproj/project.pbxproj similarity index 100% rename from cpp/src/core.xcodeproj/project.pbxproj rename to app/src/main/jni/core.xcodeproj/project.pbxproj diff --git a/cpp/src/dx7note.cc b/app/src/main/jni/dx7note.cc similarity index 100% rename from cpp/src/dx7note.cc rename to app/src/main/jni/dx7note.cc diff --git a/cpp/src/dx7note.h b/app/src/main/jni/dx7note.h similarity index 100% rename from cpp/src/dx7note.h rename to app/src/main/jni/dx7note.h diff --git a/cpp/src/env.cc b/app/src/main/jni/env.cc similarity index 100% rename from cpp/src/env.cc rename to app/src/main/jni/env.cc diff --git a/cpp/src/env.h b/app/src/main/jni/env.h similarity index 100% rename from cpp/src/env.h rename to app/src/main/jni/env.h diff --git a/cpp/src/exp2.cc b/app/src/main/jni/exp2.cc similarity index 100% rename from cpp/src/exp2.cc rename to app/src/main/jni/exp2.cc diff --git a/cpp/src/exp2.h b/app/src/main/jni/exp2.h similarity index 100% rename from cpp/src/exp2.h rename to app/src/main/jni/exp2.h diff --git a/cpp/src/fir.cc b/app/src/main/jni/fir.cc similarity index 100% rename from cpp/src/fir.cc rename to app/src/main/jni/fir.cc diff --git a/cpp/src/fir.h b/app/src/main/jni/fir.h similarity index 100% rename from cpp/src/fir.h rename to app/src/main/jni/fir.h diff --git a/cpp/src/fm_core.cc b/app/src/main/jni/fm_core.cc similarity index 100% rename from cpp/src/fm_core.cc rename to app/src/main/jni/fm_core.cc diff --git a/cpp/src/fm_core.h b/app/src/main/jni/fm_core.h similarity index 100% rename from cpp/src/fm_core.h rename to app/src/main/jni/fm_core.h diff --git a/cpp/src/fm_op_kernel.cc b/app/src/main/jni/fm_op_kernel.cc similarity index 100% rename from cpp/src/fm_op_kernel.cc rename to app/src/main/jni/fm_op_kernel.cc diff --git a/cpp/src/fm_op_kernel.h b/app/src/main/jni/fm_op_kernel.h similarity index 100% rename from cpp/src/fm_op_kernel.h rename to app/src/main/jni/fm_op_kernel.h diff --git a/cpp/src/freqlut.cc b/app/src/main/jni/freqlut.cc similarity index 100% rename from cpp/src/freqlut.cc rename to app/src/main/jni/freqlut.cc diff --git a/cpp/src/freqlut.h b/app/src/main/jni/freqlut.h similarity index 100% rename from cpp/src/freqlut.h rename to app/src/main/jni/freqlut.h diff --git a/cpp/src/lfo.cc b/app/src/main/jni/lfo.cc similarity index 100% rename from cpp/src/lfo.cc rename to app/src/main/jni/lfo.cc diff --git a/cpp/src/lfo.h b/app/src/main/jni/lfo.h similarity index 100% rename from cpp/src/lfo.h rename to app/src/main/jni/lfo.h diff --git a/cpp/src/log2.cc b/app/src/main/jni/log2.cc similarity index 100% rename from cpp/src/log2.cc rename to app/src/main/jni/log2.cc diff --git a/cpp/src/log2.h b/app/src/main/jni/log2.h similarity index 100% rename from cpp/src/log2.h rename to app/src/main/jni/log2.h diff --git a/cpp/src/main.cc b/app/src/main/jni/main.cc similarity index 100% rename from cpp/src/main.cc rename to app/src/main/jni/main.cc diff --git a/cpp/src/main.gyp b/app/src/main/jni/main.gyp similarity index 100% rename from cpp/src/main.gyp rename to app/src/main/jni/main.gyp diff --git a/cpp/src/module.h b/app/src/main/jni/module.h similarity index 100% rename from cpp/src/module.h rename to app/src/main/jni/module.h diff --git a/cpp/src/neon_fir.s b/app/src/main/jni/neon_fir.s similarity index 100% rename from cpp/src/neon_fir.s rename to app/src/main/jni/neon_fir.s diff --git a/cpp/src/neon_fm_kernel.s b/app/src/main/jni/neon_fm_kernel.s similarity index 100% rename from cpp/src/neon_fm_kernel.s rename to app/src/main/jni/neon_fm_kernel.s diff --git a/cpp/src/neon_iir.s b/app/src/main/jni/neon_iir.s similarity index 100% rename from cpp/src/neon_iir.s rename to app/src/main/jni/neon_iir.s diff --git a/cpp/src/neon_ladder.s b/app/src/main/jni/neon_ladder.s similarity index 100% rename from cpp/src/neon_ladder.s rename to app/src/main/jni/neon_ladder.s diff --git a/cpp/src/patch.cc b/app/src/main/jni/patch.cc similarity index 100% rename from cpp/src/patch.cc rename to app/src/main/jni/patch.cc diff --git a/cpp/src/patch.h b/app/src/main/jni/patch.h similarity index 100% rename from cpp/src/patch.h rename to app/src/main/jni/patch.h diff --git a/cpp/src/pitchenv.cc b/app/src/main/jni/pitchenv.cc similarity index 100% rename from cpp/src/pitchenv.cc rename to app/src/main/jni/pitchenv.cc diff --git a/cpp/src/pitchenv.h b/app/src/main/jni/pitchenv.h similarity index 100% rename from cpp/src/pitchenv.h rename to app/src/main/jni/pitchenv.h diff --git a/cpp/src/resofilter.cc b/app/src/main/jni/resofilter.cc similarity index 100% rename from cpp/src/resofilter.cc rename to app/src/main/jni/resofilter.cc diff --git a/cpp/src/resofilter.h b/app/src/main/jni/resofilter.h similarity index 100% rename from cpp/src/resofilter.h rename to app/src/main/jni/resofilter.h diff --git a/cpp/src/ringbuffer.cc b/app/src/main/jni/ringbuffer.cc similarity index 100% rename from cpp/src/ringbuffer.cc rename to app/src/main/jni/ringbuffer.cc diff --git a/cpp/src/ringbuffer.h b/app/src/main/jni/ringbuffer.h similarity index 100% rename from cpp/src/ringbuffer.h rename to app/src/main/jni/ringbuffer.h diff --git a/cpp/src/sawtooth.cc b/app/src/main/jni/sawtooth.cc similarity index 100% rename from cpp/src/sawtooth.cc rename to app/src/main/jni/sawtooth.cc diff --git a/cpp/src/sawtooth.h b/app/src/main/jni/sawtooth.h similarity index 100% rename from cpp/src/sawtooth.h rename to app/src/main/jni/sawtooth.h diff --git a/cpp/src/sin.cc b/app/src/main/jni/sin.cc similarity index 100% rename from cpp/src/sin.cc rename to app/src/main/jni/sin.cc diff --git a/cpp/src/sin.h b/app/src/main/jni/sin.h similarity index 100% rename from cpp/src/sin.h rename to app/src/main/jni/sin.h diff --git a/cpp/src/synth.h b/app/src/main/jni/synth.h similarity index 100% rename from cpp/src/synth.h rename to app/src/main/jni/synth.h diff --git a/cpp/src/synth_unit.cc b/app/src/main/jni/synth_unit.cc similarity index 100% rename from cpp/src/synth_unit.cc rename to app/src/main/jni/synth_unit.cc diff --git a/cpp/src/synth_unit.h b/app/src/main/jni/synth_unit.h similarity index 100% rename from cpp/src/synth_unit.h rename to app/src/main/jni/synth_unit.h diff --git a/cpp/src/test_filter.cc b/app/src/main/jni/test_filter.cc similarity index 100% rename from cpp/src/test_filter.cc rename to app/src/main/jni/test_filter.cc diff --git a/cpp/src/test_neon.cc b/app/src/main/jni/test_neon.cc similarity index 100% rename from cpp/src/test_neon.cc rename to app/src/main/jni/test_neon.cc diff --git a/cpp/src/test_ringbuffer.cc b/app/src/main/jni/test_ringbuffer.cc similarity index 100% rename from cpp/src/test_ringbuffer.cc rename to app/src/main/jni/test_ringbuffer.cc diff --git a/cpp/src/wavout.cc b/app/src/main/jni/wavout.cc similarity index 100% rename from cpp/src/wavout.cc rename to app/src/main/jni/wavout.cc diff --git a/cpp/src/wavout.h b/app/src/main/jni/wavout.h similarity index 100% rename from cpp/src/wavout.h rename to app/src/main/jni/wavout.h diff --git a/android/res/drawable-hdpi/add.png b/app/src/main/res/drawable-hdpi/add.png similarity index 100% rename from android/res/drawable-hdpi/add.png rename to app/src/main/res/drawable-hdpi/add.png diff --git a/android/res/drawable-hdpi/arrow.png b/app/src/main/res/drawable-hdpi/arrow.png similarity index 100% rename from android/res/drawable-hdpi/arrow.png rename to app/src/main/res/drawable-hdpi/arrow.png diff --git a/android/res/drawable-hdpi/bass.png b/app/src/main/res/drawable-hdpi/bass.png similarity index 100% rename from android/res/drawable-hdpi/bass.png rename to app/src/main/res/drawable-hdpi/bass.png diff --git a/android/res/drawable-hdpi/closed_eye.png b/app/src/main/res/drawable-hdpi/closed_eye.png similarity index 100% rename from android/res/drawable-hdpi/closed_eye.png rename to app/src/main/res/drawable-hdpi/closed_eye.png diff --git a/android/res/drawable-hdpi/down.png b/app/src/main/res/drawable-hdpi/down.png similarity index 100% rename from android/res/drawable-hdpi/down.png rename to app/src/main/res/drawable-hdpi/down.png diff --git a/android/res/drawable-hdpi/drums.png b/app/src/main/res/drawable-hdpi/drums.png similarity index 100% rename from android/res/drawable-hdpi/drums.png rename to app/src/main/res/drawable-hdpi/drums.png diff --git a/android/res/drawable-hdpi/eighth_note.png b/app/src/main/res/drawable-hdpi/eighth_note.png similarity index 100% rename from android/res/drawable-hdpi/eighth_note.png rename to app/src/main/res/drawable-hdpi/eighth_note.png diff --git a/android/res/drawable-hdpi/flute.png b/app/src/main/res/drawable-hdpi/flute.png similarity index 100% rename from android/res/drawable-hdpi/flute.png rename to app/src/main/res/drawable-hdpi/flute.png diff --git a/android/res/drawable-hdpi/guitar.png b/app/src/main/res/drawable-hdpi/guitar.png similarity index 100% rename from android/res/drawable-hdpi/guitar.png rename to app/src/main/res/drawable-hdpi/guitar.png diff --git a/android/res/drawable-hdpi/half_note.png b/app/src/main/res/drawable-hdpi/half_note.png similarity index 100% rename from android/res/drawable-hdpi/half_note.png rename to app/src/main/res/drawable-hdpi/half_note.png diff --git a/android/res/drawable-hdpi/icon.png b/app/src/main/res/drawable-hdpi/icon.png similarity index 100% rename from android/res/drawable-hdpi/icon.png rename to app/src/main/res/drawable-hdpi/icon.png diff --git a/android/res/drawable-hdpi/loop.png b/app/src/main/res/drawable-hdpi/loop.png similarity index 100% rename from android/res/drawable-hdpi/loop.png rename to app/src/main/res/drawable-hdpi/loop.png diff --git a/android/res/drawable-hdpi/no_note.png b/app/src/main/res/drawable-hdpi/no_note.png similarity index 100% rename from android/res/drawable-hdpi/no_note.png rename to app/src/main/res/drawable-hdpi/no_note.png diff --git a/android/res/drawable-hdpi/open_eye.png b/app/src/main/res/drawable-hdpi/open_eye.png similarity index 100% rename from android/res/drawable-hdpi/open_eye.png rename to app/src/main/res/drawable-hdpi/open_eye.png diff --git a/android/res/drawable-hdpi/play.png b/app/src/main/res/drawable-hdpi/play.png similarity index 100% rename from android/res/drawable-hdpi/play.png rename to app/src/main/res/drawable-hdpi/play.png diff --git a/android/res/drawable-hdpi/play_piano.png b/app/src/main/res/drawable-hdpi/play_piano.png similarity index 100% rename from android/res/drawable-hdpi/play_piano.png rename to app/src/main/res/drawable-hdpi/play_piano.png diff --git a/android/res/drawable-hdpi/quarter_note.png b/app/src/main/res/drawable-hdpi/quarter_note.png similarity index 100% rename from android/res/drawable-hdpi/quarter_note.png rename to app/src/main/res/drawable-hdpi/quarter_note.png diff --git a/android/res/drawable-hdpi/sixteenth_note.png b/app/src/main/res/drawable-hdpi/sixteenth_note.png similarity index 100% rename from android/res/drawable-hdpi/sixteenth_note.png rename to app/src/main/res/drawable-hdpi/sixteenth_note.png diff --git a/android/res/drawable-hdpi/stop.png b/app/src/main/res/drawable-hdpi/stop.png similarity index 100% rename from android/res/drawable-hdpi/stop.png rename to app/src/main/res/drawable-hdpi/stop.png diff --git a/android/res/drawable-hdpi/thirtysecond_note.png b/app/src/main/res/drawable-hdpi/thirtysecond_note.png similarity index 100% rename from android/res/drawable-hdpi/thirtysecond_note.png rename to app/src/main/res/drawable-hdpi/thirtysecond_note.png diff --git a/android/res/drawable-hdpi/trash.png b/app/src/main/res/drawable-hdpi/trash.png similarity index 100% rename from android/res/drawable-hdpi/trash.png rename to app/src/main/res/drawable-hdpi/trash.png diff --git a/android/res/drawable-hdpi/unknown_note.png b/app/src/main/res/drawable-hdpi/unknown_note.png similarity index 100% rename from android/res/drawable-hdpi/unknown_note.png rename to app/src/main/res/drawable-hdpi/unknown_note.png diff --git a/android/res/drawable-hdpi/up.png b/app/src/main/res/drawable-hdpi/up.png similarity index 100% rename from android/res/drawable-hdpi/up.png rename to app/src/main/res/drawable-hdpi/up.png diff --git a/android/res/drawable-hdpi/voice.png b/app/src/main/res/drawable-hdpi/voice.png similarity index 100% rename from android/res/drawable-hdpi/voice.png rename to app/src/main/res/drawable-hdpi/voice.png diff --git a/android/res/drawable-hdpi/whole_note.png b/app/src/main/res/drawable-hdpi/whole_note.png similarity index 100% rename from android/res/drawable-hdpi/whole_note.png rename to app/src/main/res/drawable-hdpi/whole_note.png diff --git a/android/res/drawable-hdpi/zoom.png b/app/src/main/res/drawable-hdpi/zoom.png similarity index 100% rename from android/res/drawable-hdpi/zoom.png rename to app/src/main/res/drawable-hdpi/zoom.png diff --git a/android/res/drawable-ldpi/icon.png b/app/src/main/res/drawable-ldpi/icon.png similarity index 100% rename from android/res/drawable-ldpi/icon.png rename to app/src/main/res/drawable-ldpi/icon.png diff --git a/android/res/drawable-mdpi/icon.png b/app/src/main/res/drawable-mdpi/icon.png similarity index 100% rename from android/res/drawable-mdpi/icon.png rename to app/src/main/res/drawable-mdpi/icon.png diff --git a/android/res/layout-sw600dp/piano2.xml b/app/src/main/res/layout-sw600dp/piano2.xml similarity index 100% rename from android/res/layout-sw600dp/piano2.xml rename to app/src/main/res/layout-sw600dp/piano2.xml diff --git a/android/res/layout/amplification.xml b/app/src/main/res/layout/amplification.xml similarity index 100% rename from android/res/layout/amplification.xml rename to app/src/main/res/layout/amplification.xml diff --git a/android/res/layout/chord_grid.xml b/app/src/main/res/layout/chord_grid.xml similarity index 100% rename from android/res/layout/chord_grid.xml rename to app/src/main/res/layout/chord_grid.xml diff --git a/android/res/layout/effects.xml b/app/src/main/res/layout/effects.xml similarity index 100% rename from android/res/layout/effects.xml rename to app/src/main/res/layout/effects.xml diff --git a/android/res/layout/karplus_strong.xml b/app/src/main/res/layout/karplus_strong.xml similarity index 100% rename from android/res/layout/karplus_strong.xml rename to app/src/main/res/layout/karplus_strong.xml diff --git a/android/res/layout/knobpreflayout_va.xml b/app/src/main/res/layout/knobpreflayout_va.xml similarity index 100% rename from android/res/layout/knobpreflayout_va.xml rename to app/src/main/res/layout/knobpreflayout_va.xml diff --git a/android/res/layout/knobpreflayout_vs.xml b/app/src/main/res/layout/knobpreflayout_vs.xml similarity index 100% rename from android/res/layout/knobpreflayout_vs.xml rename to app/src/main/res/layout/knobpreflayout_vs.xml diff --git a/android/res/layout/low_pass_filter.xml b/app/src/main/res/layout/low_pass_filter.xml similarity index 100% rename from android/res/layout/low_pass_filter.xml rename to app/src/main/res/layout/low_pass_filter.xml diff --git a/android/res/layout/main.xml b/app/src/main/res/layout/main.xml similarity index 100% rename from android/res/layout/main.xml rename to app/src/main/res/layout/main.xml diff --git a/android/res/layout/oscillator.xml b/app/src/main/res/layout/oscillator.xml similarity index 100% rename from android/res/layout/oscillator.xml rename to app/src/main/res/layout/oscillator.xml diff --git a/android/res/layout/piano.xml b/app/src/main/res/layout/piano.xml similarity index 100% rename from android/res/layout/piano.xml rename to app/src/main/res/layout/piano.xml diff --git a/android/res/layout/piano2.xml b/app/src/main/res/layout/piano2.xml similarity index 100% rename from android/res/layout/piano2.xml rename to app/src/main/res/layout/piano2.xml diff --git a/android/res/layout/score.xml b/app/src/main/res/layout/score.xml similarity index 100% rename from android/res/layout/score.xml rename to app/src/main/res/layout/score.xml diff --git a/android/res/layout/tremolo.xml b/app/src/main/res/layout/tremolo.xml similarity index 100% rename from android/res/layout/tremolo.xml rename to app/src/main/res/layout/tremolo.xml diff --git a/android/res/layout/vibrato.xml b/app/src/main/res/layout/vibrato.xml similarity index 100% rename from android/res/layout/vibrato.xml rename to app/src/main/res/layout/vibrato.xml diff --git a/android/res/menu/options_menu.xml b/app/src/main/res/menu/options_menu.xml similarity index 100% rename from android/res/menu/options_menu.xml rename to app/src/main/res/menu/options_menu.xml diff --git a/android/res/menu/score_menu.xml b/app/src/main/res/menu/score_menu.xml similarity index 100% rename from android/res/menu/score_menu.xml rename to app/src/main/res/menu/score_menu.xml diff --git a/android/res/menu/synth_menu.xml b/app/src/main/res/menu/synth_menu.xml similarity index 100% rename from android/res/menu/synth_menu.xml rename to app/src/main/res/menu/synth_menu.xml diff --git a/android/res/raw/presets.txt b/app/src/main/res/raw/presets.txt similarity index 100% rename from android/res/raw/presets.txt rename to app/src/main/res/raw/presets.txt diff --git a/android/res/raw/rom1a.syx b/app/src/main/res/raw/rom1a.syx similarity index 100% rename from android/res/raw/rom1a.syx rename to app/src/main/res/raw/rom1a.syx diff --git a/android/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml similarity index 100% rename from android/res/values-sw600dp/dimens.xml rename to app/src/main/res/values-sw600dp/dimens.xml diff --git a/android/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml similarity index 100% rename from android/res/values-v11/styles.xml rename to app/src/main/res/values-v11/styles.xml diff --git a/android/res/values/attrs.xml b/app/src/main/res/values/attrs.xml similarity index 100% rename from android/res/values/attrs.xml rename to app/src/main/res/values/attrs.xml diff --git a/android/res/values/dimens.xml b/app/src/main/res/values/dimens.xml similarity index 100% rename from android/res/values/dimens.xml rename to app/src/main/res/values/dimens.xml diff --git a/android/res/values/strings.xml b/app/src/main/res/values/strings.xml similarity index 100% rename from android/res/values/strings.xml rename to app/src/main/res/values/strings.xml diff --git a/android/res/values/styles.xml b/app/src/main/res/values/styles.xml similarity index 100% rename from android/res/values/styles.xml rename to app/src/main/res/values/styles.xml diff --git a/android/res/xml/device_filter.xml b/app/src/main/res/xml/device_filter.xml similarity index 100% rename from android/res/xml/device_filter.xml rename to app/src/main/res/xml/device_filter.xml diff --git a/android/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml similarity index 100% rename from android/res/xml/preferences.xml rename to app/src/main/res/xml/preferences.xml diff --git a/app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java b/app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java new file mode 100644 index 0000000..a318606 --- /dev/null +++ b/app/src/test/java/com/levien/synthesizer/ExampleUnitTest.java @@ -0,0 +1,15 @@ +package com.levien.synthesizer; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * To work on unit tests, switch the Test Artifact in the Build Variants view. + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..238a7c7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle-experimental:0.7.2' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/build.xml b/build.xml deleted file mode 100644 index c95addd..0000000 --- a/build.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/.gitignore b/core/.gitignore deleted file mode 100644 index ff4fd7d..0000000 --- a/core/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -build/** -core.jar -bin/protoc -lib/libprotobuf.jar \ No newline at end of file diff --git a/core/build.xml b/core/build.xml deleted file mode 100644 index 777dd8d..0000000 --- a/core/build.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java b/core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java deleted file mode 100644 index ec8f4f3..0000000 --- a/core/src/com/levien/synthesizer/core/model/CachedFrequencyProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * Convenient base class for any module that only wants to compute a new log frequency once at each - * step of time. - */ -public abstract class CachedFrequencyProvider implements FrequencyProvider { - public CachedFrequencyProvider() { - cachedTime_ = -1; - } - - /** - * Caching implementation of the FrequencyProvider interface. - * @param time - current synthesis time. - */ - final public double getLogFrequency(SynthesisTime time) { - if (time.getAbsoluteTime() != cachedTime_) { - cachedTime_ = time.getAbsoluteTime(); - cachedValue_ = computeLogFrequency(time); - } - return cachedValue_; - } - - /** - * Method for subclasses to implement to compute a new value for the given time. - */ - protected abstract double computeLogFrequency(SynthesisTime time); - - private double cachedTime_; - private double cachedValue_; -} diff --git a/core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java b/core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java deleted file mode 100644 index eb212d1..0000000 --- a/core/src/com/levien/synthesizer/core/model/CachedSignalProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * Convenient base class for any module that only wants to compute a new signal value once at each - * step of time. - */ -public abstract class CachedSignalProvider implements SignalProvider { - public CachedSignalProvider() { - cachedTime_ = -1; - } - - /** - * Caching implementation of the SignalProvider interface. - * @param time - current synthesis time. - */ - final public double getValue(SynthesisTime time) { - double absoluteTime = time.getAbsoluteTime(); - if (absoluteTime != cachedTime_) { - cachedTime_ = absoluteTime; - cachedValue_ = computeValue(time); - } - return cachedValue_; - } - - /** - * Method for subclasses to implement to compute a new value for the given time. - */ - protected abstract double computeValue(SynthesisTime time); - - private double cachedTime_; - private double cachedValue_; -} diff --git a/core/src/com/levien/synthesizer/core/model/Envelope.java b/core/src/com/levien/synthesizer/core/model/Envelope.java deleted file mode 100755 index a92f49a..0000000 --- a/core/src/com/levien/synthesizer/core/model/Envelope.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * An interface for any module that shapes a sound based on something like keyboard keys being - * pressed and released. - */ -public interface Envelope extends SignalProvider { - /** - * Called to tell the envelope that the key has been pressed. - * @param retriggerIfOn - A (hopefully temporary) hack. Tells whether to treat this as a new - * press if the key is already down. - */ - public abstract void turnOn(boolean retriggerIfOn); - - /** - * Called to tell the envelope the key has been released. - */ - public abstract void turnOff(); -} diff --git a/core/src/com/levien/synthesizer/core/model/FrequencyProvider.java b/core/src/com/levien/synthesizer/core/model/FrequencyProvider.java deleted file mode 100644 index e2e0817..0000000 --- a/core/src/com/levien/synthesizer/core/model/FrequencyProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * An interface for modules that produce some frequency value. - */ -public interface FrequencyProvider { - double getLogFrequency(SynthesisTime time); -} diff --git a/core/src/com/levien/synthesizer/core/model/SignalProvider.java b/core/src/com/levien/synthesizer/core/model/SignalProvider.java deleted file mode 100644 index 41a3599..0000000 --- a/core/src/com/levien/synthesizer/core/model/SignalProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * An interface for any module that provides a signal, typically in the range [-1, 1]. - */ -public interface SignalProvider { - /** - * Method for subclasses to return a value for the given time. - */ - double getValue(SynthesisTime time); -} diff --git a/core/src/com/levien/synthesizer/core/model/SynthesisTime.java b/core/src/com/levien/synthesizer/core/model/SynthesisTime.java deleted file mode 100644 index e82e17f..0000000 --- a/core/src/com/levien/synthesizer/core/model/SynthesisTime.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * A simple counter to keep track of the logical time in synthesis. - */ -public class SynthesisTime { - /** - * Creates a new timer with a 0 time delta. - */ - public SynthesisTime() { - deltaTime_ = 0.0; - absoluteTime_ = 0.0; - } - - /** - * Returns how much time will elapse next time advance() is called. - * @return the time delta in seconds. - */ - public double getDeltaTime() { - return deltaTime_; - } - - /** - * Returns the absolute time that has elapsed since creation or last reset(). - * @return the time in seconds. - */ - public double getAbsoluteTime() { - return absoluteTime_; - } - - /** - * Sets the "sample rate" of the synthesizer, which is the inverse of the time delta. - * @param sampleRate - samples per second (in Hz). - */ - public void setSampleRate(double sampleRate) { - if (sampleRate == 0.0) { - deltaTime_ = 0.0; - } else { - deltaTime_ = 1.0 / sampleRate; - } - } - - /** - * Resets the absolute time to zero. - */ - public void reset() { - absoluteTime_ = 0.0; - } - - /** - * Advances the absolute time by the time delta. - */ - public void advance() { - absoluteTime_ += deltaTime_; - } - - private double deltaTime_; - private double absoluteTime_; -} diff --git a/core/src/com/levien/synthesizer/core/model/SynthesizerInput.java b/core/src/com/levien/synthesizer/core/model/SynthesizerInput.java deleted file mode 100644 index e05a17b..0000000 --- a/core/src/com/levien/synthesizer/core/model/SynthesizerInput.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -/** - * SynthesizerInput provides a frequency or signal that doesn't inherently change over time. - * It can change occasionally as the user turns a knob or whatever, but doesn't change on its own. - */ -public class SynthesizerInput implements FrequencyProvider, SignalProvider { - /** - * Creates a new SynthesizerInput that will return value as both a frequency and a signal. - */ - public SynthesizerInput(double value, double min, double max) { - value_ = value; - min_ = min; - max_ = max; - } - - /** - * Returns the input value as a log of frequency. - * @return the value. - */ - public synchronized double getLogFrequency(SynthesisTime time) { - return value_; - } - - /** - * Returns the input value as a signal. - * @return the value. - */ - public synchronized double getValue(SynthesisTime time) { - return value_; - } - - /** - * Returns the input value. - * @return the value. - */ - public synchronized double getSynthesizerInputValue() { - return value_; - } - - /** - * Sets the input to a new value. - * @param value - the new value. - */ - public synchronized void setValue(double value) { - value_ = value; - } - - /** - * Sets the input based on an unsigned byte value in the range 0 to 127. - */ - public synchronized void setByteValue(byte value) { - value_ = min_ + (value / 127.0) * (max_ - min_); - } - - private double min_; - private double max_; - private double value_; -} diff --git a/core/src/com/levien/synthesizer/core/model/WaveformInput.java b/core/src/com/levien/synthesizer/core/model/WaveformInput.java deleted file mode 100644 index 6065f13..0000000 --- a/core/src/com/levien/synthesizer/core/model/WaveformInput.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model; - -import java.util.ArrayList; - -/** - * WaveformInput provides a waveform type that is selectable. - */ -public class WaveformInput { - /** - * Creates a new WaveformInput with the given initial value. - */ - public WaveformInput(String waveform) { - selected_ = 0; - waveforms_ = new ArrayList(); - waveforms_.add(waveform); - } - - /** - * @return the index of the given waveform. - */ - public synchronized int getWaveformIndex(String waveform) { - for (int i = 0; i < waveforms_.size(); ++i) { - if (waveforms_.get(i).equals(waveform)) { - return i; - } - } - return -1; - } - - /** - * Selects a waveform. - */ - public synchronized void select(String waveform) { - selected_ = getWaveformIndex(waveform); - if (selected_ < 0) { - selected_ = 0; - } - } - - /** - * Select the next available waveform. - */ - public synchronized void next() { - selected_ = (selected_ + 1) % waveforms_.size(); - } - - /** - * Select the previous available waveform. - */ - public synchronized void previous() { - if (selected_ == 0) { - selected_ = waveforms_.size() - 1; - } else { - --selected_; - } - } - - /** - * Returns the currently selected waveform. - */ - public synchronized int getSelected() { - return selected_; - } - - /** - * Adds a new waveform to this input. - * @return The index of the new waveform. - */ - public synchronized int addWaveform(String waveform) { - int id = getWaveformIndex(waveform); - if (id < 0) { - id = waveforms_.size(); - waveforms_.add(waveform); - } - return id; - } - - /** - * @return The number of waveforms that are selectable. - */ - public synchronized int getWaveformCount() { - return waveforms_.size(); - } - - /** - * @return The identifier of the waveform with the given index. - */ - public synchronized String getWaveform(int i) { - return waveforms_.get(i); - } - - // The currently selected waveform. - private int selected_; - - // The set of all available waveforms on this input. - private ArrayList waveforms_; - - // A few default built-in strings. - public static String SINE = "sine"; - public static String TRIANGLE = "triangle"; - public static String SQUARE = "square"; - public static String SAWTOOTH = "sawtooth"; - public static String NOISE = "noise"; - public static String KARPLUS_STRONG = "karplus-strong string"; - public static String DRAWBAR_ORGAN = "drawbar organ"; - public static String DRUMS = "drums"; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java b/core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java deleted file mode 100644 index 3de5eda..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/MidiSynthesizer.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.composite; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.music.Note; -import com.levien.synthesizer.core.soundfont.SoundFontReader; - -/** - * MidiSynthesizer is a wrapper around MultiTouchSynthesizer that allows it to accept Midi input in - * a more natural way. As more notes are played, more simulated fingers are used, until there - * aren't any more available, in which case notes are dropped. - */ -public class MidiSynthesizer extends MultiTouchSynthesizer implements SignalProvider { - /** - * Creates a new MidiSynthesizer that wraps MultiTouchSynthesizer with a given number of fingers. - * @param fingers - How many fingers to simulate. - * @param sampleRateInHz - The sample rate of the wrapped synthesizer. - */ - public MidiSynthesizer(int fingers, double sampleRateInHz, SoundFontReader sampleProvider) { - super(fingers, sampleRateInHz, sampleProvider); - noteDown_ = new int[FINGERS]; - for (int i = 0; i < FINGERS; ++i) { - noteDown_[i] = -1; - } - } - - /** - * Called to handle Midi note-on events. - * @param note - The note to turn on. - * @param velocity - How hard the key was pressed, from 0 to 127. - */ - public void onNoteOn(int note, int velocity) { - if (velocity == 0) { - onNoteOff(note, velocity); - } else { - for (int i = 0; i < FINGERS; ++i) { - if (noteDown_[i] < 0) { - noteDown_[i] = note; - setPitch(Note.computeLog12TET(note % 12, note / 12), i); - turnOn(true, i); - break; - } - } - } - } - - /** - * Called to handle Midi note-off events. - * @param note - The note to turn off. - * @param velocity - How hard the key was (un?)pressed, from 0 to 127. - */ - public void onNoteOff(int note, int velocity) { - for (int i = 0; i < FINGERS; ++i) { - if (noteDown_[i] == note) { - noteDown_[i] = -1; - turnOff(i); - break; - } - } - } - - // The map of which notes are being held down by each finger. - private int[] noteDown_; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java b/core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java deleted file mode 100644 index 9e1e4c6..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/MultiChannelSynthesizer.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.composite; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.logging.Logger; - -import com.google.protobuf.TextFormat; -import com.levien.synthesizer.core.midi.MidiAdapter; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.composite.Presets.PresetLibrary; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.core.soundfont.SoundFontReader; - -/** - * MultiChannelSynthesizer is an array of MidiSynthesizer. - */ -public class MultiChannelSynthesizer extends MidiAdapter implements SignalProvider { - /** - * MultiChannelSynthesizer is an array of BasicSynths. - * @param channels - The number of channels of the synthesizer. - * @param fingers - How many fingers to support. - * @param sampleRateInHz - The sample rate of the underlying BasicSynths. - */ - public MultiChannelSynthesizer(int channels, int fingers, double sampleRateInHz, - SoundFontReader sampleProvider) { - logger_ = Logger.getLogger(getClass().getName()); - synth_ = new MidiSynthesizer[channels]; - for (int i = 0; i < synth_.length; ++i) { - synth_[i] = new MidiSynthesizer(fingers, sampleRateInHz, sampleProvider); - } - } - - /** - * Returns the output of the synthesizer. - */ - public double getValue(SynthesisTime time) { - double value = 0.0; - for (int i = 0; i < synth_.length; ++i) { - value += synth_[i].getValue(time); - } - return value; - } - - /** - * Called to turn on the given note for the given channel. - */ - @Override - public void onNoteOn(int channel, int note, int velocity) { - synth_[channel].onNoteOn(note, velocity); - } - - /** - * Called to turn off the given note for the given channel. - */ - @Override - public void onNoteOff(int channel, int note, int velocity) { - synth_[channel].onNoteOff(note, velocity); - } - - /** - * Called when a control value changes on the given channel. - */ - @Override - public void onController(int channel, int control, int value) { - MidiSynthesizer synth = synth_[channel]; - Setting setting = Setting.valueOf(control); - SynthesizerInput input = synth.getSynthesizerInput(setting); - if (input != null) { - input.setByteValue((byte)value); - logger_.warning( - "Processed control: " + setting.name() + "[" + channel + "] = " + value + "."); - } else { - logger_.warning("Unhandled control: " + control + "[" + channel + "] = " + value + "."); - } - } - - /** - * Called when the program is changed. - */ - @Override - public void onProgramChange(int channel, int program) { - synth_[channel].setPreset(program); - } - - /** - * Populates names with the list of all known presets from the library. - * Does *not* clear the list first. - */ - public void getPresetNames(ArrayList names) { - synth_[0].getPresetNames(names); - } - - /** - * Populates library with the presets from the given input stream, in text protocol buffer format. - */ - public void loadLibraryFromText(InputStream input) throws IOException { - PresetLibrary.Builder builder = PresetLibrary.newBuilder(); - TextFormat.merge(new InputStreamReader(input), builder); - PresetLibrary library = builder.build(); - for (int i = 0; i < synth_.length; ++i) { - synth_[i].setLibrary(library); - // Load each channel with the next available preset. - synth_[i].setPreset(i % synth_[i].getPresetCount()); - } - } - - /** - * Loads a channel with the settings from the preset in the library with the given index. - */ - public void setPreset(int channel, int index) { - synth_[channel].setPreset(index); - } - - /** - * Returns the MidiSynthesizer to use for a particular channel. - */ - public MidiSynthesizer getChannel(int channel) { - return synth_[channel]; - } - - // The actual synthesizers. - private MidiSynthesizer[] synth_; - - Logger logger_; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java b/core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java deleted file mode 100644 index 06a69b7..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/MultiTouchSynthesizer.java +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.composite; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.WaveformInput; -import com.levien.synthesizer.core.model.composite.Presets.Preset; -import com.levien.synthesizer.core.model.composite.Presets.PresetLibrary; -import com.levien.synthesizer.core.model.composite.Presets.Setting; -import com.levien.synthesizer.core.model.modules.AdsrEnvelope; -import com.levien.synthesizer.core.model.modules.Amplifier; -import com.levien.synthesizer.core.model.modules.Delay; -import com.levien.synthesizer.core.model.modules.Echo; -import com.levien.synthesizer.core.model.modules.Glide; -import com.levien.synthesizer.core.model.modules.LowPassFilter; -import com.levien.synthesizer.core.model.modules.Mixer; -import com.levien.synthesizer.core.model.modules.Tremolo; -import com.levien.synthesizer.core.model.modules.Tuner; -import com.levien.synthesizer.core.model.modules.WaveformSelector; -import com.levien.synthesizer.core.model.oscillator.DrawbarOrgan; -import com.levien.synthesizer.core.model.oscillator.KarplusStrong; -import com.levien.synthesizer.core.soundfont.SoundFontOscillator; -import com.levien.synthesizer.core.soundfont.SoundFontReader; - -/** - * MultiTouchSynthesizer is a collection of synthesizer modules, connected together in a way similar - * to many basic analog synthesizers. - */ -public class MultiTouchSynthesizer implements SignalProvider { - /** - * Creates a new synthesizer with default settings. - * @param sampleRateInHz - Sample rate, used to compute buffer size from delay time. - */ - public MultiTouchSynthesizer(int fingers, double sampleRateInHz, SoundFontReader sampleLibrary) { - FINGERS = fingers; - setup(sampleRateInHz, sampleLibrary); - } - - /** - * Connects all of the modules together. - * @param sampleRateInHz - Sample rate, used to compute buffer size from delay time. - */ - @SuppressWarnings("unchecked") - private void setup(double sampleRateInHz, SoundFontReader sampleLibrary) { - // Data Structures. - library_ = PresetLibrary.newBuilder().build(); - pitch_ = new SynthesizerInput[FINGERS]; - synthesizerInputs_ = new HashMap(); - waveformInputs_ = new HashMap(); - envelopes_ = new ArrayList[FINGERS]; - for (int i = 0; i < FINGERS; ++i) { - pitch_[i] = new SynthesizerInput(0.0, 4.0, 15.0); - envelopes_[i] = new ArrayList(); - } - - // Vibrato - SignalProvider[] vibrato = setupVibrato(); - - // Oscillator 1 - SignalProvider[] oscillator1 = setupOscillator(Setting.OSCILLATOR_1_GLIDE, - Setting.OSCILLATOR_1_COARSE, - Setting.OSCILLATOR_1_FINE, - Setting.OSCILLATOR_1_VIBRATO, - Setting.OSCILLATOR_1_WAVEFORM, - Setting.OSCILLATOR_1_BLEND, - Setting.OSCILLATOR_1_STRETCH, - Setting.OSCILLATOR_1_EXCITEMENT, - pitch_, - vibrato, - true, - sampleLibrary, - sampleRateInHz); - // Oscillator 2 - SignalProvider[] oscillator2 = setupOscillator(Setting.OSCILLATOR_2_GLIDE, - Setting.OSCILLATOR_2_COARSE, - Setting.OSCILLATOR_2_FINE, - Setting.OSCILLATOR_2_VIBRATO, - Setting.OSCILLATOR_2_WAVEFORM, - Setting.OSCILLATOR_2_BLEND, - Setting.OSCILLATOR_2_STRETCH, - Setting.OSCILLATOR_2_EXCITEMENT, - pitch_, - vibrato, - true, - sampleLibrary, - sampleRateInHz); - - // Mixing - SynthesizerInput balance = new SynthesizerInput(0.0, 0.0, 1.0); - synthesizerInputs_.put(Setting.BALANCE, balance); - SignalProvider[] oscillatorOutput = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - oscillatorOutput[finger] = new Mixer(oscillator1[finger], oscillator2[finger], balance); - } - - // Tremolo - SignalProvider[] tremolo = setupTremolo(oscillatorOutput); - - // Low-pass Filter - SignalProvider[] low_pass_filter = setupLowPassFilter(tremolo); - - // Amplifier - SignalProvider[] envelope = setupEnvelope(Setting.ATTACK, - Setting.DECAY, - Setting.SUSTAIN, - Setting.RELEASE); - SynthesizerInput volume = new SynthesizerInput(1.0, 0.0, 25.0); - synthesizerInputs_.put(Setting.VOLUME, volume); - - final SignalProvider[] ampOutput = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - SignalProvider amplification = new Amplifier(envelope[finger], volume); - ampOutput[finger] = new Amplifier(low_pass_filter[finger], amplification); - } - - // Merge the fingers. - SignalProvider mergedOutput = new SignalProvider() { - public double getValue(SynthesisTime time) { - double output = 0.0; - for (int finger = 0; finger < FINGERS; ++finger) { - output += ((1.0 / FINGERS) * ampOutput[finger].getValue(time)); - } - return output; - } - }; - - // Effects - SignalProvider echo = setupEcho(mergedOutput, sampleRateInHz); - output_ = setupDelay(echo); - } - - /** - * Sets up an envelope. - */ - private SignalProvider[] setupEnvelope(Setting attackSetting, - Setting decaySetting, - Setting sustainSetting, - Setting releaseSetting) { - SynthesizerInput attack = new SynthesizerInput(0.01, 0.01, 1.0); - SynthesizerInput decay = new SynthesizerInput(0.01, 0.01, 1.0); - SynthesizerInput sustain = new SynthesizerInput(1.0, 0.0, 1.0); - SynthesizerInput release = new SynthesizerInput(0.01, 0.01, 1.0); - - synthesizerInputs_.put(attackSetting, attack); - synthesizerInputs_.put(decaySetting, decay); - synthesizerInputs_.put(sustainSetting, sustain); - synthesizerInputs_.put(releaseSetting, release); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - Envelope envelope = new AdsrEnvelope(attack, decay, sustain, release); - envelopes_[finger].add(envelope); - response[finger] = envelope; - } - return response; - } - - /** - * Sets up the vibrato section of the synthesizer. - */ - private SignalProvider[] setupVibrato() { - SynthesizerInput rate = new SynthesizerInput(0.0, 0.0, 10.0); - WaveformInput waveform = new WaveformInput(WaveformInput.SINE); - synthesizerInputs_.put(Setting.VIBRATO_RATE, rate); - waveformInputs_.put(Setting.VIBRATO_WAVEFORM, waveform); - SignalProvider[] envelope = setupEnvelope(Setting.VIBRATO_ATTACK, - Setting.VIBRATO_DECAY, - Setting.VIBRATO_SUSTAIN, - Setting.VIBRATO_RELEASE); - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - WaveformSelector waveformOutput = new WaveformSelector(waveform); - waveformOutput.addDefaultWaveforms(rate); - response[finger] = new Amplifier(waveformOutput, envelope[finger]); - } - return response; - } - - /** - * Sets up a Karplus-Strong string section of the synthesizer. - */ - private SignalProvider[] setupKarplusStrong(Setting blendSetting, - Setting stretchSetting, - Setting excitementSetting, - FrequencyProvider[] pitch, - double sampleRateInHz) { - SynthesizerInput blend = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput stretch = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput excitement = new SynthesizerInput(0.0, 0.0, 1.0); - - synthesizerInputs_.put(blendSetting, blend); - synthesizerInputs_.put(stretchSetting, stretch); - synthesizerInputs_.put(excitementSetting, excitement); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - KarplusStrong karplusStrong = - new KarplusStrong(pitch[finger], blend, stretch, excitement, sampleRateInHz); - envelopes_[finger].add(karplusStrong); - response[finger] = karplusStrong; - } - return response; - } - - /** - * Sets up a drawbar organ osciallator for each finger. - */ - private SignalProvider[] setupDrawbarOrgan(FrequencyProvider[] pitch) { - SynthesizerInput drawbar1 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar2 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar3 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar4 = new SynthesizerInput(8.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar5 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar6 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar7 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar8 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - SynthesizerInput drawbar9 = new SynthesizerInput(0.0/8.0, 0.0, 1.0); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_1, drawbar1); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_2, drawbar2); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_3, drawbar3); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_4, drawbar4); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_5, drawbar5); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_6, drawbar6); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_7, drawbar7); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_8, drawbar8); - synthesizerInputs_.put(Setting.ORGAN_DRAWBAR_9, drawbar9); - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - DrawbarOrgan organ = new DrawbarOrgan(pitch[finger], - drawbar1, - drawbar2, - drawbar3, - drawbar4, - drawbar5, - drawbar6, - drawbar7, - drawbar8, - drawbar9); - response[finger] = organ; - } - return response; - } - - /** - * Sets up a sampled drum. - */ - private SignalProvider[] setupDrums(FrequencyProvider[] pitch, - double sampleRateInHz, - SoundFontReader sampleLibrary) { - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - SoundFontOscillator sample = new SoundFontOscillator( - pitch[finger], - sampleLibrary.getPresets().get(sampleLibrary.getPresets().size() - 1), - sampleRateInHz); - response[finger] = sample; - envelopes_[finger].add(sample); - } - return response; - } - - /** - * Sets up an oscillator section of the synthesizer. - */ - private SignalProvider[] setupOscillator(Setting glideSetting, - Setting coarseSetting, - Setting fineSetting, - Setting vibratoSetting, - Setting waveformSetting, - Setting blendSetting, - Setting stretchSetting, - Setting excitementSetting, - FrequencyProvider[] pitch, - SignalProvider[] vibrato, - boolean includeOrgan, - SoundFontReader sampleLibrary, - double sampleRateInHz) { - SynthesizerInput glide = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput coarse = new SynthesizerInput(0.0, -1.0, 1.0); - SynthesizerInput fine = new SynthesizerInput(0.0, -0.0833333333, 0.0833333333); - SynthesizerInput vibratoDepth = new SynthesizerInput(0.0, 0.0, 0.1666666667); - WaveformInput waveform = new WaveformInput(WaveformInput.SINE); - - // Register all of the inputs. - synthesizerInputs_.put(glideSetting, glide); - synthesizerInputs_.put(coarseSetting, coarse); - synthesizerInputs_.put(fineSetting, fine); - synthesizerInputs_.put(vibratoSetting, vibratoDepth); - waveformInputs_.put(waveformSetting, waveform); - - // Create a KarplusStrong module. - SignalProvider[] karplusStrong = - setupKarplusStrong(blendSetting, stretchSetting, excitementSetting, pitch, sampleRateInHz); - - // Create an organ module. - SignalProvider[] organ = null; - if (includeOrgan) { - organ = setupDrawbarOrgan(pitch); - } - - // Create a drum module. - SignalProvider[] drums = null; - if (sampleLibrary != null) { - drums = setupDrums(pitch, sampleRateInHz, sampleLibrary); - } - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - // Apply all of the layers that can control pitch; - FrequencyProvider adjustedPitch = new Glide(pitch[finger], glide); - adjustedPitch = new Tuner(adjustedPitch, coarse); - adjustedPitch = new Tuner(adjustedPitch, fine); - adjustedPitch = new Tuner(adjustedPitch, new Amplifier(vibrato[finger], vibratoDepth)); - - // Create the waveform. - WaveformSelector selector = new WaveformSelector(waveform); - selector.addDefaultWaveforms(adjustedPitch); - selector.addWaveform(WaveformInput.KARPLUS_STRONG, karplusStrong[finger]); - if (organ != null) { - selector.addWaveform(WaveformInput.DRAWBAR_ORGAN, organ[finger]); - } - if (drums != null) { - selector.addWaveform(WaveformInput.DRUMS, drums[finger]); - } - response[finger] = selector; - } - return response; - } - - /** - * Sets up the tremolo section of the synthesizer. - */ - private SignalProvider[] setupTremolo(SignalProvider[] source) { - SynthesizerInput rate = new SynthesizerInput(0.0, 0.0, 10.0); - SynthesizerInput depth = new SynthesizerInput(0.0, 0.0, 1.0); - WaveformInput waveform = new WaveformInput(WaveformInput.SINE); - - synthesizerInputs_.put(Setting.TREMOLO_RATE, rate); - synthesizerInputs_.put(Setting.TREMOLO_DEPTH, depth); - waveformInputs_.put(Setting.TREMOLO_WAVEFORM, waveform); - - SignalProvider[] envelope = setupEnvelope(Setting.TREMOLO_ATTACK, - Setting.TREMOLO_DECAY, - Setting.TREMOLO_SUSTAIN, - Setting.TREMOLO_RELEASE); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - WaveformSelector waveformOutput = new WaveformSelector(waveform); - waveformOutput.addDefaultWaveforms(rate); - response[finger] = - new Amplifier(source[finger], - new Tremolo(new Amplifier(waveformOutput, envelope[finger]), depth)); - } - return response; - } - - /** - * Sets up the filter section of the synthesizer. - */ - private SignalProvider[] setupLowPassFilter(SignalProvider[] source) { - final SynthesizerInput cutoff = new SynthesizerInput(1.0, 0.0, 1.0); - final SynthesizerInput depth = new SynthesizerInput(0.0, -1.0, 1.0); - - synthesizerInputs_.put(Setting.FILTER_CUTOFF, cutoff); - synthesizerInputs_.put(Setting.FILTER_DEPTH, depth); - - final SignalProvider[] envelope = setupEnvelope(Setting.FILTER_ATTACK, - Setting.FILTER_DECAY, - Setting.FILTER_SUSTAIN, - Setting.FILTER_RELEASE); - - SignalProvider[] response = new SignalProvider[FINGERS]; - for (int finger = 0; finger < FINGERS; ++finger) { - final SignalProvider envelope_finger = envelope[finger]; - - SignalProvider shapedCutoff = new CachedSignalProvider() { - public synchronized double computeValue(SynthesisTime time) { - double c = cutoff.getValue(time); - double d = depth.getValue(time); - // This fancy math makes the envelope behave like we want. - double x = c * Math.abs(d) - 0.5 * (d + Math.abs(d)); - return c + x * (envelope_finger.getValue(time) - 1); - } - }; - response[finger] = new LowPassFilter(source[finger], shapedCutoff); - } - return response; - } - - /** - * Sets up an echo module on the synthesizer. - */ - private SignalProvider setupEcho(SignalProvider source, double sampleRateInHz) { - SynthesizerInput mix = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput delay = new SynthesizerInput(0.0, 0.1, 2.0); - - synthesizerInputs_.put(Setting.ECHO_MIX, mix); - synthesizerInputs_.put(Setting.ECHO_DELAY, delay); - - return new Echo(source, mix, delay, sampleRateInHz); - } - - /** - * Sets up the delay module for the synthesizer. - */ - private SignalProvider setupDelay(SignalProvider source) { - SynthesizerInput mix = new SynthesizerInput(0.5, 0.0, 1.0); - synthesizerInputs_.put(Setting.DELAY_MIX, mix); - delay_ = new Delay(source, mix); - return delay_; - } - - /** - * Gets a particular input for this synthesizer by its control id. - */ - public SynthesizerInput getSynthesizerInput(Setting setting) { - if (synthesizerInputs_.containsKey(setting)) { - return synthesizerInputs_.get(setting); - } - return null; - } - - /** - * Gets a particular input for this synthesizer by its control id. - */ - public WaveformInput getWaveformInput(Setting setting) { - if (waveformInputs_.containsKey(setting)) { - return waveformInputs_.get(setting); - } - return null; - } - - /** - * Sets the input pitch of the synthesizer. - * @param logFrequency - The log frequency of the pitch. - */ - public void setPitch(double logFrequency, int finger) { - if (finger < FINGERS) { - pitch_[finger].setValue(logFrequency); - } - } - - /** - * Returns the output of the synthesizer, as it should go to the speaker. - */ - public double getValue(SynthesisTime time) { - return output_.getValue(time); - } - - /** - * Turns on all envelopes used by the synth. - * @param retriggerIfOn - A (hopefully temporary) hack. Tells whether to treat this as a new - * press if the key is already down. - */ - public void turnOn(boolean retriggerIfOn, int finger) { - if (finger < FINGERS) { - for (int i = 0; i < envelopes_[finger].size(); ++i) { - envelopes_[finger].get(i).turnOn(retriggerIfOn); - } - } - } - - /** - * Turns off all envelopes used by the synth. - */ - public void turnOff(int finger) { - if (finger < FINGERS) { - for (int i = 0; i < envelopes_[finger].size(); ++i) { - envelopes_[finger].get(i).turnOff(); - } - } - } - - /** - * Starts recording what the user plays. - */ - public void startRecording() { - delay_.startRecording(); - } - - /** - * Stops recording. - */ - public void stopRecording() { - delay_.stopRecording(); - } - - /** - * Starts playing what the user has recorded. - */ - public void startPlaying() { - delay_.startPlaying(); - } - - /** - * Stops playing the recorded audio. - */ - public void stopPlaying() { - delay_.stopPlaying(); - } - - /** - * Returns whether the user's recording is being played. - */ - public boolean isPlaying() { - return delay_.isPlaying(); - } - - /** - * Returns whether the user's playing is being recorded. - */ - public boolean isRecording() { - return delay_.isRecording(); - } - - /** - * Loads this synthesizer with the settings from the given preset. - */ - public void setPreset(Preset preset) { - for (int i = 0; i < preset.getInputSettingCount(); ++i) { - SynthesizerInput input = getSynthesizerInput(preset.getInputSetting(i).getSetting()); - if (input != null) { - input.setValue(preset.getInputSetting(i).getValue()); - } else { - throw new RuntimeException( - "Unable to set synthesizer input " + preset.getInputSetting(i).getSetting()); - } - } - for (int i = 0; i < preset.getWaveformSettingCount(); ++i) { - WaveformInput input = getWaveformInput(preset.getWaveformSetting(i).getSetting()); - if (input != null) { - input.select(preset.getWaveformSetting(i).getWaveform()); - } else { - throw new RuntimeException( - "Unable to set synthesizer input " + preset.getWaveformSetting(i).getSetting() + "."); - } - } - } - - /** - * Loads this synthesizer with the settings from the preset in the library with the given name. - */ - public void setPreset(String name) { - for (int i = 0; i < library_.getPresetCount(); ++i) { - if (library_.getPreset(i).getName().equals(name)) { - setPreset(library_.getPreset(i)); - return; - } - } - throw new RuntimeException("Tried to load an unknown preset: \"" + name + "\"."); - } - - /** - * Loads this synthesizer with the settings from the preset in the library with the given index. - */ - public void setPreset(int index) { - if (index < 0 || index >= library_.getPresetCount()) { - throw new RuntimeException("Tried to load an unknown preset: " + index + "."); - } - setPreset(library_.getPreset(index)); - } - - /** - * Returns the number of presets available in the library. - */ - public int getPresetCount() { - return library_.getPresetCount(); - } - - /** - * Populates names with the list of all known presets from the library. - * Does *not* clear the list first. - */ - public void getPresetNames(ArrayList names) { - for (int i = 0; i < library_.getPresetCount(); ++i) { - names.add(library_.getPreset(i).getName()); - } - } - - public void setLibrary(PresetLibrary library) throws IOException { - library_ = library; - } - - /** - * Return the maximum number of fingers that can be used. - */ - public int getMaxFingerCount() { - return FINGERS; - } - - // Data structures for keeping track of input. - private Map synthesizerInputs_; - private Map waveformInputs_; - - // How many fingers this synthesizer supports. - protected final int FINGERS; - - // Keyboard input. - private SynthesizerInput[] pitch_; - - // List of envelopes that needs to be triggered when a key is pressed. - private List[] envelopes_; - - //The delay module that handles recording and playback. - private Delay delay_; - - //Synthesizer output. - private SignalProvider output_; - - // A collection of setting presets. - private PresetLibrary library_; -} diff --git a/core/src/com/levien/synthesizer/core/model/composite/Presets.proto b/core/src/com/levien/synthesizer/core/model/composite/Presets.proto deleted file mode 100644 index 8eb42c7..0000000 --- a/core/src/com/levien/synthesizer/core/model/composite/Presets.proto +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package synthesizer_core_proto; - -option java_package = "com.levien.synthesizer.core.model.composite"; - -enum WaveformDeprecated { - SINE = 0; - TRIANGLE = 1; - SQUARE = 2; - SAWTOOTH = 3; - NOISE = 4; - KARPLUS_STRONG = 5; - DRAWBAR_ORGAN = 6; - DRUMS = 7; - WAVEFORM_COUNT = 8; -} - -enum Setting { - TREMOLO_ATTACK = 3; - TREMOLO_DECAY = 4; - TREMOLO_SUSTAIN = 5; - TREMOLO_RELEASE = 6; - BALANCE = 9; - ECHO_DELAY = 12; - DELAY_MIX = 13; - VOLUME = 14; - VIBRATO_ATTACK = 15; - VIBRATO_DECAY = 16; - VIBRATO_SUSTAIN = 17; - VIBRATO_RELEASE = 18; - OSCILLATOR_2_COARSE = 19; - OSCILLATOR_2_FINE = 20; - OSCILLATOR_1_WAVEFORM_NEXT = 23; - OSCILLATOR_2_WAVEFORM_NEXT = 24; - TREMOLO_WAVEFORM_NEXT = 25; - VIBRATO_WAVEFORM_NEXT = 26; - OSCILLATOR_1_WAVEFORM = 27; - OSCILLATOR_2_WAVEFORM = 28; - TREMOLO_WAVEFORM = 29; - VIBRATO_WAVEFORM = 30; - OSCILLATOR_1_WAVEFORM_PREVIOUS = 33; - OSCILLATOR_2_WAVEFORM_PREVIOUS = 34; - TREMOLO_WAVEFORM_PREVIOUS = 35; - VIBRATO_WAVEFORM_PREVIOUS = 36; - ORGAN_DRAWBAR_1 = 42; - ORGAN_DRAWBAR_2 = 43; - ORGAN_DRAWBAR_3 = 50; - ORGAN_DRAWBAR_4 = 51; - ORGAN_DRAWBAR_5 = 52; - ORGAN_DRAWBAR_6 = 53; - ORGAN_DRAWBAR_7 = 54; - ORGAN_DRAWBAR_8 = 55; - ORGAN_DRAWBAR_9 = 56; - OSCILLATOR_1_GLIDE = 57; - OSCILLATOR_1_STRETCH = 58; - OSCILLATOR_1_BLEND = 59; - OSCILLATOR_1_EXCITEMENT = 60; - OSCILLATOR_2_GLIDE = 61; - OSCILLATOR_2_STRETCH = 62; - OSCILLATOR_2_BLEND = 63; - OSCILLATOR_2_EXCITEMENT = 65; - FILTER_CUTOFF = 74; - OSCILLATOR_1_COARSE = 78; - OSCILLATOR_1_FINE = 79; - ECHO_MIX = 94; - FILTER_ATTACK = 105; - FILTER_DECAY = 106; - FILTER_SUSTAIN = 107; - FILTER_RELEASE = 108; - FILTER_DEPTH = 109; - ATTACK = 110; - DECAY = 111; - SUSTAIN = 112; - RELEASE = 113; - VIBRATO_RATE = 114; - OSCILLATOR_1_VIBRATO = 115; - OSCILLATOR_2_VIBRATO = 116; - TREMOLO_RATE = 117; - TREMOLO_DEPTH = 118; -} - -message InputSetting { - optional Setting setting = 1; - optional double value = 2; -} - -message WaveformSetting { - optional Setting setting = 1; - optional string waveform = 2; -} - -message Preset { - optional string name = 1; - repeated InputSetting input_setting = 2; - repeated WaveformSetting waveform_setting = 3; -} - -message PresetLibrary { - repeated Preset preset = 1; -} \ No newline at end of file diff --git a/core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java b/core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java deleted file mode 100644 index 0ae03fb..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/AdsrEnvelope.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An ADSR is the most common envelope for a synth. - */ -public class AdsrEnvelope extends CachedSignalProvider implements Envelope { - /** - * Creates an ADSR with the given parameters. - * @param attack - attack time in seconds. - * @param decay - decay time in seconds. - * @param sustain - sustain level from 0 to 1. - * @param release - release time in seconds. - */ - public AdsrEnvelope(SignalProvider attack, - SignalProvider decay, - SignalProvider sustain, - SignalProvider release) { - value_ = 0.0; - attacking_ = false; - - trigger_ = false; - gate_ = false; - - attack_ = attack; - decay_ = decay; - sustain_ = sustain; - release_ = release; - } - - public synchronized double computeValue(SynthesisTime time) { - if (trigger_) { - attacking_ = true; - trigger_ = false; - // It doesn't really matter if the attack is on the leading or trailing edge of the trigger. - // By having it start on the trailing edge for 0 and the leading edge otherwise, it makes the - // math a tiny bit simpler and makes this a little easier to unit test. - if (value_ == 0) { - return value_; - } - } - - if (gate_) { - double sustain = sustain_.getValue(time); - if (attacking_) { - // Attacking. - double attack = attack_.getValue(time); - if (attack > 0.0) { - double timeDelta = time.getDeltaTime(); - value_ += timeDelta / attack; - if (value_ >= 1.0) { - // TODO(klimt): This isn't exactly right. We should really figure out what time it - // would've reached zero, and go ahead and apply the decay for that extra time that - // has passed. - value_ = 1.0; - attacking_ = false; - } - } else { - value_ = 1.0; - attacking_ = false; - } - } else if (value_ > sustain) { - // Decaying. - double decay = decay_.getValue(time); - if (decay > 0.0) { - double timeDelta = time.getDeltaTime(); - value_ += timeDelta * ((sustain - 1.0) / decay); - if (value_ < sustain) { - value_ = sustain; - } - } else { - value_ = sustain; - } - } else if (value_ < sustain) { - // Decaying backwards. - // This shouldn't _normally_ happen, but can if you change the parameters over time. - double decay = decay_.getValue(time); - if (decay > 0.0) { - double timeDelta = time.getDeltaTime(); - value_ -= timeDelta * ((sustain - 1.0) / decay); - if (value_ > sustain) { - value_ = sustain; - } - } else { - value_ = sustain; - } - } - } else { - // Releasing. - if (value_ > 0.0) { - double release = release_.getValue(time); - if (release > 0.0) { - double sustain = sustain_.getValue(time); - if (sustain == 0.0) { - double decay = decay_.getValue(time); - if (decay == 0.0) { - value_ = 0.0; - } else { - double timeDelta = time.getDeltaTime(); - value_ -= timeDelta * ((sustain - 1.0) / decay); - } - } else { - double timeDelta = time.getDeltaTime(); - value_ -= timeDelta * (sustain / release); - } - if (value_ < 0.0) { - value_ = 0.0; - } - } else { - value_ = 0.0; - } - } - } - return value_; - } - - public synchronized void turnOn(boolean retriggerIfOn) { - if (gate_ && !retriggerIfOn) { - return; - } - trigger_ = true; - gate_ = true; - } - - public synchronized void turnOff() { - gate_ = false; - } - - /** - * Returns whether the envelope is currently being triggered. - */ - public synchronized boolean getTrigger() { - return trigger_; - } - - /** - * Returns whether the key for this envelope is currently being held down. - */ - public synchronized boolean getGate() { - return gate_; - } - - // The most recently output value from this envelope. - private double value_; - - // Are we in the attack phase? - private boolean attacking_; - - // Whether the envelope is "on". - private boolean trigger_; - private boolean gate_; - - // The envelope shape parameters. - private SignalProvider attack_; - private SignalProvider decay_; - private SignalProvider sustain_; - private SignalProvider release_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Amplifier.java b/core/src/com/levien/synthesizer/core/model/modules/Amplifier.java deleted file mode 100755 index 8dbe4ea..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Amplifier.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Amplifier simply multiplies the input signal by the input gain. - */ -public class Amplifier implements SignalProvider { - /** - * Creates a new Amplifier with the given signal and gain. - * @param inputSignal - Any input signal. - * @param gain - The signal it's multiplied times. - */ - public Amplifier(SignalProvider inputSignal, SignalProvider gain) { - inputSignal_ = inputSignal; - gain_ = gain; - } - - /** - * Returns signal * gain. - */ - public double getValue(SynthesisTime time) { - // Most of the time, the gain will be 0.0 because of some envelope. So this is an optimization. - double gain = gain_.getValue(time); - if (gain == 0.0) { - return 0.0; - } - return inputSignal_.getValue(time) * gain; - } - - private SignalProvider inputSignal_; - private SignalProvider gain_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Delay.java b/core/src/com/levien/synthesizer/core/model/modules/Delay.java deleted file mode 100755 index d166b96..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Delay.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import java.util.Arrays; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Delay is a module for recording sampled sound and playing it back later. It has 3 modes. - * In regular mode, it outputs its input, attenuated by half. - * In record mode, it also captures sound until it is stopped or the MAX_BUFFER_SIZE is reached. - * In play mode, it plays back its output mixed with the recorded buffer in a loop. - */ -public class Delay extends CachedSignalProvider { - public Delay(SignalProvider source, SignalProvider mix) { - source_ = source; - mix_ = mix; - buffer_ = new double[MAX_BUFFER_SIZE]; - current_ = 0; - bufferSize_ = MAX_BUFFER_SIZE; - Arrays.fill(buffer_, 0.0); - playing_ = false; - recording_ = false; - } - - @Override - protected synchronized double computeValue(SynthesisTime time) { - double input = source_.getValue(time); - double mix = mix_.getValue(time); - if (playing_) { - double output = mix * buffer_[current_] + (1.0 - mix) * input; - current_ = (current_ + 1) % bufferSize_; - return output; - } else { - if (recording_) { - buffer_[bufferSize_++] = input; - if (bufferSize_ >= MAX_BUFFER_SIZE) { - stopRecording(); - } - } - return (1.0 - mix) * input; - } - } - - /** - * Resets the buffer and changes to record mode. - */ - public synchronized void startRecording() { - playing_ = false; - recording_ = true; - current_ = 0; - bufferSize_ = 0; - } - - /** - * Stops recording, but doesn't start playing. - */ - public synchronized void stopRecording() { - recording_ = false; - current_ = 0; - } - - /** - * Starts playing what's recorded. - */ - public synchronized void startPlaying() { - playing_ = true; - recording_ = false; - current_ = 0; - } - - /** - * Stops playing and recording. - */ - public synchronized void stopPlaying() { - playing_ = false; - recording_ = false; - current_ = 0; - } - - /** - * Returns whether the module is in playing mode. - */ - public synchronized boolean isPlaying() { - return playing_; - } - - /** - * Returns whether the module is in record mode. - */ - public synchronized boolean isRecording() { - return recording_; - } - - private SignalProvider source_; - private SignalProvider mix_; - - private double[] buffer_; - private int bufferSize_; - private int current_; - - private boolean playing_; - private boolean recording_; - - private final static int MAX_BUFFER_SIZE = 10; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Echo.java b/core/src/com/levien/synthesizer/core/model/modules/Echo.java deleted file mode 100755 index fa347ae..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Echo.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * The Echo module produces an echo effect by mixing its current input with its earlier input. - */ -public class Echo extends CachedSignalProvider { - /** - * Creates a new Echo module. - * @param source - The input to the echo module. - * @param mix - How wet/dry the output is, i.e. the depth of the effect. - * @param delay - The length of time in seconds between input and its first repetition. - * @param sampleRateInHz - Sample rate, used to compute buffer size from delay time. - */ - public Echo(SignalProvider source, - SignalProvider mix, - SignalProvider delay, - double sampleRateInHz) { - source_ = source; - mix_ = mix; - delay_ = delay; - sampleRateInHz_ = sampleRateInHz; - buffer_ = new double[MAX_BUFFER_SIZE]; - for (int i = 0; i < MAX_BUFFER_SIZE; ++i) { - buffer_[i] = 0.0; - } - bufferSize_ = 0; - current_ = 0; - previousDelay_ = 0.0; - } - - protected void maybeUpdateDelay(double delay) { - // As an optimization, just bail if the delay value hasn't changed. - if (previousDelay_ == delay) { - return; - } - previousDelay_ = delay; - - int newBufferSize = 0; - if (delay != 0.0) { - newBufferSize = (int)Math.round(delay * sampleRateInHz_); - } - if (bufferSize_ == newBufferSize) { - return; - } - bufferSize_ = newBufferSize; - if (bufferSize_ < 1) { - bufferSize_ = 0; - } - if (bufferSize_ > MAX_BUFFER_SIZE) { - bufferSize_ = MAX_BUFFER_SIZE; - } - } - - @Override - protected double computeValue(SynthesisTime time) { - maybeUpdateDelay(delay_.getValue(time)); - double input = source_.getValue(time); - double mix = mix_.getValue(time); - if (bufferSize_ == 0) { - return (1.0 - mix) * input; - } else { - double value = mix * buffer_[current_] + (1.0 - mix) * input; - buffer_[current_] = value; - current_ = (current_ + 1) % bufferSize_; - return value; - } - } - - private SignalProvider source_; - private SignalProvider mix_; - private SignalProvider delay_; - - private double previousDelay_; - private double[] buffer_; - private int bufferSize_; - private double sampleRateInHz_; - private int current_; - - private final static int MAX_BUFFER_SIZE = 55125; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Glide.java b/core/src/com/levien/synthesizer/core/model/modules/Glide.java deleted file mode 100644 index e23e97f..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Glide.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedFrequencyProvider; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Glide smooths changes in frequency over time. - */ -public class Glide extends CachedFrequencyProvider { - /** - * Creates a Glide module to wrap source. - * @param source - The input frequency to smooth. - * @param rate - The time in seconds in which output should change to a new input. - */ - public Glide(FrequencyProvider source, SignalProvider rate) { - source_ = source; - rate_ = rate; - previousLogFrequency_ = 0.0; - nextLogFrequency_ = 0.0; - } - - public double computeLogFrequency(SynthesisTime time) { - double currentLogFrequency = source_.getLogFrequency(time); - double rate = rate_.getValue(time); - - // If rate is 0 seconds, then don't do anything. - if (rate == 0.0) { - previousLogFrequency_ = currentLogFrequency; - nextLogFrequency_ = currentLogFrequency; - return currentLogFrequency; - } - - // It hasn't changed, so don't do anything. - if (currentLogFrequency == previousLogFrequency_ && - nextLogFrequency_ == previousLogFrequency_) { - return currentLogFrequency; - } - - // See where we are, based on where we were last heading. - double timeSinceChange = time.getAbsoluteTime() - switchTime_; - double output; - if (timeSinceChange > rate) { - output = nextLogFrequency_; - } else { - output = previousLogFrequency_ + - (timeSinceChange / rate) * (nextLogFrequency_ - previousLogFrequency_); - } - - // Adjust if there is a new destination. - if (currentLogFrequency != nextLogFrequency_) { - previousLogFrequency_ = output; - nextLogFrequency_ = currentLogFrequency; - switchTime_ = time.getAbsoluteTime(); - } - - return output; - } - - // The wrapped frequency provider to take as input and output smoothed. - private FrequencyProvider source_; - - // The time in seconds in which output should change to a new input. - private SignalProvider rate_; - - // The log frequency that was being output last time the input switched. - private double previousLogFrequency_; - - // The log frequency of the input that this module is moving toward. - private double nextLogFrequency_; - - // The last time that in the input frequency changed. - private double switchTime_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java b/core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java deleted file mode 100644 index 8d8b31b..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/LowPassFilter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * A very simple low-pass filter. - */ -public class LowPassFilter extends CachedSignalProvider { - /** - * Creates a LowPassFilter with the given parameters. - * @param source - The input signal to filter. - * @param cutoff - "Alpha" parameter that controls the cutoff frequency. - */ - public LowPassFilter(SignalProvider source, SignalProvider cutoff) { - source_ = source; - alpha_ = cutoff; - previousValue_ = 0.0; - } - - public double computeValue(SynthesisTime time) { - double alpha = alpha_.getValue(time); - double output = 0.0; - if (alpha != 0) { - double signal = source_.getValue(time); - output = previousValue_ + alpha * (signal - previousValue_); - previousValue_ = output; - } else { - output = previousValue_; - } - return output; - } - - // The filter parameters. - private SignalProvider source_; - private SignalProvider alpha_; - - private double previousValue_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Mixer.java b/core/src/com/levien/synthesizer/core/model/modules/Mixer.java deleted file mode 100755 index 950a5be..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Mixer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Mixer outputs a weighted average of two input signals. - * A "balance" of 0.0 outputs signal 1, and a balance of 1.0 outputs signal 2. - * The balance can be changed over time. - */ -public class Mixer implements SignalProvider { - /** - * Creates a new Mixer. - * @param signal1 - Any input signal module. - * @param signal2 - Any input signal module. - * @param balance - A module outputting the weight to use when averaging. - */ - public Mixer(SignalProvider signal1, SignalProvider signal2, SignalProvider balance) { - signal1_ = signal1; - signal2_ = signal2; - balance_ = balance; - } - - /** - * Returns the average of the input signals, weighted by balance. - */ - public double getValue(SynthesisTime time) { - double balance = balance_.getValue(time); - // As an optimization, don't compute any signal that's not needed. - if (balance == 0.0) { - return signal1_.getValue(time); - } else if (balance == 1.0) { - return signal2_.getValue(time); - } else { - return (1.0 - balance) * signal1_.getValue(time) + balance * signal2_.getValue(time); - } - } - - private SignalProvider signal1_; - private SignalProvider signal2_; - private SignalProvider balance_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Tremolo.java b/core/src/com/levien/synthesizer/core/model/modules/Tremolo.java deleted file mode 100644 index 2f3878b..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Tremolo.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Module to modulate an amplitude over time based on a modulator signal. Its output is intended to - * be fed into an amplifier. - */ -public class Tremolo implements SignalProvider { - /** - * Creates a Tremolo module. - * @param modulator - Waveform that modulates the amplitude. - * @param depth - Depth of amplitude modulation. - */ - public Tremolo(SignalProvider modulator, SignalProvider depth) { - modulator_ = modulator; - depth_ = depth; - } - - public double getValue(SynthesisTime time) { - double modulator = modulator_.getValue(time); - double depth = depth_.getValue(time); - return (modulator * (depth / 2.0)) + (1.0 - depth / 2.0); - } - - // Waveform that modulates the amplitude. - private SignalProvider modulator_; - - // Depth of amplitude modulation. - private SignalProvider depth_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/Tuner.java b/core/src/com/levien/synthesizer/core/model/modules/Tuner.java deleted file mode 100644 index bb7e7ee..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/Tuner.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * Module to modify the output of a frequency provider. - */ -public class Tuner implements FrequencyProvider { - /** - * Creates a Tuner module to wrap source. - * @param input - The base log frequency. - * @param shift - The amount to alter it. - */ - public Tuner(FrequencyProvider input, SignalProvider shift) { - input_ = input; - shift_ = shift; - } - - public double getLogFrequency(SynthesisTime time) { - double input = input_.getLogFrequency(time); - double shift = shift_.getValue(time); - return input + shift; - } - - // The wrapped frequency provider to take as input. - private FrequencyProvider input_; - - // The amount to alter the signal. - private SignalProvider shift_; -} diff --git a/core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java b/core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java deleted file mode 100644 index 6cff8b9..0000000 --- a/core/src/com/levien/synthesizer/core/model/modules/WaveformSelector.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules; - -import java.util.ArrayList; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.WaveformInput; -import com.levien.synthesizer.core.model.oscillator.Noise; -import com.levien.synthesizer.core.model.oscillator.Sawtooth; -import com.levien.synthesizer.core.model.oscillator.Sine; -import com.levien.synthesizer.core.model.oscillator.Square; -import com.levien.synthesizer.core.model.oscillator.Triangle; - -/** - * Module that outputs a waveform from a selectable set of oscillators. - */ -public class WaveformSelector implements SignalProvider { - /** - * Constructs a waveform selector with no waveforms available. - * @param waveform - The source for which waveform to use at any given time. - */ - public WaveformSelector(WaveformInput waveform) { - waveform_ = waveform; - sources_ = new ArrayList(); - } - - /** - * Adds a source for a new waveform type. - */ - public synchronized void addWaveform(String waveform, SignalProvider source) { - int id = waveform_.addWaveform(waveform); - while (sources_.size() < id + 1) { - sources_.add(null); - } - sources_.set(id, source); - } - - /** - * Returns the output of the source associated with the selected waveform. - */ - public synchronized double getValue(SynthesisTime time) { - int selected = waveform_.getSelected(); - SignalProvider provider = sources_.get(selected); - if (provider != null) { - return provider.getValue(time); - } else { - return 0.0; - } - } - - /** - * Adds the standard waveforms to this selector. - */ - public synchronized void addDefaultWaveforms(FrequencyProvider frequency) { - addWaveform(WaveformInput.SINE, new Sine(frequency)); - addWaveform(WaveformInput.TRIANGLE, new Triangle(frequency)); - addWaveform(WaveformInput.SQUARE, new Square(frequency)); - addWaveform(WaveformInput.SAWTOOTH, new Sawtooth(frequency)); - addWaveform(WaveformInput.NOISE, new Noise(frequency)); - } - - // Instances of each waveform type. - private ArrayList sources_; - - // The currently selected waveform. - private WaveformInput waveform_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java b/core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java deleted file mode 100644 index 06ed36a..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/DrawbarOrgan.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that emulates a set of tone wheels for a drawbar organ. - */ -public class DrawbarOrgan extends Oscillator { - /** - * Creates a new drawbar organ with the given pitch and inputs for the level of each drawbar. - */ - public DrawbarOrgan(FrequencyProvider frequency, - SignalProvider subFundamental, - SignalProvider subThirdHarmonic, - SignalProvider fundamental, - SignalProvider secondHarmonic, - SignalProvider thirdHarmonic, - SignalProvider fourthHarmonic, - SignalProvider fifthHarmonic, - SignalProvider sixthHarmonic, - SignalProvider eighthHarmonic) { - super(frequency); - - depth_ = new SignalProvider[9]; - oscillator_ = new Sine[9]; - - depth_[0] = subFundamental; - oscillator_[0] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) - 1.0; - } - }); - - depth_[1] = subThirdHarmonic; - oscillator_[1] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 0.5849625; // log2(3) =~ 7/12 - } - }); - - depth_[2] = fundamental; - oscillator_[2] = new Sine(frequency); - - depth_[3] = secondHarmonic; - oscillator_[3] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 1.0; - } - }); - - depth_[4] = thirdHarmonic; - oscillator_[4] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 1.5849625; // 1 + log2(3) =~ 19/12 - } - }); - - depth_[5] = fourthHarmonic; - oscillator_[5] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 2.0; - } - }); - - depth_[6] = fifthHarmonic; - oscillator_[6] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 2.3219281; // 1 + log2(5) =~ 28/12; - } - }); - - depth_[7] = sixthHarmonic; - oscillator_[7] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 2.5849625; // 1 + log2(6) =~ 31/12; - } - }); - - depth_[8] = eighthHarmonic; - oscillator_[8] = new Sine(new FrequencyProvider() { - public double getLogFrequency(SynthesisTime time) { - return frequency_.getLogFrequency(time) + 3.0; - } - }); - } - - /** - * Makes a weighted average of the value from each tone wheel. - */ - public double computeValue(SynthesisTime time) { - double output = 0.0; - double denominator = 0.0; - for (int i = 0; i < oscillator_.length; ++i) { - double depth = depth_[i].getValue(time); - if (depth != 0.0) { - output += (depth * oscillator_[i].getValue(time)); - denominator += depth; - } - } - if (denominator == 0.0) { - return 0.0; - } - return output / denominator; - } - - // How much each drawbar is pulled out. - private SignalProvider[] depth_; - - // The set of underlying sine oscillators for each tone wheel. - private Sine[] oscillator_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java b/core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java deleted file mode 100644 index 92683e9..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/KarplusStrong.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import java.util.Arrays; - -/** - * Karplus-Strong string/drum synthesis algorithm. - * - * @param frequency - The frequency of the note produced. - * @param blend - Blend factor. Closer to 0 sounds more like a string, closer to 1 more like a drum. - * @param stretch - How fast the vibration of the string should decay. - * @param excitement - How noisy (i.e. random) the initial pluck should be. - * @param sampleRateInHz - The sample rate, used with pitch to compute KS buffer size. - */ -public class KarplusStrong extends Oscillator implements Envelope { - public KarplusStrong(FrequencyProvider frequency, - SignalProvider blend, - SignalProvider stretch, - SignalProvider excitement, - double sampleRateInHz) { - super(frequency); - sampleRateInHz_ = sampleRateInHz; - buffer_ = new double[kMaxBufferSize]; - Arrays.fill(buffer_, 0.0); - bufferSize_ = 0; - current_ = 0; - - blend_ = blend; - stretch_ = stretch; - excitement_ = excitement; - } - - @Override - protected synchronized double computeValue(SynthesisTime time) { - if (current_ == 0) { - // We've looped around to the beginning of the buffer, so take the opportunity to resize. - bufferSize_ = - (int)Math.round(sampleRateInHz_ / (Math.pow(2.0, frequency_.getLogFrequency(time)))); - if (bufferSize_ > kMaxBufferSize) { - bufferSize_ = kMaxBufferSize; - } - } - - // If the frequency is so high the buffer disappears, then we just can't do anything. - if (bufferSize_ == 0) { - trigger_ = false; - return 0.0; - } - - // The "string" has been "plucked". Fill the buffer with noise. - if (trigger_) { - trigger_ = false; - double excitement = excitement_.getValue(time); - for (int i = 0; i < kMaxBufferSize; ++i) { - if (excitement == 0.0) { - // Just an optimization. - buffer_[i] = 0.5; - } else { - buffer_[i] = excitement * (Math.random() * 2.0 - 1.0); - } - } - } - - // Process the buffer. - double output = buffer_[current_]; - double blend = blend_.getValue(time); - double stretch = 1.0 - stretch_.getValue(time); // Invert stretch so it's more intuitive. - double direction = (blend == 0.0 || (blend != 1.0 && blend <= Math.random())) ? -1.0 : 1.0; - double magnitude = 0.0; - if (stretch == 0.0 || (stretch != 1.0 && stretch <= Math.random())) { - magnitude = buffer_[current_]; - } else { - magnitude = (buffer_[current_] + previousOutput_) / 2.0; - } - buffer_[current_] = direction * magnitude; - previousOutput_ = output; - current_ = (current_ + 1) % bufferSize_; - return output; - } - - /** - * Doesn't really do anything at this time. - */ - public synchronized void turnOff() { - gate_ = false; - } - - /** - * Causes the string to be plucked by setting trigger_ to true. - */ - public synchronized void turnOn(boolean retriggerIfOn) { - if (gate_ && !retriggerIfOn) { - return; - } - trigger_ = true; - gate_ = true; - } - - private double[] buffer_; - private int bufferSize_; - private double sampleRateInHz_; - private int current_; - private double previousOutput_; - - // Blend factor. Closer to 0 sounds more like a string. Closer to 1 sounds more like a drum. - private SignalProvider blend_; - - // How fast the vibration of the string should decay. - private SignalProvider stretch_; - - // How noisy (i.e. random) the initial pluck should be. - private SignalProvider excitement_; - - private boolean trigger_; - private boolean gate_; - - // The max buffer size is the highest sample rate divided by the lowest frequency (20 Hz). - private final static int kMaxBufferSize = 44100/20; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Noise.java b/core/src/com/levien/synthesizer/core/model/oscillator/Noise.java deleted file mode 100755 index f4589a2..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Noise.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs random values in the range [-1, 1]. - */ -public class Noise extends Oscillator { - public Noise(FrequencyProvider frequency) { - super(frequency); - } - - public double computeValue(SynthesisTime time) { - return Math.random() * 2.0 - 1.0; - } -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java b/core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java deleted file mode 100755 index ddb232a..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Oscillator.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.FrequencyProvider; - -/** - * Subclass for any oscillator -- any module that outputs a waveform based on a given frequency. - * The range of the output is [-1, 1.0]. - */ -public abstract class Oscillator extends CachedSignalProvider { - /** - * Constructor for subclasses to store the frequency. - */ - public Oscillator(FrequencyProvider frequency) { - frequency_ = frequency; - } - - protected FrequencyProvider frequency_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java b/core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java deleted file mode 100755 index c32ddba..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Sawtooth.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a sawtooth wave. - */ -public class Sawtooth extends Oscillator { - public Sawtooth(FrequencyProvider frequency) { - super(frequency); - value_ = 0.0; - currentFrequency_ = 1.0; - } - - public double computeValue(SynthesisTime time) { - // The output value drops until it is below -1.0, then shoots up to 1.0. - value_ -= (2.0 * currentFrequency_ * time.getDeltaTime()); - while (value_ <= -1.0) { - // Frequency is only updated at the end of each cycle. - double nextFrequency = Math.pow(2.0, frequency_.getLogFrequency(time)); - currentFrequency_ = nextFrequency; - // We can't just set to 1.0. The signal should have decreased from 1.0 by the amount it - // actually decreased below -1.0. - value_ += 2.0; - } - return value_; - } - - // The most recent output value. - private double value_; - - // The current frequency of the waveform. - private double currentFrequency_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Sine.java b/core/src/com/levien/synthesizer/core/model/oscillator/Sine.java deleted file mode 100755 index 865a168..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Sine.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a sine wave. - */ -public class Sine extends Oscillator { - public Sine(FrequencyProvider frequency) { - super(frequency); - value_ = 0.0; - offset_ = 0.0; - currentLogFrequency_ = 0.0; - currentFrequency_ = 1.0; - } - - public double computeValue(SynthesisTime time) { - // Compute the output using the current frequency. - value_ = Math.sin(2 * Math.PI * currentFrequency_ * (time.getAbsoluteTime() + offset_)); - - // If the frequency is supposed to change, change the phase offset to where the new frequency - // would be outputting the same current value. - double nextLogFrequency = frequency_.getLogFrequency(time); - if (currentLogFrequency_ != nextLogFrequency) { - double nextFrequency = Math.pow(2.0, nextLogFrequency); - offset_ = ((time.getAbsoluteTime() + offset_) * currentFrequency_ / nextFrequency) - - time.getAbsoluteTime(); - currentLogFrequency_ = nextLogFrequency; - currentFrequency_ = nextFrequency; - } - - return value_; - } - - // Most recently output value. - private double value_; - - // How far out of phrase the wave is from one starting at time 0. - private double offset_; - - // Amplitude and frequency for the current output value. - private double currentLogFrequency_; - private double currentFrequency_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Square.java b/core/src/com/levien/synthesizer/core/model/oscillator/Square.java deleted file mode 100755 index b8b88fa..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Square.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a square wave. - */ -public class Square extends Oscillator { - public Square(FrequencyProvider frequency) { - super(frequency); - sine_ = new Sine(frequency); - } - - public double computeValue(SynthesisTime time) { - // The easiest way to make a square wave is to take a sine wave and round it to -1 or 1. - if (sine_.getValue(time) > 0.0) { - return 1.0; - } else { - return -1.0; - } - } - - private Sine sine_; -} diff --git a/core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java b/core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java deleted file mode 100755 index aaea06b..0000000 --- a/core/src/com/levien/synthesizer/core/model/oscillator/Triangle.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator; - -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * An oscillator module that outputs a triangle wave. - */ -public class Triangle extends Oscillator { - public Triangle(FrequencyProvider frequency) { - super(frequency); - sawtooth_ = new Sawtooth(frequency); - } - - public double computeValue(SynthesisTime time) { - // It's a simple mathematical transformation to convert a sawtooth to a triangle. - return -2.0 * Math.abs(sawtooth_.getValue(time)) + 1.0; - } - - private Sawtooth sawtooth_; -} diff --git a/core/src/com/levien/synthesizer/core/music/EventComparator.java b/core/src/com/levien/synthesizer/core/music/EventComparator.java deleted file mode 100644 index 651302a..0000000 --- a/core/src/com/levien/synthesizer/core/music/EventComparator.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -import java.util.Comparator; - -import com.levien.synthesizer.core.music.Music.EventOrBuilder; - -/** - * A few comparators for sorting lists of Events (like in a score). - */ -public class EventComparator { - /** - * Sorts by the start times of the events. - */ - public static Comparator byStart() { - return new Comparator() { - public int compare(EventOrBuilder event, EventOrBuilder other) { - if (other.getStart() == event.getStart()) { - if (other.hasKeyEvent() && !event.hasKeyEvent()) { - return -1; - } else if (!other.hasKeyEvent() && event.hasKeyEvent()) { - return 1; - } else if (other.getEnd() == event.getEnd()) { - return 0; - } else if (other.getEnd() > event.getEnd()) { - return 1; - } else { - return -1; - } - } else if (other.getStart() < event.getStart()) { - return 1; - } else { - return -1; - } - } - }; - } - - /** - * Sorts by the end times of the events. - */ - public static Comparator byEnd() { - return new Comparator() { - public int compare(EventOrBuilder event, EventOrBuilder other) { - if (other.getEnd() == event.getEnd()) { - if (other.hasKeyEvent() && !event.hasKeyEvent()) { - return 1; - } else if (!other.hasKeyEvent() && event.hasKeyEvent()) { - return -1; - } else if (other.getStart() == event.getStart()) { - return 0; - } else if (other.getStart() < event.getStart()) { - return -1; - } else { - return 1; - } - } else if (other.getEnd() < event.getEnd()) { - return 1; - } else { - return -1; - } - } - }; - } -} diff --git a/core/src/com/levien/synthesizer/core/music/Music.proto b/core/src/com/levien/synthesizer/core/music/Music.proto deleted file mode 100644 index 1848c0b..0000000 --- a/core/src/com/levien/synthesizer/core/music/Music.proto +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package synthesizer_core_music; - -option java_package = "com.levien.synthesizer.core.music"; - -// An Event is one item in a score. It has a start and end time, and information about what -// happens at that time, such as what note is played, and on what channel (instrument). -message Event { - // The start time of the event in measures from the beginning of the score. - optional double start = 1; - - // The end time of the event. - optional double end = 2; - - // The start time before "snapping to" the nearest note in the editor. - optional double unsnapped_start = 3; - - // The end time before "snapping to" the nearest note in the editor. - optional double unsnapped_end = 4; - - // For a key event, the key/note being pressed. For other events, this is just where it shows up - // in the score. For example, a loop event shows on a certain key just because that makes them - // easier to edit. - optional int32 key = 5; - - // The key before before "snapping to" the nearest whole key in the editor. - // This can hold a fractional key, which can represent a valid frequency between two notes, - // which might be valid for some synthesizers, but not for midi output. - optional double unsnapped_key = 6; - - // Is this event selected in the UI? - optional bool selected = 7; - - // An event where a key is pressed. - optional KeyEvent key_event = 8; - - // An event where that defines a loop. - optional LoopEvent loop_event = 9; -} - -// An event where a key is pressed at the beginning and released at the end. -message KeyEvent { - // The channel/instrument to play the note on. - optional int32 channel = 1; -} - -// An event where playback jumps from the end to the beginning a certain number of times. -message LoopEvent { - // The total number of times to loop. - optional int32 count = 1; - - // The number of times left to loop in the current playback. - optional int32 count_remaining = 2; -} - -// A score, representing a series of synthesizer events that can be played. -message Score { - // The set of events, in no particular order. - repeated Event event = 1; -} diff --git a/core/src/com/levien/synthesizer/core/music/Note.java b/core/src/com/levien/synthesizer/core/music/Note.java deleted file mode 100755 index 49a8428..0000000 --- a/core/src/com/levien/synthesizer/core/music/Note.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -/** - * Collection of static methods dealing with musical notes. - */ -public class Note { - /** - * Determines the log frequency of a note in 12 tone equal temperament (12-TET). - * @param note - the note, a value from one of the constants in this class. - * @param octave - the octave of the note. - */ - public static double computeLog12TET(int note, int octave) { - return FACTOR + ((((12 * octave) + (note - 9) + 1) - 49) / 12.0); - } - - /** - * Returns the note, or midi key, that corresponds to the given log frequency. - * @param logFrequency - the log frequency that corresponds to a note. - * @return - the nearest note to that frequency. - */ - public static int getKeyforLog12TET(double logFrequency) { - return (int)(12.0 * (logFrequency - FACTOR) + 57.5); - } - - /** - * Returns true if the note is natural, i.e. not a sharp or flat. - * @param note - the note, a value from one of the constants in this class. - */ - public static boolean isNatural(int note) { - return NATURAL[note % NATURAL.length]; - } - - /** - * Returns a printable name for the given note. - * @param note - the note, a value from one of the constants in this class. - */ - public static String getName(int note) { - return NAMES[note]; - } - - // Note frequencies in 12-TET are defined relative to log2 of A4 (440Hz). - // There's no reason to redo the log conversion every time a frequency is computed. - private static final double FACTOR = Math.log(440.0) / Math.log(2.0); - - // Constants for each of the possible notes. - public static final int NONE = -1; - public static final int C = 0; - public static final int C_SHARP = 1; - public static final int D_FLAT = 1; - public static final int D = 2; - public static final int D_SHARP = 3; - public static final int E_FLAT = 3; - public static final int E = 4; - public static final int F = 5; - public static final int F_SHARP = 6; - public static final int G_FLAT = 6; - public static final int G = 7; - public static final int G_SHARP = 8; - public static final int A_FLAT = 8; - public static final int A = 9; - public static final int A_SHARP = 10; - public static final int B_FLAT = 10; - public static final int B = 11; - - // Constants for intervals between notes. - public static final double HALF_STEP = 1.0f / 12.0f; - public static final double WHOLE_STEP = 1.0f / 6.0f; - public static final double OCTAVE = 1.0f; - - // A simple map of which notes are natural. - private static final boolean[] NATURAL = { - true, false, true, false, true, true, false, true, false, true, false, true }; - - // A displayable name for each note. - private static final String[] NAMES = { - "C", "C#", "D", "Eb", "E", "F", "F#", "G", "Ab", "A", "Bb", "B" - }; -} diff --git a/core/src/com/levien/synthesizer/core/music/ScorePlayer.java b/core/src/com/levien/synthesizer/core/music/ScorePlayer.java deleted file mode 100644 index 85e0fb7..0000000 --- a/core/src/com/levien/synthesizer/core/music/ScorePlayer.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.ListIterator; -import java.util.PriorityQueue; -import java.util.logging.Logger; - -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.music.Music.Event; -import com.levien.synthesizer.core.music.Music.Score; - -/** - * Methods for playing a score using a synthesizer. - * @see ScorePlayerListener - */ -public class ScorePlayer { - /** - * Creates a new ScorePlayer. - */ - public ScorePlayer() { - logger_ = Logger.getLogger(ScorePlayer.class.getName()); - playing_ = false; - } - - /** - * Merges identical loop events in a sorted list of events. Since having two loops over the same - * time period would normally make them multiplicative, and that isn't useful, this changes that - * one situation to make them additive. That way, you can have a segment that play three times - * without having to create any events that have a repeat count other than one. - */ - private void mergeIdenticalLoopEvents(ArrayList startList) { - for (int i = 0; i < startList.size(); ++i) { - if (i+1 < startList.size() && - startList.get(i).hasLoopEvent() && - startList.get(i+1).hasLoopEvent() && - startList.get(i).getStart() == startList.get(i+1).getStart() && - startList.get(i).getEnd() == startList.get(i+1).getEnd()) { - startList.get(i).getLoopEventBuilder().setCount( - startList.get(i).getLoopEventBuilder().getCount() + - startList.get(i+1).getLoopEventBuilder().getCount()); - startList.remove(i+1); - i--; - } - } - } - - /** - * Plays the given score using the given synthesizer. Returns immediately, while the music plays - * in a separate thread. - * - * @param synth - the synthesizer to use for output. - * @param score - the score to play. - * @param beatsPerMinute - the tempo to play. - * @param beatsPerMeasure - the time signature. - * @param listener - the listener to notify of events. - */ - public synchronized void startPlaying(MidiListener synth, - Score score, - double beatsPerMinute, - int beatsPerMeasure, - ScorePlayerListener listener) { - if (playing_) { - logger_.warning("startPlaying called while already playing."); - return; - } - - // Copy the sequence so that it's safe to modify it while it's playing asynchronously. - ArrayList startList = - new ArrayList(Score.newBuilder(score).getEventBuilderList()); - Collections.sort(startList, EventComparator.byStart()); - mergeIdenticalLoopEvents(startList); - starts_ = startList.listIterator(); - - ends_ = new PriorityQueue(startList.size(), EventComparator.byEnd()); - - // Setup the internal state. - synth_ = synth; - listener_ = listener; - beatsPerMinute_ = beatsPerMinute; - beatsPerMeasure_ = beatsPerMeasure; - playing_ = true; - stop_ = false; - currentTime_ = 0.0; - - listener_.onStart(); - - new Thread("ScorePlayer.startPlaying()") { - public void run() { - logger_.info("ScorePlayer.startPlaying() thread running."); - while (true) { - // While we have the lock, we'll need to see how long to sleep until the next iteration of - // the loop. This variable will contain that delay at the end of the loop. - long delay; - - synchronized (ScorePlayer.this) { - onTimeUpdate(); - - // Check if it's time to stop. - if (stop_) { - playing_ = false; - - // Okay, now finish off all of the events that have been started. - while (!ends_.isEmpty()) { - Event.Builder event = ends_.remove(); - if (event.hasKeyEvent()) { - synth_.onNoteOff(event.getKeyEvent().getChannel(), event.getKey(), 0); - } - } - - listener_.onStop(); - logger_.info("Finished playing."); - break; - } - - // See if there are more events to process. - if (!starts_.hasNext() && ends_.isEmpty()) { - // There are no more events to process. - stop_ = true; - continue; - } - - // There are more events. See when the next one should be processed. - boolean isEnd; - double targetTime; - if (!starts_.hasNext()) { - // All of the start events are over. The next event will need to be an end event. - isEnd = true; - targetTime = getSecondsPerMeasure() * ends_.peek().getEnd(); - } else if (ends_.isEmpty()) { - // There are no end events queued up yet. The next event will need to be a start. - isEnd = false; - targetTime = getSecondsPerMeasure() * starts_.next().getStart(); - starts_.previous(); - } else { - // We'll need to process either a start or an end, whichever is first. - if (ends_.peek().getEnd() <= peek(starts_).getStart()) { - // Process the next end. - isEnd = true; - targetTime = getSecondsPerMeasure() * ends_.peek().getEnd(); - } else { - // Process the next start. - isEnd = false; - targetTime = getSecondsPerMeasure() * peek(starts_).getStart(); - } - } - - // See if we need to process an event now. - if (currentTime_ >= targetTime) { - // Yes, we do. - if (isEnd) { - Event.Builder event = ends_.remove(); - if (event.hasKeyEvent()) { - synth_.onNoteOff(event.getKeyEvent().getChannel(), - event.getKey(), 0); - } else if (event.hasLoopEvent()) { - if (!event.getLoopEvent().hasCountRemaining()) { - event.getLoopEventBuilder().setCountRemaining(event.getLoopEvent().getCount()); - } - if (event.getLoopEvent().getCountRemaining() > 0) { - // Okay, it's time to loop. - // TODO(klimt): Ideally, we'd kill all note events currently alive, but we - // don't want to kill any of the loop events, so it's a little tricky. - // while (!ends_.isEmpty()) { - // Event.Builder eventToStop = ends_.remove(); - // if (eventToStop.hasKeyEvent()) { - // synth_.onNoteOff(eventToStop.getKeyEvent().getChannel(), - // eventToStop.getKey(), 0); - // } - // } - // Now, rewind the start list until it's before the start time. - while (starts_.previous() != event) { - // Rewind. - } - // Okay, now update the current time. - currentTime_ = getSecondsPerMeasure() * event.getStart(); - targetTime = currentTime_; - event.getLoopEventBuilder().setCountRemaining( - event.getLoopEvent().getCountRemaining() - 1); - } else { - // We're finished with this loop, so we're moving on. - event.getLoopEventBuilder().clearCountRemaining(); - } - } - } else { - Event.Builder event = starts_.next(); - if (event.hasKeyEvent()) { - synth_.onNoteOn(event.getKeyEvent().getChannel(), event.getKey(), 127); - } - // We started the event, so let's make sure we end it eventually. :) - ends_.add(event); - } - // Okay, move on to the next event. - continue; - } - - // If we got this far, we'll need to sleep until the next event. See how long. - delay = (long)((targetTime - currentTime_) * 1000.0); - } // synchronized (ScorePlayer.this) - - // Sleep for a while. - if (delay > 250) { - delay = 250; - } - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - logger_.warning("Sequence.play() thread interrupted."); - } - - synchronized (ScorePlayer.this) { - currentTime_ += (delay / 1000.0); - } - } // while (true) - } // run() - }.start(); - } - - /** - * This is a stupid hack because ListIterator doesn't have a peek method. - */ - private static Event.Builder peek(ListIterator iterator) { - Event.Builder event = iterator.next(); - iterator.previous(); - return event; - } - - /** - * Stops playback as soon as convenient. Doesn't block. - */ - public synchronized void stopPlaying() { - stop_ = true; - } - - /** - * Returns the number of seconds each measure of the song should take. - */ - private synchronized double getSecondsPerMeasure() { - return (beatsPerMeasure_ / beatsPerMinute_) * 60.0; - } - - /** - * Calls the onTimeUpdate() method of the listener. - */ - private synchronized void onTimeUpdate() { - listener_.onTimeUpdate(currentTime_ / getSecondsPerMeasure()); - } - - // The synthesizer to use for playing. - private MidiListener synth_; - - // The tempo of the song. - private double beatsPerMinute_; - - // The time signature of the score. - private int beatsPerMeasure_; - - // The listener to notify of events. - private ScorePlayerListener listener_; - - // Is the thread playing? - private boolean playing_; - - // Should the thread stop? - private boolean stop_; - - // The time of the current head of the playback, in seconds. - private double currentTime_; - - // The sequence being played. - private ListIterator starts_; - private PriorityQueue ends_; - - private Logger logger_; -} diff --git a/core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java b/core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java deleted file mode 100644 index ea6d61b..0000000 --- a/core/src/com/levien/synthesizer/core/music/ScorePlayerListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.music; - -/** - * Listener for events from a ScorePlayer. - * @see ScorePlayer - */ -public interface ScorePlayerListener { - /** - * Called when playback starts. - */ - void onStart(); - - /** - * Called every so often during playback. - * @param time - time in measures from the start of the score. - */ - void onTimeUpdate(double time); - - /** - * Called when playback stops. - */ - void onStop(); -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Bag.java b/core/src/com/levien/synthesizer/core/soundfont/Bag.java deleted file mode 100644 index c3671fd..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Bag.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Bag is a structure particular to the SoundFont format that represents a list of generators and - * modulators. It could be a "preset bag" or an "instrument bag", but it's basically the same. - */ -public class Bag { - /** - * Reads one Bag from the given input stream. - * @param input - An input stream where the next bytes represent a bag. - */ - public Bag(RiffInputStream input) throws IOException { - generatorStart_ = input.readWord(); - modulatorStart_ = input.readWord(); - generatorEnd_ = generatorStart_; - modulatorEnd_ = modulatorStart_; - } - - /** - * @return The index of the first generator in this bag. - */ - public int getGeneratorStart() { - return generatorStart_; - } - - /** - * @return The index of the first modulator in this bag. - */ - public int getModulatorStart() { - return modulatorStart_; - } - - /** - * @return The index of the first generator after getGeneratorStart() *not* in this bag. - */ - public int getGeneratorEnd() { - return generatorEnd_; - } - - /** - * @return The index of the first modulator after getModulatorStart() *not* in this bag. - */ - public int getModulatorEnd() { - return modulatorEnd_; - } - - /** - * Sets the value to be returned by getGeneratorEnd(). - */ - public void setGeneratorEnd(int end) { - generatorEnd_ = end; - } - - /** - * Sets the value to be returned by getModulatorEnd(). - */ - public void setModulatorEnd(int end) { - modulatorEnd_ = end; - } - - /** - * Returns a user-readable string representing this bag. - */ - public String toString() { - return - "Bag {\n" + - " generator: [" + generatorStart_ + ", " + generatorEnd_ + ")\n" + - " modulator: [" + modulatorStart_ + ", " + modulatorEnd_ + ")\n" + - "}"; - } - - private int generatorStart_; - private int modulatorStart_; - private int generatorEnd_; - private int modulatorEnd_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Generator.java b/core/src/com/levien/synthesizer/core/soundfont/Generator.java deleted file mode 100644 index 6cc4793..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Generator.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Generator is a SoundFont data structure that represents an "operator" and an "amount". - */ -public class Generator { - /** - * Reads one generator from the given input. - */ - public Generator(RiffInputStream input) throws IOException { - operator_ = Operator.fromType(input.readWord()); - amount_ = input.readShort(); - } - - /** - * @return The operator for this generator. - */ - public Operator getOperator() { - return operator_; - } - - /** - * @return The unprocessed argument associated with this generator. - */ - public short getAmount() { - return amount_; - } - - /** - * Returns a user-readable string representing this generator. - */ - public String toString() { - return - "Generator {\n" + - " operator: " + operator_.toString() + " (" + operator_.getType() + ")\n" + - " amount: " + amount_ + "\n" + - "}"; - } - - private Operator operator_; - private short amount_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Instrument.java b/core/src/com/levien/synthesizer/core/soundfont/Instrument.java deleted file mode 100644 index 57775a4..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Instrument.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; -import java.util.ArrayList; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * An instrument is a SoundFont data structure that consists of a set of zones. Each "zone" is - * basically a flattened "bag" with a sample and a key range, etc. - */ -public class Instrument { - /** - * Reads one instrument from the given input. - */ - public Instrument(RiffInputStream input) throws IOException { - name_ = input.readString(20); - bagStart_ = input.readWord(); - bagEnd_ = bagStart_; - zoneList_ = new ArrayList(); - } - - public String getName() { - return name_; - } - - public int getBagStart() { - return bagStart_; - } - - public int getBagEnd() { - return bagEnd_; - } - - public void setBagEnd(int end) { - bagEnd_ = end; - } - - public void addZone(Zone zone) { - zoneList_.add(zone); - } - - public ArrayList getZoneList() { - return zoneList_; - } - - /** - * Returns a user-readable string representing this instrument. - */ - public String toString() { - return - "Instrument {\n" + - " name: \"" + name_ + "\"\n" + - " bag index: [" + bagStart_ + ", " + bagEnd_ + ")\n" + - "}"; - } - - private String name_; - private int bagStart_; - private int bagEnd_; - private ArrayList zoneList_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Modulator.java b/core/src/com/levien/synthesizer/core/soundfont/Modulator.java deleted file mode 100644 index 0d5811b..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Modulator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Modulator is a SoundFont data structure. They are read in by this library, but then ignored. - */ -public class Modulator { - public Modulator(RiffInputStream input) throws IOException { - sourceOperator = new ModulatorSource(input.readWord()); - destinationOperator = input.readWord(); - amount = input.readShort(); - amountOperator = new ModulatorSource(input.readWord()); - transform = input.readWord(); - } - - public String toString() { - return - "Modulator {\n" + - " source operator: \n" + - sourceOperator + "\n" + - " destination operator: " + destinationOperator + "\n" + - " amount: " + amount + "\n" + - " amount operator: \n" + - amountOperator + "\n" + - " transform: " + transform + "\n" + - "}"; - } - - public ModulatorSource sourceOperator; - public int destinationOperator; - public short amount; - public ModulatorSource amountOperator; - public int transform; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java b/core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java deleted file mode 100644 index 12b694c..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/ModulatorSource.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -/** - * A ModulatorSource is a SoundFont data structure. They are read by this library and then ignored. - */ -public class ModulatorSource { - /** - * Initializes the source from the given value. - */ - public ModulatorSource(int value) { - type_ = (byte)((0xFC00 & value) >> 10); - polarity_ = ((value & 0x0200) != 0); - direction_ = ((value & 0x0100) != 0); - continuous_ = ((value & 0x0080) != 0); - index_ = (byte)(0x007F & value); - } - - public String toString() { - return - " ModulatorSource {\n" + - " type: " + type_ + "\n" + - " polarity: " + polarity_ + "\n" + - " direction: " + direction_ + "\n" + - " continuous: " + continuous_ + "\n" + - " index: " + index_ + "\n" + - " }"; - } - - private byte type_; - public boolean polarity_; - public boolean direction_; - public boolean continuous_; - public byte index_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Operator.java b/core/src/com/levien/synthesizer/core/soundfont/Operator.java deleted file mode 100644 index 21d5c0e..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Operator.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -/** - * An enumeration of all possible SoundFont Generator Operators. - * Most of these are ignored. - */ -public enum Operator { - UNSUPPORTED(-1), - START_ADDRS_OFFSET(0, false), - END_ADDRS_OFFSET(1, false), - STARTLOOP_ADDRS_OFFSET(2, false), - ENDLOOP_ADDRS_OFFSET(3, false), - START_ADDRS_COARSE_OFFSET(4, false), - MOD_LFO_TO_PITCH(5), - VIB_LFO_TO_PITCH(6), - MOD_ENV_TO_PITCH(7), - INITIAL_FILTER_FC(8), - INITIAL_FILTER_Q(9), - MOD_LFO_TO_FILTER_FC(10), - MOD_ENV_TO_FILTER_FC(11), - END_ADDRS_COARSE_OFFSET(12, false), - MOD_LFO_TO_VOLUME(13), - CHORUS_EFFECTS_SEND(15), - REVERB_EFFECTS_SEND(16), - PAN(17), - DELAY_MOD_LFO(21), - FREQ_MOD_LFO(22), - DELAY_VIB_LFO(23), - FREQ_VIB_LFO(24), - DELAY_MOD_ENV(25), - ATTACK_MOD_ENV(26), - HOLD_MOD_ENV(27), - DECAY_MOD_ENV(28), - SUSTAIN_MOD_ENV(29), - RELEASE_MOD_ENV(30), - KEYNUM_TO_MOD_ENV_HOLD(31), - KEYNUM_TO_MOD_ENV_DECAY(32), - DELAY_VOL_ENV(33), - ATTACK_VOL_ENV(34), - HOLD_VOL_ENV(35), - DECAY_VOL_ENV(36), - SUSTAIN_VOL_ENV(37), - RELEASE_VOL_END(38), - KEYNUM_TO_VOL_ENV_HOLD(39), - KEYNUM_TO_VOL_ENV_DECAY(40), - INSTRUMENT(41, true, false), - KEY_RANGE(43), - VELOCITY_RANGE(44), - STARTLOOP_ADDRS_COARSE_OFFSET(45, false), - KEYNUM(46, false), - VELOCITY(47, false), - INITIAL_ATTENUATION(48), - ENDLOOP_ADDRS_COARSE_OFFSET(50, false), - COARSE_TUNE(51), - FINE_TUNE(52), - SAMPLE_ID(53, false), - SAMPLE_MODES(54, false), - SCALE_TUNING(56), - EXCLUSIVE_CLASS(57, false), - OVERRIDING_ROOT_KEY(58, false), - END_OPER(60); - - /** - * Creates a new enum value. - * @param type - The enum value in the SoundFont format. - * @param validForPreset - True if this operator would be valid in a preset zone. - * @param validForInstrument - True if this operator would be valid in an instrument zone. - */ - Operator(int type, boolean validForPreset, boolean validForInstrument) { - type_ = type; - validForPreset_ = validForPreset; - validForInstrument_ = validForInstrument; - } - - /** - * Creates a new enum value that is valid for an instrument zone. - * @param type - The enum value in the SoundFont format. - * @param validForPreset - True if this operator would be valid in a preset zone. - */ - Operator(int type, boolean validForPreset) { - this(type, validForPreset, true); - } - - /** - * Creates a new enum value that is valid for a preset or instrument zone. - * @param type - The enum value in the SoundFont format. - */ - Operator(int type) { - this(type, true); - } - - /** - * @return The SoundFont enum value for this operator. - */ - public int getType() { - return type_; - } - - /** - * @return True if this operator is valid in a preset zone. - */ - public boolean isValidForPreset() { - return validForPreset_; - } - - /** - * @return True if this operator is valid in an instrument zone. - */ - public boolean isValidForInstrument() { - return validForInstrument_; - } - - /** - * @return The operator corresponding to the given type. - * @param type - The enum value in the SoundFont format. - */ - public static Operator fromType(int type) { - // TODO(klimt): Keep an index instead of linear search. - for (Operator op : Operator.values()) { - if (op.getType() == type) { - return op; - } - } - return UNSUPPORTED; - } - - private final int type_; - private final boolean validForPreset_; - private final boolean validForInstrument_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Preset.java b/core/src/com/levien/synthesizer/core/soundfont/Preset.java deleted file mode 100644 index 9dcaa7f..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Preset.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; -import java.util.ArrayList; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Preset is a SoundFont data structure that corresponds to a bunch of "preset zones" and a set - * of instruments. - */ -public class Preset { - /** - * Reads one Preset from the given input stream. - */ - public Preset(RiffInputStream input) throws IOException { - name_ = input.readString(20); - preset_ = input.readWord(); - bank_ = input.readWord(); - bagStart_ = input.readWord(); - bagEnd_ = bagStart_; - library_ = input.readDWord(); - genre_ = input.readDWord(); - morphology_ = input.readDWord(); - zoneList_ = new ArrayList(); - } - - public String getName() { - return name_; - } - - public int getBagStart() { - return bagStart_; - } - - public int getBagEnd() { - return bagEnd_; - } - - public void setBagEnd(int end) { - bagEnd_ = end; - } - - public void addZone(Zone zone) { - zoneList_.add(zone); - } - - public ArrayList getZoneList() { - return zoneList_; - } - - public String toString() { - return - "Preset {\n" + - " name: \"" + name_ + "\"\n" + - " preset: " + preset_ + "\n" + - " bank: " + bank_ + "\n" + - " bag index: [" + bagStart_ + ", " + bagEnd_ + ")\n" + - "}"; - } - - private String name_; - private int preset_; - private int bank_; - - private int bagStart_; - private int bagEnd_; - - private ArrayList zoneList_; - - @SuppressWarnings("unused") - private long library_; - @SuppressWarnings("unused") - private long genre_; - @SuppressWarnings("unused") - private long morphology_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Sample.java b/core/src/com/levien/synthesizer/core/soundfont/Sample.java deleted file mode 100644 index 5c9ada6..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Sample.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.IOException; - -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * A Sample is a subset of sample data from a SoundFont file. - */ -public class Sample { - /** - * Reads one SampleHeader from the given input stream. - * @param input - A SoundFont input stream. - * @param samples - All of the sample data from the SoundFont file. - */ - public Sample(RiffInputStream input, double[] samples) throws IOException { - name_ = input.readString(20); - start_ = (int)input.readDWord(); - end_ = (int)input.readDWord(); - startLoop_ = (int)input.readDWord(); - endLoop_ = (int)input.readDWord(); - sampleRate_ = input.readDWord(); - originalKey_ = input.readByte(); - correction_ = input.readChar(); - sampleLink_ = input.readWord(); - sampleType_ = SampleLink.fromType(input.readWord()); - if (sampleType_.equals(SampleLink.UNKNOWN) && - !name_.equals("EOS")) { - throw new IOException("Unsupported sample type."); - } - sample_ = samples; - } - - /** - * @return The index of the first sample in the sample. - */ - public long getStart() { - return start_; - } - - /** - * @return The index of one past the last sample in the sample. - */ - public long getEnd() { - return end_; - } - - /** - * @return The sample rate of the sample. - */ - public long getRate() { - return sampleRate_; - } - - /** - * @return The number of samples in the sample. - */ - public int getCount() { - return end_ - start_; - } - - /** - * Returns one sample from the, um, sample. - * @param i - The index of the sample. Should be between getStart() and getEnd(). - */ - public double getSample(int i) { - return sample_[i]; - } - - /** - * Returns a human-readable description of the sample. - */ - public String toString() { - return - "SampleHeader {\n" + - " name: " + name_ + "\n" + - " start: " + start_ + "\n" + - " end: " + end_ + "\n" + - " start loop: " + startLoop_ + "\n" + - " end loop: " + endLoop_ + "\n" + - " sample rate: " + sampleRate_ + "\n" + - " original key: " + originalKey_ + "\n" + - " correction: " + correction_ + "\n" + - " sample link: " + sampleLink_ + "\n" + - " sample type: " + sampleType_.toString() + " (" + sampleType_.getType() + ")\n" + - "}"; - } - - // The info from the SampleHeader. - private String name_; - private int start_; - private int end_; - private int startLoop_; - private int endLoop_; - private long sampleRate_; - private short originalKey_; - private byte correction_; - private int sampleLink_; - private SampleLink sampleType_; - - // All of the actual sample data from the SoundFont file. - private double[] sample_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/SampleLink.java b/core/src/com/levien/synthesizer/core/soundfont/SampleLink.java deleted file mode 100644 index df3c96a..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/SampleLink.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -/** - * SampleLink enum for the SoundFont format. - */ -public enum SampleLink { - UNKNOWN(-1), - MONO_SAMPLE(1), - RIGHT_SAMPLE(2), - LEFT_SAMPLE(4), - LINKED_SAMPLE(8), - ROM_MONO_SAMPLE(0x8001), - ROM_RIGHT_SAMPLE(0x8002), - ROM_LEFT_SAMPLE(0x8004), - ROM_LINKED_SAMPLE(0x8008); - - /** - * Creates a new enum value for the given type. - */ - SampleLink(int type) { - type_ = type; - } - - /** - * @return The enum value from the SoundFont format. - */ - public int getType() { - return type_; - } - - /** - * @return The enum corresponding to the given SoundFont format value. - */ - public static SampleLink fromType(int type) { - for (SampleLink sl : SampleLink.values()) { - if (sl.getType() == type) { - return sl; - } - } - return UNKNOWN; - } - - private final int type_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java b/core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java deleted file mode 100644 index 7f5165e..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/SoundFontOscillator.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.util.Arrays; -import java.util.logging.Logger; - -import com.levien.synthesizer.core.model.Envelope; -import com.levien.synthesizer.core.model.FrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.oscillator.Oscillator; -import com.levien.synthesizer.core.music.Note; -import com.levien.synthesizer.core.soundfont.Zone.SampleMode; - -/** - * An oscillator module that outputs a sample from a file. - */ -public class SoundFontOscillator extends Oscillator implements Envelope { - /** - * Creates a new oscillator from a preset in a SoundFont file. - * @param frequency - The frequency determines what key was pressed. - * @parma preset - The SoundFont preset to get the sample data from. - * @param sampleRateInHz - The sample rate of the output synthesizer. - */ - public SoundFontOscillator(FrequencyProvider frequency, - Preset preset, - double sampleRateInHz) { - super(frequency); - logger_ = Logger.getLogger(getClass().getName()); - preset_ = preset; - sampleRateInHz_ = sampleRateInHz; - - // Find the max sample length. - maxSampleLength_ = 1; - for (Zone pzone : preset_.getZoneList()) { - Instrument instrument = pzone.getInstrument(); - if (instrument != null) { - for (Zone izone : instrument.getZoneList()) { - Sample sample = izone.getSample(); - int length = (int)Math.ceil((sampleRateInHz_ * izone.getCount()) / sample.getRate()); - if (length > maxSampleLength_) { - maxSampleLength_ = length; - } - } - } - } - - currentSample_ = null; - currentSampleIndex_ = 0; - - buffer_ = new double[maxSampleLength_]; - Arrays.fill(buffer_, 0.0); - bufferIndex_ = 0; - } - - /** - * Gets one value from the synthesizer. - */ - public synchronized double computeValue(SynthesisTime time) { - // How many samples have passed? - double deltaTime = time.getAbsoluteTime() - previousTime_; - previousTime_ = time.getAbsoluteTime(); - - // First, skip over however many samples we've passed in the buffer. - int bufferSamples = (int)(deltaTime * sampleRateInHz_ + 0.5); - // If everything in the buffer would be skipped, don't do extra work. - if (bufferSamples > buffer_.length) { - bufferSamples = buffer_.length; - } - // Clear all of the ones we've passed. - for (int i = 0; i < bufferSamples; ++i) { - buffer_[bufferIndex_++] = 0.0; - if (bufferIndex_ >= buffer_.length) { - bufferIndex_ = 0; - } - } - double output = buffer_[bufferIndex_]; - - // If the instrument has been retriggered, find the right sample. - if (pressed_) { - pressed_ = false; - int key = Note.getKeyforLog12TET(frequency_.getLogFrequency(time)); - int velocity = 255; - initSample(key, velocity); - } else { - if (currentSample_ != null) { - // Advance by deltaTime in the current sample. - currentSampleIndex_ += deltaTime * currentSample_.getSample().getRate(); - if (currentSample_.getSampleMode() == SampleMode.NO_LOOP) { - if (currentSampleIndex_ > currentSample_.getEnd()) { - // We're off the end of the sample. - currentSample_ = null; - } - } else { - if (currentSampleIndex_ >= currentSample_.getEndLoop()) { - double distanceFromLoopStart = currentSampleIndex_ - currentSample_.getStartLoop(); - double loopLength = currentSample_.getEndLoop() - currentSample_.getStartLoop(); - currentSampleIndex_ = - currentSample_.getStartLoop() + (distanceFromLoopStart % loopLength); - } - } - } - } - - // Okay, now get the new data from the current sample. - if (currentSample_ != null) { - int firstSample = (int)currentSampleIndex_; - double weight = 1.0 - (currentSampleIndex_ - firstSample); - if (weight == 1.0) { - output += currentSample_.getSample().getSample(firstSample); - } else { - output += - weight * currentSample_.getSample().getSample(firstSample) + - (1.0 - weight) * currentSample_.getSample().getSample(firstSample + 1); - } - } - - return output; - } - - /** - * Initializes the "current sample" based on the given key and velocity. - */ - private synchronized void initSample(int key, int velocity) { - // Find any sample in this preset that can handle the given key and velocity. - currentSample_ = null; - for (Zone pzone : preset_.getZoneList()) { - Instrument instrument = pzone.getInstrument(); - if (instrument != null) { - for (Zone izone : instrument.getZoneList()) { - if (izone.inKeyRange(key) && - izone.inVelocityRange(velocity) && - izone.getSample() != null) { - currentSample_ = izone; - currentSampleIndex_ = currentSample_.getStart(); - return; - } - } - } - } - } - - /** - * Trigger this oscillator to start outputting from the sample. - */ - public synchronized void turnOn(boolean retriggerIfOn) { - pressed_ = true; - } - - /** - * Turns off this oscillator from getting data from the current sample. - * If this sample supports it, then the rest of the current sample is copied to the output buffer - * before the current sample is cleared. - */ - public synchronized void turnOff() { - if (currentSample_ != null) { - // Copy in the rest of the current sample. - int bufferIndex = bufferIndex_; - while (currentSampleIndex_ <= currentSample_.getEnd()) { - int firstSample = (int)currentSampleIndex_; - double weight = 1.0 - (currentSampleIndex_ - firstSample); - if (weight == 1.0) { - buffer_[bufferIndex] += currentSample_.getSample().getSample(firstSample); - } else { - buffer_[bufferIndex] += - weight * currentSample_.getSample().getSample(firstSample) + - (1.0 - weight) * currentSample_.getSample().getSample(firstSample + 1); - } - bufferIndex = (bufferIndex + 1) % buffer_.length; - currentSampleIndex_ += (currentSample_.getSample().getRate() / sampleRateInHz_); - } - } - currentSample_ = null; - } - - @SuppressWarnings("unused") - private Logger logger_; - - // The preset to get samples from. - private Preset preset_; - - // The current sample being played, and where in the sample we are currently at in the output. - private Zone currentSample_; - private double currentSampleIndex_; - - // A buffer of data that has been queued up and should be played in the future. This handles the - // case of releasing the key and then pressing it again at a different value. - private double[] buffer_; - private int bufferIndex_; - - // True if the oscillator has been triggered, but the sample hasn't been loaded yet. - private boolean pressed_; - - // The previous time the oscillator was polled for its value. - private double previousTime_; - - // The maximum length of any sample in this preset, converted to the output sample rate. - private int maxSampleLength_; - - // The sample rate of the output synthesizer. - private double sampleRateInHz_; -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java b/core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java deleted file mode 100644 index f482da6..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/SoundFontReader.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -//import com.levien.synthesizer.core.model.sample.Proto; -import com.levien.synthesizer.core.wave.RiffInputStream; - -/** - * Reads a SoundFont file from a stream and provides access its data. - */ -public class SoundFontReader { - /** - * Reads the .sf2 file from a stream and stores the data in a buffer. - * @param input - the stream to read from. - * @throws IOExpection - on a malformed or unsupported file format. - */ - public SoundFontReader(InputStream in) throws IOException { - Logger logger = Logger.getLogger(getClass().getName()); - logger.info("Loading SoundFont file."); - - RiffInputStream input = new RiffInputStream(in); - - input.checkBytes("RIFF"); - long riffSize = input.readDWord(); - long riffRemaining = riffSize; - - input.checkBytes("sfbk"); - riffRemaining -= 4; - - // All of the sample data, scaled from -1 to 1. - double[] samples = null; - - while (riffRemaining > 0) { - input.checkBytes("LIST"); - long listSize = input.readDWord(); - riffRemaining -= 8; - riffRemaining -= listSize; - String chunk = input.readString(4); - long listRemaining = listSize; - listRemaining -= 4; - if (chunk.equals("INFO")) { - // Mostly worthless info headers. - while (listRemaining > 0) { - String subchunk = input.readString(4); - int subchunkSize = (int)input.readDWord(); - listRemaining -= 8; - listRemaining -= subchunkSize; - if (subchunk.equals("ifil")) { - if (subchunkSize != 4) { - throw new IOException("ifil size != 4."); - } - majorVersion_ = input.readWord(); - minorVersion_ = input.readWord(); - } else if (subchunk.equals("isng")) { - engine_ = input.readString(subchunkSize); - } else if (subchunk.equals("INAM")) { - name_ = input.readString(subchunkSize); - } else if (subchunk.equals("irom")) { - rom_ = input.readString(subchunkSize); - } else if (subchunk.equals("iver")) { - if (subchunkSize != 4) { - throw new IOException("iver size != 4."); - } - romMajorVersion_ = input.readWord(); - romMinorVersion_ = input.readWord(); - } else if (subchunk.equals("ICRD")) { - creationDate_ = input.readString(subchunkSize); - } else if (subchunk.equals("IENG")) { - engineer_ = input.readString(subchunkSize); - } else if (subchunk.equals("IPRD")) { - product_ = input.readString(subchunkSize); - } else if (subchunk.equals("ICOP")) { - copyright_ = input.readString(subchunkSize); - } else if (subchunk.equals("ICMT")) { - comment_ = input.readString(subchunkSize); - } else if (subchunk.equals("ISFT")) { - software_ = input.readString(subchunkSize); - } else { - logger.info("Skipping unknown INFO subchunk type " + subchunk + "."); - input.skipBytes(subchunkSize); - } - } - System.out.println("Read SoundFont INFO: \n" + this.toString()); - } else if (chunk.equals("sdta")) { - // The actual sample data. - while (listRemaining > 0) { - String subchunk = input.readString(4); - long subchunkSize = input.readDWord(); - listRemaining -= 8; - listRemaining -= subchunkSize; - if (subchunk.equals("smpl")) { - int words = (int)(subchunkSize / 2); - logger.info("Reading " + words + " samples."); - samples = new double[words]; - for (int i = 0; i < words; ++i) { - samples[i] = input.readShort() / 32768.0; - } - } else { - logger.info("Skipping unknown sdta subchunk type " + subchunk + "."); - input.skipBytes(subchunkSize); - } - } - } else if (chunk.equals("pdta")) { - // This is the so-called HYDRA data structure, with 9 parts. - - ArrayList presetBagList = new ArrayList(); - ArrayList presetModulatorList = new ArrayList(); - ArrayList presetGeneratorList = new ArrayList(); - ArrayList instrumentList = new ArrayList(); - ArrayList instrumentBagList = new ArrayList(); - ArrayList instrumentModulatorList = new ArrayList(); - ArrayList instrumentGeneratorList = new ArrayList(); - ArrayList sampleHeaderList = new ArrayList(); - - // Preset data is the metadata about the samples. - while (listRemaining > 0) { - String subchunk = input.readString(4); - long subchunkSize = input.readDWord(); - listRemaining -= 8; - listRemaining -= subchunkSize; - byte[] subchunkData = input.readBytes((int)subchunkSize); - ByteArrayInputStream subchunkInput = new ByteArrayInputStream(subchunkData); - if (subchunk.equals("phdr")) { - Preset previous = null; - while (subchunkInput.available() > 0) { - Preset preset = new Preset(new RiffInputStream(subchunkInput)); - logger.info("Found preset: " + preset.getName()); - if (previous != null) { - previous.setBagEnd(preset.getBagStart()); - presets_.add(previous); - } - previous = preset; - } - } else if (subchunk.equals("pbag")) { - Bag previous = null; - while (subchunkInput.available() > 0) { - Bag presetBag = new Bag(new RiffInputStream(subchunkInput)); - if (previous != null) { - previous.setGeneratorEnd(presetBag.getGeneratorStart()); - previous.setModulatorEnd(presetBag.getModulatorStart()); - presetBagList.add(previous); - } - previous = presetBag; - } - } else if (subchunk.equals("pmod")) { - while (subchunkInput.available() > 0) { - Modulator presetModulator = new Modulator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - presetModulatorList.add(presetModulator); - } - } - } else if (subchunk.equals("pgen")) { - while (subchunkInput.available() > 0) { - Generator generator = new Generator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - presetGeneratorList.add(generator); - } - } - } else if (subchunk.equals("inst")) { - Instrument previous = null; - while (subchunkInput.available() > 0) { - Instrument instrument = new Instrument(new RiffInputStream(subchunkInput)); - logger.info("Found instrument: " + instrument.getName()); - if (previous != null) { - previous.setBagEnd(instrument.getBagStart()); - instrumentList.add(previous); - } - previous = instrument; - } - } else if (subchunk.equals("ibag")) { - Bag previous = null; - while (subchunkInput.available() > 0) { - Bag instrumentBag = new Bag(new RiffInputStream(subchunkInput)); - if (previous != null) { - previous.setGeneratorEnd(instrumentBag.getGeneratorStart()); - previous.setModulatorEnd(instrumentBag.getModulatorStart()); - instrumentBagList.add(previous); - } - previous = instrumentBag; - } - } else if (subchunk.equals("imod")) { - while (subchunkInput.available() > 0) { - Modulator instrumentModulator = new Modulator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - instrumentModulatorList.add(instrumentModulator); - } - } - } else if (subchunk.equals("igen")) { - while (subchunkInput.available() > 0) { - Generator generator = new Generator(new RiffInputStream(subchunkInput)); - if (subchunkInput.available() > 0) { - instrumentGeneratorList.add(generator); - } - } - } else if (subchunk.equals("shdr")) { - while (subchunkInput.available() > 0) { - Sample sampleHeader = new Sample(new RiffInputStream(subchunkInput), - samples); - if (subchunkInput.available() > 0) { - sampleHeaderList.add(sampleHeader); - } - } - } else { - logger.info("Skipping unknown pdta subchunk type " + subchunk + "."); - } - } - - // Now that we've read in the HYDRA, we have to backtrack through it to convert the _bags_ - // to _zones_. - - for (Preset preset : presets_) { - // There might be a "global" zone for the preset that applies to all the other zones. - Zone globalZone = null; - for (int bag = preset.getBagStart(); bag < preset.getBagEnd(); ++bag) { - // Start with the global zone, if it exists. - Zone zone = (globalZone != null) ? globalZone.copy() : new Zone(); - for (int gen = presetBagList.get(bag).getGeneratorStart(); - gen < presetBagList.get(bag).getGeneratorEnd(); - ++gen) { - zone.addPresetGenerator(presetGeneratorList.get(gen), instrumentList); - } - for (int mod = presetBagList.get(bag).getModulatorStart(); - mod < presetBagList.get(bag).getModulatorEnd(); - ++mod) { - zone.addModulator(presetModulatorList.get(mod)); - } - // This might be the global zone for the preset. - if (zone.getInstrument() == null) { - if (globalZone == null) { - // It is the global zone, so set it. - globalZone = zone; - } - // Any zone missing an instrument is either the global zone or should be ignored. - continue; - } - // Okay, it's not the global zone. - preset.addZone(zone); - } - } - - for (Instrument instrument : instrumentList) { - // There might be a "global" zone for the preset that applies to all the other zones. - Zone globalZone = null; - for (int bag = instrument.getBagStart(); bag < instrument.getBagEnd(); ++bag) { - // Start with the global zone, if it exists. - Zone zone = (globalZone != null) ? globalZone.copy() : new Zone(); - for (int gen = instrumentBagList.get(bag).getGeneratorStart(); - gen < instrumentBagList.get(bag).getGeneratorEnd(); - ++gen) { - zone.addInstrumentGenerator(instrumentGeneratorList.get(gen), sampleHeaderList); - } - for (int mod = instrumentBagList.get(bag).getModulatorStart(); - mod < instrumentBagList.get(bag).getModulatorEnd(); - ++mod) { - zone.addModulator(instrumentModulatorList.get(mod)); - } - // This might be the global zone for the preset. - if (zone.getSample() == null) { - if (globalZone == null) { - // It is the global zone, so set it. - globalZone = zone; - } - // Any zone missing an instrument is either the global zone or should be ignored. - continue; - } - // Okay, it's not the global zone. - instrument.addZone(zone); - } - } - - // TODO(klimt): So, actually some of the generator values for an instrument should be added - // to the generator values for the preset zone it's in, but an instrument could be in - // multiple different preset zones, so there's no way to store that here. So I need to make - // a function to add two zones, and call it whenever the instrument zone is used. Grrr. - } else { - logger.info("Skipping unknown sfbk LIST type " + chunk + "."); - input.skipBytes(listRemaining); - } - } - input.close(); - } - - public List getPresets() { - return presets_; - } - - public String toString() { - return - "version: " + majorVersion_ + "." + minorVersion_ + "\n" + - "engine: " + engine_ + "\n" + - "name: " + name_ + "\n" + - "rom: " + rom_ + "\n" + - "rom version: " + romMajorVersion_ + "." + romMinorVersion_ + "\n" + - "created: " + creationDate_ + "\n" + - "engineer: " + engineer_ + "\n" + - "product: " + product_ + "\n" + - "copyright: " + copyright_ + "\n" + - "comment: " + comment_ + "\n" + - "software: " + software_ + "\n"; - } - - private int majorVersion_; - private int minorVersion_; - private String engine_; - private String name_; - private String rom_; - private int romMajorVersion_; - private int romMinorVersion_; - private String creationDate_; - private String engineer_; - private String product_; - private String copyright_; - private String comment_; - private String software_; - private ArrayList presets_ = new ArrayList(); -} diff --git a/core/src/com/levien/synthesizer/core/soundfont/Zone.java b/core/src/com/levien/synthesizer/core/soundfont/Zone.java deleted file mode 100644 index db077af..0000000 --- a/core/src/com/levien/synthesizer/core/soundfont/Zone.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.soundfont; - -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * A zone is like a flattened bag that contains any of the settings that could be in a bag. - */ -@SuppressWarnings("unused") -public class Zone { - /** - * Creates a new Zone that's empty. - */ - public Zone() { - logger_ = Logger.getLogger(getClass().getName()); - modulatorList_ = new ArrayList(); - } - - /** - * Copies all of the values from another zone into this one. - */ - public void CopyFrom(Zone other) { - instrument_ = other.instrument_; - sample_ = other.sample_; - startAddrsOffset_ = other.startAddrsOffset_; - endAddrsOffset_ = other.endAddrsOffset_; - startloopAddrsOffset_ = other.startloopAddrsOffset_; - endloopAddrsOffset_ = other.endloopAddrsOffset_; - startAddrsCoarseOffset_ = other.startAddrsCoarseOffset_; - endAddrsCoarseOffset_ = other.endAddrsCoarseOffset_; - startloopAddrsCoarseOffset_ = other.startloopAddrsCoarseOffset_; - endloopAddrsCoarseOffset_ = other.endloopAddrsCoarseOffset_; - modLfoToPitch_ = other.modLfoToPitch_; - vibLfoToPitch_ = other.vibLfoToPitch_; - modEnvToPitch_ = other.modEnvToPitch_; - initialFilterFc_ = other.initialFilterFc_; - initialFilterQ_ = other.initialFilterQ_; - modLfoToFilterFc_ = other.modLfoToFilterFc_; - modEnvToFilterFc_ = other.modEnvToFilterFc_; - modLfoToVolume_ = other.modLfoToVolume_; - chorusEffectsSend_ = other.chorusEffectsSend_; - reverbEffectsSend_ = other.reverbEffectsSend_; - pan_ = other.pan_; - delayModLFO_ = other.delayModLFO_; - freqModLFO_ = other.freqModLFO_; - delayVibLFO_ = other.delayVibLFO_; - freqVibLFO_ = other.freqVibLFO_; - delayModEnv_ = other.delayModEnv_; - attackModEnv_ = other.attackModEnv_; - holdModEnv_ = other.holdModEnv_; - decayModEnv_ = other.decayModEnv_; - sustainModEnv_ = other.sustainModEnv_; - releaseModEnv_ = other.releaseModEnv_; - keynumToModEnvHold_ = other.keynumToModEnvHold_; - keynumToModEnvDecay_ = other.keynumToModEnvDecay_; - delayVolEnv_ = other.delayVolEnv_; - attackVolEnv_ = other.attackVolEnv_; - holdVolEnv_ = other.holdVolEnv_; - decayVolEnv_ = other.decayVolEnv_; - sustainVolEnv_ = other.sustainVolEnv_; - releaseVolEnv_ = other.releaseVolEnv_; - keynumToVolEnvHold_ = other.keynumToVolEnvHold_; - keynumToVolEnvDecay_ = other.keynumToVolEnvDecay_; - minKey_ = other.minKey_; - maxKey_ = other.maxKey_; - minVelocity_ = other.minVelocity_; - maxVelocity_ = other.maxVelocity_; - keynum_ = other.keynum_; - velocity_ = other.velocity_; - initialAttenuation_ = other.initialAttenuation_; - coarseTune_ = other.coarseTune_; - fineTune_ = other.fineTune_; - sampleMode_ = other.sampleMode_; - scaleTuning_ = other.scaleTuning_; - exclusiveClass_ = other.exclusiveClass_; - overridingRootKey_ = other.overridingRootKey_; - modulatorList_ = new ArrayList(other.modulatorList_); - } - - /** - * @return A new Zone equivalent to this one. - */ - public Zone copy() { - Zone other = new Zone(); - other.CopyFrom(this); - return other; - } - - /** - * @return The input converted from cents to octaves. - */ - private static double convertCentsToOctaves(double value) { - return value / 1200.0; - } - - /** - * @return The input converted from cents to seconds. - */ - private static double convertCentsToSeconds(double value) { - return Math.pow(2.0, convertCentsToOctaves(value)); - } - - /** - * Adds a preset generator to this Zone. - * @param generator - The generator to add. - * @param instruments - The list of all instruments in this SoundFont file. - */ - public void addPresetGenerator(Generator generator, - List instruments) { - if (!generator.getOperator().isValidForPreset()) { - throw new IllegalArgumentException("Invalid operator for preset: " + - generator.getOperator() + "."); - } - addGenerator(generator, instruments, null); - } - - /** - * Adds an instrument generator to this Zone. - * @param generator - The generator to add. - * @param samples - The list of all samples in this SoundFont file. - */ - public void addInstrumentGenerator(Generator generator, - List samples) { - if (!generator.getOperator().isValidForInstrument()) { - throw new IllegalArgumentException("Invalid operator for instrument: " + - generator.getOperator() + "."); - } - addGenerator(generator, null, samples); - } - - /** - * Internal method to add a generator of either type. - */ - protected void addGenerator(Generator generator, - List instruments, - List samples) { - short amount = generator.getAmount(); - // - // This ridiculous switch statement takes the given operator and decodes its argument into the - // right values in the Zone. - // - switch (generator.getOperator()) { - case UNSUPPORTED: { - break; - } - case START_ADDRS_OFFSET: { - startAddrsOffset_ = amount; break; - } - case END_ADDRS_OFFSET: { - endAddrsOffset_ = amount; break; - } - case STARTLOOP_ADDRS_OFFSET: { - startloopAddrsOffset_ = amount; break; - } - case ENDLOOP_ADDRS_OFFSET: { - endloopAddrsOffset_ = amount; break; - } - case START_ADDRS_COARSE_OFFSET: { - startAddrsCoarseOffset_ = amount * 32768; break; - } - case MOD_LFO_TO_PITCH: { - modLfoToPitch_ = convertCentsToOctaves(amount); break; - } - case VIB_LFO_TO_PITCH: { - vibLfoToPitch_ = convertCentsToOctaves(amount); break; - } - case MOD_ENV_TO_PITCH: { - modEnvToPitch_ = convertCentsToOctaves(amount); break; - } - case INITIAL_FILTER_FC: { - initialFilterFc_ = convertCentsToOctaves(amount); break; - } - case INITIAL_FILTER_Q: { - initialFilterQ_ = amount; break; - } - case MOD_LFO_TO_FILTER_FC: { - modLfoToFilterFc_ = convertCentsToOctaves(amount); break; - } - case MOD_ENV_TO_FILTER_FC: { - modEnvToFilterFc_ = convertCentsToOctaves(amount); break; - } - case END_ADDRS_COARSE_OFFSET: { - endAddrsCoarseOffset_ = amount * 32768; break; - } - case MOD_LFO_TO_VOLUME: { - modLfoToVolume_ = amount; break; - } - case CHORUS_EFFECTS_SEND: { - chorusEffectsSend_ = amount / 1000.0; break; - } - case REVERB_EFFECTS_SEND: { - reverbEffectsSend_ = amount / 1000.0; break; - } - case PAN: { - pan_ = amount / 1000.0; break; - } - case DELAY_MOD_LFO: { - delayModLFO_ = convertCentsToSeconds(amount); break; - } - case FREQ_MOD_LFO: { - freqModLFO_ = convertCentsToOctaves(amount); break; - } - case DELAY_VIB_LFO: { - delayVibLFO_ = convertCentsToSeconds(amount); break; - } - case FREQ_VIB_LFO: { - freqVibLFO_ = convertCentsToOctaves(amount); break; - } - case DELAY_MOD_ENV: { - delayModEnv_ = convertCentsToSeconds(amount); break; - } - case ATTACK_MOD_ENV: { - attackModEnv_ = convertCentsToSeconds(amount); break; - } - case HOLD_MOD_ENV: { - holdModEnv_ = convertCentsToSeconds(amount); break; - } - case DECAY_MOD_ENV: { - decayModEnv_ = convertCentsToSeconds(amount); break; - } - case SUSTAIN_MOD_ENV: { - sustainModEnv_ = 1.0 - (amount / -1000.0); break; - } - case RELEASE_MOD_ENV: { - releaseModEnv_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_MOD_ENV_HOLD: { - keynumToModEnvHold_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_MOD_ENV_DECAY: { - keynumToModEnvDecay_ = convertCentsToSeconds(amount); break; - } - case DELAY_VOL_ENV: { - delayVolEnv_ = convertCentsToSeconds(amount); break; - } - case ATTACK_VOL_ENV: { - attackVolEnv_ = convertCentsToSeconds(amount); break; - } - case HOLD_VOL_ENV: { - holdVolEnv_ = convertCentsToSeconds(amount); break; - } - case DECAY_VOL_ENV: { - decayVolEnv_ = convertCentsToSeconds(amount); break; - } - case SUSTAIN_VOL_ENV: { - sustainVolEnv_ = 1.0 - (amount / -1000.0); break; - } - case RELEASE_VOL_END: { - releaseVolEnv_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_VOL_ENV_HOLD: { - keynumToVolEnvHold_ = convertCentsToSeconds(amount); break; - } - case KEYNUM_TO_VOL_ENV_DECAY: { - keynumToVolEnvDecay_ = convertCentsToSeconds(amount); break; - } - case INSTRUMENT: { - instrument_ = instruments.get(((int)amount) & 0xFFFF); break; - } - case KEY_RANGE: { - minKey_ = amount & 0xFF; - maxKey_ = (amount >> 8) & 0xFF; - break; - } - case VELOCITY_RANGE: { - minVelocity_ = amount & 0xFF; - maxVelocity_ = (amount >> 8) & 0xFF; - break; - } - case STARTLOOP_ADDRS_COARSE_OFFSET: { - startloopAddrsCoarseOffset_ = amount * 32768; break; - } - case KEYNUM: { - keynum_ = amount & 0xFF; break; - } - case VELOCITY: { - velocity_ = amount & 0xFF; break; - } - case INITIAL_ATTENUATION: { - initialAttenuation_ = amount; break; - } - case ENDLOOP_ADDRS_COARSE_OFFSET: { - endloopAddrsCoarseOffset_ = amount * 32768; break; - } - case COARSE_TUNE: { - coarseTune_ = amount / 12.0; break; - } - case FINE_TUNE: { - fineTune_ = convertCentsToOctaves(amount); break; - } - case SAMPLE_ID: { - sample_ = samples.get(((int)amount) & 0xFFFF); break; - } - case SAMPLE_MODES: { - switch (amount & 0x03) { - case 0: sampleMode_ = SampleMode.NO_LOOP; break; - case 1: sampleMode_ = SampleMode.LOOP_CONTINUOUSLY; break; - case 2: sampleMode_ = SampleMode.NO_LOOP; break; - case 3: sampleMode_ = SampleMode.LOOP_CONTINUOUSLY_THEN_FINISH; break; - } - break; - } - case SCALE_TUNING: { - scaleTuning_ = convertCentsToOctaves(amount); break; - } - case EXCLUSIVE_CLASS: { - exclusiveClass_ = amount & 0xFF; break; - } - case OVERRIDING_ROOT_KEY: { - overridingRootKey_ = amount & 0xFF; break; - } - case END_OPER: { - break; - } - } - } - - /** - * Adds a modulator the zone. - */ - public void addModulator(Modulator modulator) { - modulatorList_.add(modulator); - } - - /** - * @return the index of the first sample in this instrument zone. - * Adjusts based on the generator settings. - */ - public long getStart() { - long start = startAddrsOffset_ + startAddrsCoarseOffset_; - if (sample_ != null) { - start += sample_.getStart(); - } - return start; - } - - /** - * @return the index one after the last sample in this instrument zone. - * Adjusts based on the generator settings. - */ - public long getEnd() { - long end = endAddrsOffset_ + endAddrsCoarseOffset_; - if (sample_ != null) { - end += sample_.getEnd(); - } - return end; - } - - /** - * @return the number of samples in this instrument zone. - * Adjusts based on the generator settings. - */ - public long getCount() { - return getEnd() - getStart(); - } - - /** - * @return the index of the first sample in this instrument zone's loop subset. - * Adjusts based on the generator settings. - */ - public long getStartLoop() { - long startloop = startloopAddrsOffset_ + startloopAddrsCoarseOffset_; - if (sample_ != null) { - startloop += sample_.getStart(); - } - return startloop; - } - - /** - * @return the index one after the last sample in this instrument zone's loop subset. - * Adjusts based on the generator settings. - */ - public long getEndLoop() { - long endloop = endloopAddrsOffset_ + endloopAddrsCoarseOffset_; - if (sample_ != null) { - endloop += sample_.getEnd(); - } - return endloop; - } - - /** - * @return The instrument associated with this preset zone. - */ - public Instrument getInstrument() { - return instrument_; - } - - /** - * @return True if this instrument zone can handle the given key. - */ - public boolean inKeyRange(int key) { - return ((minKey_ < 0 || key >= minKey_) && - (maxKey_ < 0 || key <= maxKey_)); - } - - /** - * @return True if this instrument zone can handle the given velocity. - */ - public boolean inVelocityRange(int velocity) { - return ((minVelocity_ < 0 || velocity >= minVelocity_) && - (maxVelocity_ < 0 || velocity <= maxVelocity_)); - } - - /** - * @return The sample associated with this instrument zone. - */ - public Sample getSample() { - return sample_; - } - - /** - * @return The sample mode for this instrument zone. - */ - public SampleMode getSampleMode() { - return sampleMode_; - } - - private Logger logger_; - - // - // The various settings for a zone, according to the SoundFont 2.1 format specification. - // Most of these are ignored in this synthesizer implementation, but some are not. - // - - private Instrument instrument_ = null; // Set for a preset zone. - private Sample sample_ = null; // Set for an instrument zone. - - // All in samples. - private int startAddrsOffset_ = 0; - private int endAddrsOffset_ = 0; - private int startloopAddrsOffset_ = 0; - private int endloopAddrsOffset_ = 0; - private int startAddrsCoarseOffset_ = 0; - private int endAddrsCoarseOffset_ = 0; - private int startloopAddrsCoarseOffset_ = 0; - private int endloopAddrsCoarseOffset_ = 0; - - // All in log Hz. - private double modLfoToPitch_ = 0; - private double vibLfoToPitch_ = 0; - private double modEnvToPitch_ = 0; - - private double initialFilterFc_ = convertCentsToOctaves(13500); // in log Hz. - private int initialFilterQ_ = 0; // in centibels. - private double modLfoToFilterFc_ = 0; // in log Hz. - private double modEnvToFilterFc_ = 0; // in log Hz. - - private int modLfoToVolume_ = 0; // in centibels. - - // All are percentages. - private double chorusEffectsSend_ = 0.0; - private double reverbEffectsSend_ = 0.0; - private double pan_ = 0.0; - - private double delayModLFO_ = convertCentsToSeconds(-12000); // in seconds. - private double freqModLFO_ = 0; // in log Hz. - private double delayVibLFO_ = convertCentsToSeconds(-12000); // in seconds. - private double freqVibLFO_ = 0; // in log Hz. - - // All in seconds, except sustain. - private double delayModEnv_ = convertCentsToSeconds(-12000); - private double attackModEnv_ = convertCentsToSeconds(-12000); - private double holdModEnv_ = convertCentsToSeconds(-12000); - private double decayModEnv_ = convertCentsToSeconds(-12000); - private double sustainModEnv_ = 0; // percentage. - private double releaseModEnv_ = convertCentsToSeconds(-12000); - - // All in seconds per key. - private double keynumToModEnvHold_ = 0; - private double keynumToModEnvDecay_ = 0; - - // All in seconds, except sustain. - private double delayVolEnv_ = convertCentsToSeconds(-12000); - private double attackVolEnv_ = convertCentsToSeconds(-12000); - private double holdVolEnv_ = convertCentsToSeconds(-12000); - private double decayVolEnv_ = convertCentsToSeconds(-12000); - private double sustainVolEnv_ = 0; // percentage. - private double releaseVolEnv_ = convertCentsToSeconds(-12000); - - // All in seconds per key. - private double keynumToVolEnvHold_ = 0; - private double keynumToVolEnvDecay_ = 0; - - // These are midi values in the range [0, 127]. -1 means unset. - private int minKey_ = -1; - private int maxKey_ = -1; - private int minVelocity_ = -1; - private int maxVelocity_ = -1; - - // These values override the input value. - private int keynum_ = -1; - private int velocity_ = -1; - - private int initialAttenuation_ = 0; // in centibels. - - // All in log Hz. - private double coarseTune_ = 0; - private double fineTune_ = 0; - - enum SampleMode { - NO_LOOP, - LOOP_CONTINUOUSLY, - LOOP_CONTINUOUSLY_THEN_FINISH, - } - private SampleMode sampleMode_ = SampleMode.NO_LOOP; - - private double scaleTuning_ = 0; // in log Hz per key. - private int exclusiveClass_ = 0; // An id in range [1, 127], or 0 if not set. - private int overridingRootKey_ = -1; // A key in range [0, 127], or -1 if not set. - - // All of the modulators in this zone. This is ignored. - private ArrayList modulatorList_; -} diff --git a/core/src/com/levien/synthesizer/core/wave/RiffInputStream.java b/core/src/com/levien/synthesizer/core/wave/RiffInputStream.java deleted file mode 100644 index 73c8b37..0000000 --- a/core/src/com/levien/synthesizer/core/wave/RiffInputStream.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.levien.synthesizer.core.wave; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * A wrapper around an InputStream that provides some utility functions for reading RIFF files. - */ -public class RiffInputStream extends FilterInputStream { - /** - * Creates a new RiffInputStream wrapping the given input stream. - */ - public RiffInputStream(InputStream in) { - super(in); - } - - /** - * Skips the specified number of bytes in the input. - */ - public void skipBytes(long bytes) throws IOException { - while (bytes > 0) { - int skipped = (int)skip(bytes); - if (skipped <= 0) { - throw new IOException("Error skipping bytes."); - } - bytes -= skipped; - } - } - - /** - * Reads one signed byte from an input stream. - * @param output - the stream to read from. - * @return the signed byte read. - * @throws IOException - on any kind of read error or EOF. - */ - public byte readChar() throws IOException { - return (byte)readByte(); - } - - /** - * Reads one unsigned byte from an input stream. - * @param output - the stream to read from. - * @return the unsigned byte read. - * @throws IOException - on any kind of read error or EOF. - */ - public short readByte() throws IOException { - int b = read(); - if (b < 0) { - throw new IOException("Unexpected EOF while reading byte."); - } - return (short)(b & 0xFF); - } - - /** - * Checks that the given String matches the next bytes in the input stream. - * @param input - the stream to read from. - * @param data - the String to check for. - * @throws IOException - On any kind of read error or if the exact string wasn't found. - */ - public void checkBytes(String data) throws IOException { - byte[] bytes = data.getBytes(); - for (int i = 0; i < bytes.length; ++i) { - int b = read(); - if (b < 0) { - throw new IOException("Expected " + bytes[i] + ", got EOF, while looking for " + data); - } - if ((byte)b != bytes[i]) { - throw new IOException("Expected " + bytes[i] + ", got " + (byte)b + - ", while looking for " + data); - } - } - } - - /** - * Reads the given number of bytes and returns an array of them. - * @param input - the stream to read from. - * @param size - the number of bytes to read. - * @throws IOException - On any kind of read error or EOF. - */ - public byte[] readBytes(int size) throws IOException { - // TODO(klimt): This could be more efficient. - byte[] bytes = new byte[size]; - int length = 0; - for (length = 0; length < bytes.length; ++length) { - int b = read(); - if (b < 0) { - throw new IOException("Unexpected EOF while reading bytes."); - } - bytes[length] = (byte)b; - } - return bytes; - } - - /** - * Reads a string of the given size from the input stream. - * I'm not sure what happens if it's not ASCII. - * @param input - the stream to read from. - * @param size - the number of bytes to read. - * @throws IOException - On any kind of read error or if the exact string wasn't found. - */ - public String readString(int size) throws IOException { - byte[] bytes = new byte[size]; - int length = 0; - for (length = 0; length < bytes.length; ++length) { - int b = read(); - if (b < 0) { - throw new IOException("Unexpected EOF while reading string."); - } - if (b == 0) { - skipBytes(size - (length + 1)); - break; - } - bytes[length] = (byte)b; - } - String s = new String(bytes, 0, length); - if (s.length() > size) { - throw new IOException("Read string \"" + s + "\" longer than " + size + " bytes."); - } - return s; - } - - /** - * Reads one unsigned dword (32 bits) from an input stream in little-endian format. - * @param input - the stream to read from. - * @return - the unsigned dword read. - * @throws IOException - on any kind of read error or EOF. - */ - public long readDWord() throws IOException { - long byte1 = read(); - long byte2 = read(); - long byte3 = read(); - long byte4 = read(); - if (byte1 < 0 || byte2 < 0 || byte3 < 0 || byte4 < 0) { - throw new IOException("Unexpected EOF while reading int32."); - } - return (byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1; - } - - /** - * Reads one signed word (16 bits) from an input stream in little-endian format. - * @param output - the stream to read from. - * @return the signed word read. - * @throws IOException - on any kind of read error or EOF. - */ - public short readShort() throws IOException { - return (short)readWord(); - } - - /** - * Reads one unsigned word (16 bits) from an input stream in little-endian format. - * @param output - the stream to read from. - * @return the unsigned word read. - * @throws IOException - on any kind of read error or EOF. - */ - public int readWord() throws IOException { - int lower = read(); - int upper = read(); - if (lower < 0 || upper < 0) { - throw new IOException("Unexpected EOF while reading int16."); - } - int value = (int)(((upper << 8) | lower) & 0xFFFF); - return value; - } -} diff --git a/core/src/com/levien/synthesizer/core/wave/WaveAdapter.java b/core/src/com/levien/synthesizer/core/wave/WaveAdapter.java deleted file mode 100644 index 71f1ce6..0000000 --- a/core/src/com/levien/synthesizer/core/wave/WaveAdapter.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.wave; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -/** - * A WaveAdapter wraps a synthesizer component and allows siphoning off its output and writing it to - * a wave file. - * @see WaveWriter - */ -public class WaveAdapter extends CachedSignalProvider { - /** - * Creates a new WaveAdapter. - * @param sampleRate - The sample rate of the synthesizer in Hz. - * @param bitsPerSample - The bits per sample of the wave file to write. Should be 8 or 16. - * @param source - The synthesizer component to siphon output from. - */ - public WaveAdapter(int sampleRate, int bitsPerSample, SignalProvider source) { - logger_ = Logger.getLogger(getClass().getName()); - sampleRate_ = sampleRate; - bitsPerSample_ = bitsPerSample; - source_ = source; - } - - /** - * Starts the WaveAdapter recording for a specified length of time. - * @param seconds - The length of time to record. - * @parma output - The stream to write the output to. - */ - public synchronized void startRecording(double seconds, OutputStream output) { - if (writer_ != null) { - try { - writer_.close(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to close wave file.", e); - } - writer_ = null; - } - writer_ = new WaveWriter(sampleRate_, bitsPerSample_); - logger_.info("Recording " + seconds + " seconds to file."); - try { - writer_.startRecording(seconds, output); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to open wave file for writing.", e); - } - } - - /** - * Reads one sample from source, writes it to output, and returns it. - */ - @Override - protected synchronized double computeValue(SynthesisTime time) { - double value = source_.getValue(time); - if (writer_ != null) { - try { - if (!writer_.writeSample(value)) { - // The file is full. - logger_.info("Finished writing wave file."); - close(); - } - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to write sample to wave file. Aborting.", e); - close(); - } - } - return value; - } - - /** - * Makes sure the file is closed. You don't need to call this between recordings, but only when - * you are done, to make sure the last wave file was closed. If the file has already finished - * recording, then this method will not do anything. - */ - public synchronized void close() { - if (writer_ != null) { - try { - writer_.close(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to close the wave file. Aborting.", e); - } - writer_ = null; - } - } - - // The sample rate of the source and output, in Hz. - private int sampleRate_; - - // The number of bits per sample specified when creating the file. Should be 8 or 16. - private int bitsPerSample_; - - // The synthesizer module to siphon output from. - private SignalProvider source_; - - // The underlying writer that does the real work of creating the wave file. - private WaveWriter writer_; - - private Logger logger_; -} diff --git a/core/src/com/levien/synthesizer/core/wave/WaveReader.java b/core/src/com/levien/synthesizer/core/wave/WaveReader.java deleted file mode 100644 index f3b5113..0000000 --- a/core/src/com/levien/synthesizer/core/wave/WaveReader.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.wave; - -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Logger; - -/** - * Reads a WAVE file from a stream and provides access its data. - */ -public class WaveReader { - /** - * Reads the WAVE file from a stream and stores the data in a buffer. - * @param input - the stream to read from. - * @throws IOExpection - on a malformed or unsupported file format. - */ - public WaveReader(InputStream in) throws IOException { - Logger logger = Logger.getLogger(getClass().getName()); - logger.info("Loading WAVE file."); - - RiffInputStream input = new RiffInputStream(in); - - // Header. - input.checkBytes("RIFF"); - logger.info("Read RIFF"); - @SuppressWarnings("unused") - int chunkSize = (int)input.readDWord(); - input.checkBytes("WAVE"); - - // Sub-chunk 1. - input.checkBytes("fmt "); - int subChunk1Size = (int)input.readDWord(); - if (subChunk1Size != 16) { - throw new IOException("Format is not PCM."); - } - int audioFormat = input.readWord(); - if (audioFormat != 1) { - throw new IOException("Unsupported compression scheme: " + audioFormat); - } - numChannels_ = input.readWord(); - if (numChannels_ != 1 && numChannels_ != 2) { - throw new IOException("Unsupported number of channels: " + numChannels_); - } - sampleRateInHz_ = (int)input.readDWord(); - @SuppressWarnings("unused") - int byteRate = (int)input.readDWord(); - @SuppressWarnings("unused") - int blockAlign = input.readWord(); - int bitsPerSample = input.readWord(); - if (bitsPerSample != 8 && bitsPerSample != 16) { - throw new IOException("Unsupported bits per sample: " + bitsPerSample); - } - int bytesPerSample = bitsPerSample / 8; - - // Sub-chunk 2. - input.checkBytes("data"); - int subChunk2Size = (int)input.readDWord(); - - // Actual data. - int numSamples = subChunk2Size / (numChannels_ * bytesPerSample); - leftChannel_ = new double[numSamples]; - rightChannel_ = new double[numSamples]; - for (int i = 0; i < numSamples; ++i) { - switch (bitsPerSample) { - case 8: - leftChannel_[i] = input.readChar() / 128.0; - break; - case 16: - leftChannel_[i] = input.readShort() / 32768.0; - break; - } - if (numChannels_ == 2) { - switch (bitsPerSample) { - case 8: - rightChannel_[i] = input.readChar() / 128.0; - break; - case 16: - rightChannel_[i] = input.readShort() / 32768.0; - break; - } - } else { - rightChannel_[i] = leftChannel_[i]; - } - } - - input.close(); - } - - /** - * Returns the sample rate of the wave file. - */ - public int getSampleRateInHz() { - return sampleRateInHz_; - } - - /** - * Returns the number of samples in the wave file. - */ - public int getSize() { - return leftChannel_.length; - } - - /** - * Returns the nth sample from the left channel of the wave file. - * If it's a mono file, returns the one sample. - */ - public double getLeftSample(int i) { - return leftChannel_[i]; - } - - /** - * Returns the nth sample from the right channel of the wave file. - * If it's a mono file, returns the one sample. - */ - public double getRightSample(int i) { - return rightChannel_[i]; - } - - /** - * Returns the nth sample from the wave file. - * If it's a mono file, returns the one sample. It it's stereo, returns the average. - */ - public double getMonoSample(int i) { - return (leftChannel_[i] + rightChannel_[i]) / 2; - } - - // The number of channels in the file. - private int numChannels_; - - // The sample rate of the file. - private int sampleRateInHz_; - - // The samples in the file. - private double[] leftChannel_; - private double[] rightChannel_; -} diff --git a/core/src/com/levien/synthesizer/core/wave/WaveWriter.java b/core/src/com/levien/synthesizer/core/wave/WaveWriter.java deleted file mode 100644 index b490889..0000000 --- a/core/src/com/levien/synthesizer/core/wave/WaveWriter.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.wave; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * WaveWriter is a class for writing sampled audio data to an output stream as a wave file. - * To use it, call startRecording. Then call writeSample until it returns false. Then call close. - * @see WaveAdapter - */ -public class WaveWriter { - /** - * Creates a new WaveWriter with the given parameters. - * @param sampleRate - The sample rate in Hz. - * @param bitsPerSample - The size of each sample. Should be 8 or 16. - * 8-bit is assumed to be unsigned. 16-bit is assumed to be signed. - */ - public WaveWriter(int sampleRate, int bitsPerSample) { - sampleRate_ = sampleRate; - bitsPerSample_ = bitsPerSample; - if (bitsPerSample_ != 8 && bitsPerSample_ != 16) { - throw new RuntimeException( - "Unacceptable bits per sample: " + bitsPerSample_ + ". Try 8 or 16."); - } - samples_ = 0; - output_ = null; - } - - /** - * Initializes the wave file and writes its header. - * @param seconds - How many seconds of recording to do. - * @param output - The stream to write the wave file to. - * @throws IOException - On any kind of write error. - */ - public void startRecording(double seconds, OutputStream output) throws IOException { - if (output_ != null) { - close(); - } - - samples_ = (int)Math.round(sampleRate_ * seconds); - try { - output_ = output; - - writeBytes("RIFF", output_); - writeLittle32(chunkSize(samples_), output_); - writeBytes("WAVE", output_); - - // Sub-chunk 1 - writeBytes("fmt ", output_); - writeLittle32(16, output_); - writeLittle16(1, output_); - writeLittle16(numChannels(), output_); - writeLittle32(sampleRate_, output_); - writeLittle32(byteRate(), output_); - writeLittle16(blockAlign(), output_); - writeLittle16(bitsPerSample(), output_); - - // Sub-chunk 2 - writeBytes("data", output_); - writeLittle32(subChunk2Size(samples_), output_); - } catch (IOException e) { - if (output_ != null) { - output_.close(); - } - output_ = null; - samples_ = 0; - throw e; - } - } - - /** - * Writes one sample of audio data to the file. Closes the stream when the file is full. - * @param sample - The value to output, expected to be in the range [-1, 1]. - * @return False when the sample can't be written because the file is full. True otherwise. - * @throws IOException - On any kind of write error. - */ - public boolean writeSample(double sample) throws IOException { - if (samples_ == 0) { - return false; - } - // Clamp values out of range. - if (sample < -1.0) { - sample = -1.0; - } - if (sample > 1.0) { - sample = 1.0; - } - try { - if (bitsPerSample() == 16) { - short shortSample = (short)(32767 * sample); - writeLittle16(shortSample, output_); - } else if (bitsPerSample() == 8) { - writeByte((int)(255 * sample + 127.5), output_); - } - --samples_; - if (samples_ == 0) { - output_.close(); - } - } catch (IOException e) { - if (output_ != null) { - output_.close(); - output_ = null; - } - samples_ = 0; - throw e; - } - return true; - } - - /** - * Pads the file until it is the pre-specified length, and then closes the stream. - */ - public void close() throws IOException { - while (samples_ > 0) { - writeSample(0.0); - } - output_.close(); - } - - /** - * Returns the chunk size for the wave header. - */ - private int chunkSize(int samples) { - return 36 + subChunk2Size(samples); - } - - /** - * Returns the second sub-chunk size for the wave header. - */ - private int subChunk2Size(int samples) { - return samples * numChannels() * bitsPerSample() / 8; - } - - /** - * Returns the number of channels for the wave file. - */ - private int numChannels() { - return 1; - } - - /** - * Returns the bytes per second of the wave file. - */ - private int byteRate() { - return sampleRate_ * numChannels() * bitsPerSample() / 8; - } - - /** - * Returns the block-align parameter for the wave header. - */ - private int blockAlign() { - return numChannels() * bitsPerSample() / 8; - } - - /** - * Returns the bits per sample used when creating the WaveWriter. - */ - private int bitsPerSample() { - return bitsPerSample_; - } - - /** - * Writes one byte to an output stream. - * @param data - The unsigned byte to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeByte(int data, OutputStream output) throws IOException { - output.write(data); - } - - /** - * Writes a String to an output stream as bytes. - * @param data - The bytes to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeBytes(String data, OutputStream output) throws IOException { - output.write(data.getBytes()); - } - - /** - * Writes one dword (32 bits) to an output stream in little-endian format. - * @param data - The dword to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeLittle32(int data, OutputStream output) throws IOException { - output.write(data & 0xFF); - output.write((data >> 8) & 0xFF); - output.write((data >> 16) & 0xFF); - output.write((data >> 24) & 0xFF); - } - - /** - * Writes one word (16 bits) to an output stream in little-endian format. - * @param data - The word to write. - * @param output - The stream to write to. - * @throws IOException - On any kind of write error. - */ - private static void writeLittle16(int data, OutputStream output) throws IOException { - output.write(data & 0xFF); - output.write((data >> 8) & 0xFF); - } - - // The number of samples left to write until the file is full. - private int samples_; - // The sample rate in Hz. - private int sampleRate_; - // The number of bits per output sample. Should be 8 or 16. - private int bitsPerSample_; - // The output stream to write the wave file to. - private OutputStream output_; -} diff --git a/cpp/README b/cpp/README deleted file mode 100644 index e715643..0000000 --- a/cpp/README +++ /dev/null @@ -1,24 +0,0 @@ -README for C++ codebase - -The C++ codebase will eventually be the primary sound generation module -for this app. It's still experimental, and not yet wired up to the Android -parts, but can be used to make sound. The best way is to use the simple -test app for the Mac. - -To build, edit src/SynthApp/SynthMain.mm to change the path to ROM1A.SYX -to the actual path. These patches can be downloaded from: - -http://www.abdn.ac.uk/~mth192/dx7/dx7patch.zip - -Also change the "KeyRig 49" string to match the actual USB name of your -MIDI controller. Then "open src/SynthApp.xcodeproj", then do "Build and -Run". - -The File Open menu command is hooked up as well and will load SYX format -DX7 patch files (32 patches per file). Send program change midi events -with the first 32 program numbers. - -The xcodeproj files are checked into the repo, but they are autogenerated -from .gyp files, which are the authoritative masters. To modify the -build, change the .gyp file, then run "gyp" in this dir. For changes -to the core, also change ../../android/jni/Android.mk . \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..1d3591c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659 GIT binary patch literal 53636 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ⅅ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 H-+%o-(+5aQ literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..122a0dc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/j2se/.classpath b/j2se/.classpath deleted file mode 100644 index a3d94e2..0000000 --- a/j2se/.classpath +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/j2se/.externalToolBuilders/Proto Builder.launch b/j2se/.externalToolBuilders/Proto Builder.launch deleted file mode 100644 index 68b4dfa..0000000 --- a/j2se/.externalToolBuilders/Proto Builder.launch +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/j2se/.gitignore b/j2se/.gitignore deleted file mode 100644 index 6c3adb3..0000000 --- a/j2se/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/** -j2se.jar \ No newline at end of file diff --git a/j2se/.project b/j2se/.project deleted file mode 100644 index 8cc21b9..0000000 --- a/j2se/.project +++ /dev/null @@ -1,49 +0,0 @@ - - - MusicSynthesizerJ2SE - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - auto,full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/Proto Builder.launch - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - - - core - 2 - PARENT-1-PROJECT_LOC/core/src - - - core-gen - 2 - PARENT-1-PROJECT_LOC/core/gen - - - core-lib - 2 - PARENT-1-PROJECT_LOC/core/lib - - - test - 2 - PARENT-1-PROJECT_LOC/test/src - - - diff --git a/j2se/build.xml b/j2se/build.xml deleted file mode 100644 index 6615363..0000000 --- a/j2se/build.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/j2se/src/com/levien/synthesizer/j2se/Midi.java b/j2se/src/com/levien/synthesizer/j2se/Midi.java deleted file mode 100755 index ed43988..0000000 --- a/j2se/src/com/levien/synthesizer/j2se/Midi.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.j2se; - -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; - -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiMessage; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; - -/** - * Midi keeps track of the Midi devices connected to the system, and their control bindings. - */ -public class Midi { - /** - * Creates a new Midi system for the given synthesizer. - */ - public Midi(MultiChannelSynthesizer synth) { - synthesizer_ = synth; - binders_ = new ArrayList(); - logger_ = Logger.getLogger(getClass().getName()); - } - - /** - * Prints out a list of all of the Midi devices connected to the system. - */ - public void printDevices() { - StringBuilder debug = new StringBuilder("\n"); - MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); - for (int i = 0; i < devices.length; ++i) { - debug.append("Device " + i + ": " + - devices[i].getName() + ": " + devices[i].getDescription() + "\n"); - debug.append(" " + devices[i].getVendor()); - debug.append(" " + devices[i].getVersion()); - try { - MidiDevice device = MidiSystem.getMidiDevice(devices[i]); - debug.append(" receivers: " + device.getMaxReceivers() + - " transmitters: " + device.getMaxTransmitters() + "\n"); - } catch (MidiUnavailableException mue) { - debug.append(" Unavailable!"); - } - } - logger_.info(debug.toString()); - } - - /** - * Returns the Midi device at the specified index. - */ - private MidiDevice getDevice(int index) { - MidiDevice.Info[] devices = MidiSystem.getMidiDeviceInfo(); - if (index < 0 || index >= devices.length) { - return null; - } - try { - return MidiSystem.getMidiDevice(devices[index]); - } catch (MidiUnavailableException mue) { - return null; - } - } - - /** - * Connects the synthesizer to the controls of the Midi device at the specified index. - */ - public void bindDevice(int index) { - MidiDevice device = getDevice(index); - if (device != null) { - binders_.add(new MidiDeviceBinder(device, synthesizer_)); - } else { - logger_.severe("Unable to get device with index " + index + "."); - } - } - - /** - * Stops the connection to all Midi devices. - */ - public void stop() { - for (MidiDeviceBinder binder : binders_) { - binder.stop(); - } - } - - /** - * Sends the given message to all Midi devices. - */ - public void send(MidiMessage message) { - for (MidiDeviceBinder binder : binders_) { - binder.send(message); - } - } - - // The synthesizer to bind controls to. - private MultiChannelSynthesizer synthesizer_; - - // The list of Midi device bindings. - private List binders_; - - private Logger logger_; -} diff --git a/j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java b/j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java deleted file mode 100644 index c69fc94..0000000 --- a/j2se/src/com/levien/synthesizer/j2se/MidiDeviceBinder.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.j2se; - -import com.levien.synthesizer.core.midi.MessageInputProcessor; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiMessage; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Receiver; -import javax.sound.midi.Transmitter; - -/** - * MidiDeviceBinder manages the connection between a MidiDevice and its associated BindingSet. - */ -public class MidiDeviceBinder { - /** - * MidiDeviceBinder manages the connection between a MidiDevice and its associated BindingSet. - * @param device - The device to connect the BindingSet to. - * @param synth - The synthesizer to bind to. - */ - public MidiDeviceBinder(MidiDevice device, MultiChannelSynthesizer synth) { - device_ = device; - synth_ = synth; - midiIn_ = null; - logger_ = Logger.getLogger(getClass().getName()); - try { - if (midiIn_ == null && device_.getMaxTransmitters() != 0) { - if (!device_.isOpen()) { - device_.open(); - } - midiIn_ = device_.getTransmitter(); - midiIn_.setReceiver(new Receiver() { - public void send(MidiMessage message, long time) { - ByteArrayInputStream stream = new ByteArrayInputStream( - message.getMessage(), 0, message.getLength()); - try { - MessageInputProcessor.process(stream, 0, synth_); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Error processing Midi message.", e); - } - } - public void close() { - logger_.info("Closing MIDI receiver."); - } - }); - } - if (midiOut_ == null && device_.getMaxReceivers() != 0) { - if (!device_.isOpen()) { - device_.open(); - } - midiOut_ = device_.getReceiver(); - } - } catch (MidiUnavailableException mue) { - logger_.severe("Unable to open MIDI device."); - midiIn_ = null; - midiOut_ = null; - } - } - - /** - * Closes the Midi device. - */ - public void stop() { - logger_.info("Closing MIDI device."); - if (device_ != null) { - device_.close(); - } - if (midiIn_ != null) { - midiIn_.close(); - midiIn_ = null; - } - if (midiOut_ != null) { - midiOut_.close(); - midiOut_ = null; - } - } - - /** - * Sends the given message to the Midi device. - */ - public void send(MidiMessage message) { - if (midiOut_ != null) { - midiOut_.send(message, System.currentTimeMillis()); - } - } - - // The synthesizer to bind to. - private MultiChannelSynthesizer synth_; - - // The Midi device to bind to. - private MidiDevice device_; - private Transmitter midiIn_; - private Receiver midiOut_; - - private Logger logger_; -} diff --git a/j2se/src/com/levien/synthesizer/j2se/Perform.java b/j2se/src/com/levien/synthesizer/j2se/Perform.java deleted file mode 100644 index cf15417..0000000 --- a/j2se/src/com/levien/synthesizer/j2se/Perform.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.j2se; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.sound.midi.MidiMessage; - -import com.levien.synthesizer.core.midi.MessageOutputProcessor; -import com.levien.synthesizer.core.midi.MidiFilePlayer; -import com.levien.synthesizer.core.midi.MidiListener; -import com.levien.synthesizer.core.model.composite.MultiChannelSynthesizer; -import com.levien.synthesizer.core.soundfont.SoundFontReader; -import com.levien.synthesizer.core.wave.WaveAdapter; - -/** - * Perform is a simple little command-line app for debugging the synthesizer. - */ -public class Perform { - /** - * Loads presets from the given file into the synthesizer. - * @param filename - The path to the file. - * @param synth - The synthesizer to load the presets into. - */ - public void loadPresetsFile(String filename, MultiChannelSynthesizer synth) { - InputStream input; - try { - input = new BufferedInputStream(new FileInputStream(new File(filename))); - try { - synth.loadLibraryFromText(input); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to read from input stream.", e); - } - } catch (FileNotFoundException e) { - logger_.severe("Unable to open file " + filename + "."); - } - } - - /** - * This is dumb. - */ - private static class DummyMidiMessage extends MidiMessage { - protected DummyMidiMessage(byte[] data) { - super(data); - } - - @Override - public Object clone() { - return new DummyMidiMessage(getMessage()); - } - } - - /** - * The real main() function for this class. Creates a synthesizer and runs a read-eval-print loop - * to take input from the user and control the synthesizer. - */ - public Perform() { - logger_ = Logger.getLogger(getClass().getName()); - double sampleRateInHz = 11025; - - SoundFontReader samples = null; - try { - samples = new SoundFontReader(new FileInputStream(new File("android/res/raw/drums.sf2"))); - } catch (IOException e) { - samples = null; - e.printStackTrace(); - } - - MultiChannelSynthesizer synth = new MultiChannelSynthesizer(16, 5, sampleRateInHz, samples); - WaveAdapter writer = new WaveAdapter((int)sampleRateInHz, 16, synth); - - // Load some arbitrary presets to make playing midis more interesting. - loadPresetsFile("android/res/raw/presets.txt", synth); - synth.setPreset(0, 0); - synth.setPreset(1, 1); - synth.setPreset(2, 3); - synth.setPreset(3, 0); - synth.setPreset(4, 1); - synth.setPreset(5, 1); - synth.setPreset(6, 0); - synth.setPreset(7, 0); - synth.setPreset(8, 0); - synth.setPreset(9, 5); - synth.setPreset(10, 2); - synth.setPreset(11, 0); - synth.setPreset(12, 0); - synth.setPreset(13, 0); - synth.setPreset(14, 0); - synth.setPreset(15, 0); - - final Midi midi = new Midi(synth); - List listeners = new ArrayList(); - listeners.add(synth); - listeners.add(new MessageOutputProcessor() { - @Override - protected void onMessage(byte[] message) { - midi.send(new DummyMidiMessage(message)); - } - }); - MidiFilePlayer player = new MidiFilePlayer(listeners); - - SynthesizerThread thread = new SynthesizerThread(writer, (int)sampleRateInHz); - thread.play(); - - boolean running = true; - BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); - while (running) { - String line = null; - System.out.print("\n[synth]$ "); - System.out.flush(); - try { - line = stdin.readLine(); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Error reading line.", e); - running = false; - } - if (line == null) { - running = false; - } else if (line.trim().equals("")) { - // Do nothing. - } else if (line.equals("exit") || line.equals("quit")) { - running = false; - } else if (line.equals("ls")) { - midi.printDevices(); - } else if (line.equals("ls midi")) { - midi.printDevices(); - } else if (line.equals("ls presets")) { - ArrayList names = new ArrayList(); - synth.getPresetNames(names); - StringBuilder output = new StringBuilder(""); - for (String name : names) { - output.append("\n" + name); - } - logger_.info(output.toString()); - } else if (line.startsWith("bind ")) { - String bindArgs = line.substring("bind ".length()); - try { - int index = Integer.parseInt(bindArgs); - midi.bindDevice(index); - } catch (NumberFormatException e) { - logger_.severe("Invalid number format \"" + bindArgs + "\"."); - } - } else if (line.startsWith("presets ")) { - String filename = line.substring("presets ".length()); - loadPresetsFile(filename, synth); - } else if (line.startsWith("play ")) { - String filename = line.substring("play ".length()); - try { - player.play(new FileInputStream(filename)); - } catch (FileNotFoundException e) { - logger_.log(Level.SEVERE, "Unable to open midi file.", e); - } catch (IOException e) { - logger_.log(Level.SEVERE, "Unable to read midi file.", e); - } - } else if (line.startsWith("record ")) { - String[] args = line.split(" +", 3); - if (args.length != 3) { - logger_.severe("Usage: record

YsZq(Mlan0|cQ4s6cpaq4`FPUc@gsSxE=qGmBP` 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 diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/AdsrEnvelopeTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/AdsrEnvelopeTest.java deleted file mode 100755 index 7ddecea..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/AdsrEnvelopeTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import junit.framework.TestCase; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.AdsrEnvelope; - -public class AdsrEnvelopeTest extends TestCase { - final private static double TOLERANCE = 0.0001; - - public void setUp() { - time_ = new SynthesisTime(); - time_.setSampleRate(44100.0); // 44.1 kHz sampling. - - // Set some arbitrary but realistic time parameters. - attack_ = new SynthesizerInput(0.1, 0.0, 1.0); - decay_ = new SynthesizerInput(0.2, 0.0, 1.0); - sustain_ = new SynthesizerInput(0.8, 0.0, 1.0); - release_ = new SynthesizerInput(0.3, 0.0, 1.0); - - adsr_ = new AdsrEnvelope(attack_, decay_, sustain_, release_); - } - - /** - * Checks that the attack matches the slope of its parameter. - * @param duration - How long to check the slope. - */ - private void checkA(double duration) { - double startLevel = adsr_.getValue(time_); - double start = time_.getAbsoluteTime(); - double finish = start + duration; - double slope = 1.0 / attack_.getSynthesizerInputValue(); - for (; time_.getAbsoluteTime() <= finish; time_.advance()) { - double x = time_.getAbsoluteTime() - start; - double level = startLevel + x * slope; - assertEquals(level, adsr_.getValue(time_), TOLERANCE); - } - } - - /** - * Checks that the decay matches the slope of its parameter. - * @param duration - How long to check the slope. - */ - private void checkD(double duration) { - double startLevel = adsr_.getValue(time_); - double start = time_.getAbsoluteTime(); - double finish = start + duration; - double slope = (sustain_.getSynthesizerInputValue() - 1.0) / decay_.getSynthesizerInputValue(); - for (; time_.getAbsoluteTime() <= finish; time_.advance()) { - double x = time_.getAbsoluteTime() - start; - double level = startLevel + x * slope; - assertEquals(level, adsr_.getValue(time_), TOLERANCE); - } - } - - /** - * Checks that the enveleope's output is sustain. - * @param duration - How long to check the output. - */ - private void checkS(double duration) { - double start = time_.getAbsoluteTime(); - double finish = start + duration; - for (; time_.getAbsoluteTime() <= finish; time_.advance()) { - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - } - } - - /** - * Checks that the release matches the slope of its parameter. - * @param duration - How long to check the slope. - */ - private void checkR(double duration) { - double startLevel = adsr_.getValue(time_); - double start = time_.getAbsoluteTime(); - double finish = start + duration; - double slope = (0.0 - sustain_.getSynthesizerInputValue()) / - release_.getSynthesizerInputValue(); - for (; time_.getAbsoluteTime() <= finish; time_.advance()) { - double x = time_.getAbsoluteTime() - start; - double level = startLevel + x * slope; - if (level < 0.0) { - level = 0.0; - } - assertEquals(level, adsr_.getValue(time_), TOLERANCE); - } - } - - public void testTurnOffDuringAttack() { - double time_On = 0.05; - adsr_.turnOn(true); - checkA(time_On); - adsr_.turnOff(); - assertEquals(time_On / attack_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(release_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testTurnOffDuringDecay() { - double time_On = 0.2; - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkA(attack_.getSynthesizerInputValue()); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(time_On - attack_.getSynthesizerInputValue()); - adsr_.turnOff(); - checkR(release_.getSynthesizerInputValue() / sustain_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testTurnOffDuringSustain() { - double sustainDuration = 0.4; - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkA(attack_.getSynthesizerInputValue()); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration); - adsr_.turnOff(); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(release_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testTriggerDuringAttack() { - double attack1Duration = 0.05; - double sustainDuration = 0.4; - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkA(attack1Duration); - adsr_.turnOn(true); - checkA(attack_.getSynthesizerInputValue() - time_.getAbsoluteTime()); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration); - adsr_.turnOff(); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(release_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testTriggerDuringDecay() { - double decayDuration = 0.15; - double sustainDuration = 0.5; - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkA(attack_.getSynthesizerInputValue()); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decayDuration); - adsr_.turnOn(true); - checkA(attack_.getSynthesizerInputValue() * (1.0 - adsr_.getValue(time_))); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration); - adsr_.turnOff(); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(release_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testTriggerDuringSustain() { - double sustainDuration1 = 0.5; - double sustainDuration2 = 1.0; - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkA(attack_.getSynthesizerInputValue()); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration1); - adsr_.turnOn(true); - checkA(attack_.getSynthesizerInputValue() * (1.0 - sustain_.getSynthesizerInputValue())); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration2); - adsr_.turnOff(); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(release_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testTriggerDuringRelease() { - double releaseDuration1 = 0.1; - double sustainDuration1 = 0.5; - double sustainDuration2 = 1.0; - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkA(attack_.getSynthesizerInputValue()); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration1); - adsr_.turnOff(); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(releaseDuration1); - adsr_.turnOn(true); - checkA(attack_.getSynthesizerInputValue() * (1.0 - adsr_.getValue(time_))); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration2); - adsr_.turnOff(); - assertEquals(sustain_.getSynthesizerInputValue(), adsr_.getValue(time_), TOLERANCE); - checkR(release_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - public void testZeroAttack() { - double sustainDuration = 5.0; - attack_.setValue(0.0); - sustain_.setValue(0.0); - release_.setValue(0.0); - - adsr_.turnOn(true); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - time_.advance(); - assertEquals(1.0, adsr_.getValue(time_), TOLERANCE); - checkD(decay_.getSynthesizerInputValue()); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - checkS(sustainDuration); - adsr_.turnOff(); - assertEquals(0.0, adsr_.getValue(time_), TOLERANCE); - } - - private AdsrEnvelope adsr_; - private SynthesisTime time_; - private SynthesizerInput attack_; - private SynthesizerInput decay_; - private SynthesizerInput sustain_; - private SynthesizerInput release_; -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/AmplifierTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/AmplifierTest.java deleted file mode 100755 index 67b4fb9..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/AmplifierTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Amplifier; - -import junit.framework.TestCase; - -public class AmplifierTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void testAmp() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - SignalProvider signal = new SynthesizerInput(3.0, 0.0, 1.0); - SignalProvider gain = new SynthesizerInput(4.5, 0.0, 1.0); - - Amplifier amp = new Amplifier(signal, gain); - - assertEquals(13.5, amp.getValue(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/DelayTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/DelayTest.java deleted file mode 100755 index 065133e..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/DelayTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Delay; - -import junit.framework.TestCase; - -public class DelayTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void testBasic() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - SynthesizerInput signal = new SynthesizerInput(1.0, 0.0, 1.0); - SynthesizerInput mix = new SynthesizerInput(0.5, 0.0, 1.0); - Delay delay = new Delay(signal, mix); - - // Regular mode. - - signal.setValue(3.0); - assertEquals(1.5, delay.getValue(time), TOLERANCE); - signal.setValue(1.0); - assertEquals(1.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.5, delay.getValue(time), TOLERANCE); - signal.setValue(4.0); - assertEquals(0.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(2.0, delay.getValue(time), TOLERANCE); - signal.setValue(1.0); - assertEquals(2.0, delay.getValue(time), TOLERANCE); - time.advance(); - - // Record mode. - - delay.startRecording(); - signal.setValue(3.0); - assertEquals(1.5, delay.getValue(time), TOLERANCE); - signal.setValue(1.0); - assertEquals(1.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.5, delay.getValue(time), TOLERANCE); - signal.setValue(4.0); - assertEquals(0.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(2.0, delay.getValue(time), TOLERANCE); - signal.setValue(1.0); - assertEquals(2.0, delay.getValue(time), TOLERANCE); - time.advance(); - - // Play mode. - - delay.startPlaying(); - signal.setValue(6.0); - assertEquals(3.0 + 1.5, delay.getValue(time), TOLERANCE); - assertEquals(3.0 + 1.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.0 + 0.5, delay.getValue(time), TOLERANCE); - assertEquals(3.0 + 0.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.0 + 2.0, delay.getValue(time), TOLERANCE); - assertEquals(3.0 + 2.0, delay.getValue(time), TOLERANCE); - time.advance(); - - // Looped. - - signal.setValue(7.0); - assertEquals(3.5 + 1.5, delay.getValue(time), TOLERANCE); - assertEquals(3.5 + 1.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.5 + 0.5, delay.getValue(time), TOLERANCE); - assertEquals(3.5 + 0.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.5 + 2.0, delay.getValue(time), TOLERANCE); - assertEquals(3.5 + 2.0, delay.getValue(time), TOLERANCE); - time.advance(); - - // Regular mode. - - delay.stopPlaying(); - assertEquals(3.5, delay.getValue(time), TOLERANCE); - assertEquals(3.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.5, delay.getValue(time), TOLERANCE); - signal.setValue(9.0); - assertEquals(3.5, delay.getValue(time), TOLERANCE); - time.advance(); - assertEquals(4.5, delay.getValue(time), TOLERANCE); - assertEquals(4.5, delay.getValue(time), TOLERANCE); - time.advance(); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/EchoTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/EchoTest.java deleted file mode 100755 index 7ecdf70..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/EchoTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Echo; - -import junit.framework.TestCase; - -public class EchoTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void testBasic() { - // Test the echo effect sampling at 10 Hz with a delay of 0.5 seconds. - // This means input should repeat every 5 samples. - - final double MIX = 0.6; - final double DELAY_IN_SECONDS = 0.5; - final double SAMPLE_RATE = 10.0; - final int DELAY_IN_SAMPLES = (int)Math.round(DELAY_IN_SECONDS * SAMPLE_RATE); - - assertTrue(DELAY_IN_SAMPLES > 0); - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - SynthesizerInput signal = new SynthesizerInput(0.0, 0.0, 1.0); - SynthesizerInput mix = new SynthesizerInput(MIX, 0.0, 1.0); - SynthesizerInput delay = new SynthesizerInput(DELAY_IN_SECONDS, 0.0, 1.0); - Echo echo = new Echo(signal, mix, delay, SAMPLE_RATE); - - // It's only really interesting when input is longer than DELAY_IN_SAMPLES. - // It's also good for its length to not be a multiple of DELAY_IN_SAMPLES. - double[] input = { 0.3, 0.1, 0.4, 0.1, 0.5, 0.9, 0.2, 0.6 }; - - for (int i = 0; i < 1000; ++i) { - if (i < input.length) { - signal.setValue(input[i]); - } else { - signal.setValue(0.0); - } - - double expected = 0.0; - // Loop backwards through time and sum up the residuals. - for (int j = 0; j <= i / DELAY_IN_SAMPLES; ++j) { - int index = i - j * DELAY_IN_SAMPLES; - if (index < input.length) { - expected += (input[index] * (1.0 - MIX) * Math.pow(MIX, j)); - } - } - - assertEquals(expected, echo.getValue(time), TOLERANCE); - time.advance(); - } - } -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/GlideTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/GlideTest.java deleted file mode 100644 index d0801d5..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/GlideTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Glide; - -import junit.framework.TestCase; - -public class GlideTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void setUp() { - time_ = new SynthesisTime(); - time_.setSampleRate(5.0); // 5 Hz. - - // Just set the inputs to arbitrary values. - source_ = new SynthesizerInput(3.0, 0.0, 1.0); - rate_ = new SynthesizerInput(0.0, 0.0, 1.0); - - glide_ = new Glide(source_, rate_); - } - - public void testOff() { - rate_.setValue(0.0); - - source_.setValue(3.0); - assertEquals(3.0, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - source_.setValue(4.0); - assertEquals(4.0, glide_.getLogFrequency(time_), TOLERANCE); - } - - public void testBasic() { - source_.setValue(3.0); - assertEquals(3.0, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - - rate_.setValue(1.0); - assertEquals(3.0, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - - source_.setValue(4.0); - assertEquals(3.0, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - assertEquals(3.2, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - assertEquals(3.4, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - assertEquals(3.6, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - assertEquals(3.8, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - assertEquals(4.0, glide_.getLogFrequency(time_), TOLERANCE); - time_.advance(); - assertEquals(4.0, glide_.getLogFrequency(time_), TOLERANCE); - } - - private SynthesisTime time_; - private SynthesizerInput source_; - private SynthesizerInput rate_; - private Glide glide_; -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/MixerTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/MixerTest.java deleted file mode 100755 index d817ffb..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/MixerTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Mixer; - -import junit.framework.TestCase; - -public class MixerTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void setUp() { - time_ = new SynthesisTime(); - time_.setSampleRate(44100.0); - - // Just set the inputs to arbitrary values. - signal1_ = new SynthesizerInput(3.0, 0.0, 1.0); - signal2_ = new SynthesizerInput(4.5, 0.0, 1.0); - balance_ = new SynthesizerInput(0.0, 0.0, 1.0); - - mixer_ = new Mixer(signal1_, signal2_, balance_); - } - - public void testChannel1() { - balance_.setValue(0.0); - assertEquals(3.0, mixer_.getValue(time_), TOLERANCE); - } - - public void testChannel2() { - balance_.setValue(1.0); - assertEquals(4.5, mixer_.getValue(time_), TOLERANCE); - } - - public void testMix() { - balance_.setValue(0.5); - assertEquals(3.75, mixer_.getValue(time_), TOLERANCE); - } - - private SynthesisTime time_; - private SynthesizerInput signal1_; - private SynthesizerInput signal2_; - private SynthesizerInput balance_; - private Mixer mixer_; -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/TremoloTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/TremoloTest.java deleted file mode 100644 index a17597f..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/TremoloTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Tremolo; - -import junit.framework.TestCase; - -public class TremoloTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void setUp() { - time_ = new SynthesisTime(); - time_.setSampleRate(5.0); // 5 Hz. - - // Just set the inputs to arbitrary values. - modulator_ = new SynthesizerInput(3.0, 0.0, 1.0); - depth_ = new SynthesizerInput(0.0, 0.0, 1.0); - - tremolo_ = new Tremolo(modulator_, depth_); - } - - public void testOff() { - depth_.setValue(0.0); - - modulator_.setValue(0.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.5); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(1.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.5); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-0.5); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-1.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-0.5); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - } - - public void testHalf() { - depth_.setValue(0.5); - - modulator_.setValue(0.0); - assertEquals(0.75, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.5); - assertEquals(0.875, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(1.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.5); - assertEquals(0.875, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.0); - assertEquals(0.75, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-0.5); - assertEquals(0.625, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-1.0); - assertEquals(0.5, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-0.5); - assertEquals(0.625, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.0); - assertEquals(0.75, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - } - - public void testFull() { - depth_.setValue(1.0); - - modulator_.setValue(0.0); - assertEquals(0.5, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.5); - assertEquals(0.75, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(1.0); - assertEquals(1.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.5); - assertEquals(0.75, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.0); - assertEquals(0.5, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-0.5); - assertEquals(0.25, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-1.0); - assertEquals(0.0, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(-0.5); - assertEquals(0.25, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - - modulator_.setValue(0.0); - assertEquals(0.5, tremolo_.getValue(time_), TOLERANCE); - time_.advance(); - } - - private SynthesisTime time_; - private SynthesizerInput modulator_; - private SynthesizerInput depth_; - private Tremolo tremolo_; -} diff --git a/test/src/com/levien/synthesizer/core/model/modules/test/TunerTest.java b/test/src/com/levien/synthesizer/core/model/modules/test/TunerTest.java deleted file mode 100644 index 75608ca..0000000 --- a/test/src/com/levien/synthesizer/core/model/modules/test/TunerTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.modules.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.modules.Tuner; -import com.levien.synthesizer.core.music.Note; - -import junit.framework.TestCase; - -public class TunerTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void setUp() { - time_ = new SynthesisTime(); - time_.setSampleRate(5.0); // 5 Hz. - - // Just set the inputs to arbitrary values. - source_ = new SynthesizerInput(3.0, 0.0, 1.0); - shift_ = new SynthesizerInput(0.0, 0.0, 1.0); - - tuner_ = new Tuner(source_, shift_); - } - - public void testOff() { - source_.setValue(Note.computeLog12TET(Note.C, 3)); - shift_.setValue(0.0); - assertEquals(Note.computeLog12TET(Note.C, 3), tuner_.getLogFrequency(time_), TOLERANCE); - } - - public void testHalfStepUp() { - source_.setValue(Note.computeLog12TET(Note.C, 3)); - shift_.setValue(Note.HALF_STEP); - assertEquals(Note.computeLog12TET(Note.C_SHARP, 3), tuner_.getLogFrequency(time_), TOLERANCE); - } - - public void testWholeStepUp() { - source_.setValue(Note.computeLog12TET(Note.C, 3)); - shift_.setValue(Note.WHOLE_STEP); - assertEquals(Note.computeLog12TET(Note.D, 3), tuner_.getLogFrequency(time_), TOLERANCE); - } - - public void testHalfStepDown() { - source_.setValue(Note.computeLog12TET(Note.C, 3)); - shift_.setValue(-1 * Note.HALF_STEP); - assertEquals(Note.computeLog12TET(Note.B, 2), tuner_.getLogFrequency(time_), TOLERANCE); - } - - public void testWholeStepDown() { - source_.setValue(Note.computeLog12TET(Note.C, 3)); - shift_.setValue(-1 * Note.WHOLE_STEP); - assertEquals(Note.computeLog12TET(Note.B_FLAT, 2), tuner_.getLogFrequency(time_), TOLERANCE); - } - - private SynthesisTime time_; - private SynthesizerInput source_; - private SynthesizerInput shift_; - private Tuner tuner_; -} diff --git a/test/src/com/levien/synthesizer/core/model/oscillator/test/OscillatorTest.java b/test/src/com/levien/synthesizer/core/model/oscillator/test/OscillatorTest.java deleted file mode 100755 index 2fc82c6..0000000 --- a/test/src/com/levien/synthesizer/core/model/oscillator/test/OscillatorTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.oscillator.Oscillator; - -import junit.framework.TestCase; - -public class OscillatorTest extends TestCase { - public void testBasic() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - final SynthesizerInput frequency = new SynthesizerInput(440.0, 0.0, 1.0); - Oscillator osc = new Oscillator(frequency) { - public double computeValue(SynthesisTime time) { - assertEquals(frequency, frequency_); - return 0.0; - } - }; - - osc.getValue(time); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/oscillator/test/SawtoothTest.java b/test/src/com/levien/synthesizer/core/model/oscillator/test/SawtoothTest.java deleted file mode 100755 index 466a5d3..0000000 --- a/test/src/com/levien/synthesizer/core/model/oscillator/test/SawtoothTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.oscillator.Sawtooth; - -import junit.framework.TestCase; - -public class SawtoothTest extends TestCase { - final private static double TOLERANCE = 0.0000001; - - public void testBasic() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Sawtooth sawtooth = new Sawtooth(frequency); - - assertEquals(-1.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-2.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-3.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(4.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(2.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0/4.0, sawtooth.getValue(time), TOLERANCE); - } - - public void testFrequencyChange() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Sawtooth sawtooth = new Sawtooth(frequency); - - assertEquals(-1.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-2.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - - // Change the frequency. - frequency.setValue(-1.0); // 1/2 Hz. - - assertEquals(-3.0/4.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - - // The frequency change takes effect here at the end of the cycle. - - assertEquals(8.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(7.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(6.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(5.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(4.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(2.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0/8.0, sawtooth.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0/8.0, sawtooth.getValue(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/oscillator/test/SineTest.java b/test/src/com/levien/synthesizer/core/model/oscillator/test/SineTest.java deleted file mode 100755 index 9d8b083..0000000 --- a/test/src/com/levien/synthesizer/core/model/oscillator/test/SineTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.oscillator.Sine; - -import junit.framework.TestCase; - -public class SineTest extends TestCase { - final private static double TOLERANCE = 0.0000001; - - public void testBasic() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Sine sine = new Sine(frequency); - - assertEquals(0.0, sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0, sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1 * Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1 * Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0, sine.getValue(time), TOLERANCE); - } - - public void testFrequencyChange() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Sine sine = new Sine(frequency); - - assertEquals(0.0, sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, sine.getValue(time), TOLERANCE); - time.advance(); - assertEquals(Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - - // Change the frequency. - frequency.setValue(-1.0); // 1/2 Hz. - - assertEquals(0.0, sine.getValue(time), TOLERANCE); - time.advance(); - time.advance(); - assertEquals(-1.0 * Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - time.advance(); - assertEquals(-1.0, sine.getValue(time), TOLERANCE); - time.advance(); - time.advance(); - assertEquals(-1.0 * Math.cos(Math.PI / 4.0), sine.getValue(time), TOLERANCE); - time.advance(); - time.advance(); - assertEquals(0.0, sine.getValue(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/oscillator/test/SquareTest.java b/test/src/com/levien/synthesizer/core/model/oscillator/test/SquareTest.java deleted file mode 100755 index ca0a6a3..0000000 --- a/test/src/com/levien/synthesizer/core/model/oscillator/test/SquareTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.oscillator.Square; - -import junit.framework.TestCase; - -public class SquareTest extends TestCase { - final private static double TOLERANCE = 0.0000001; - - public void testBasic() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Square square = new Square(frequency); - - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - } - - public void testFrequencyChange() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Square square = new Square(frequency); - - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - - // Change the frequency. - frequency.setValue(-1.0); // 1/2 Hz. - - assertEquals(1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0, square.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0, square.getValue(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/oscillator/test/TriangleTest.java b/test/src/com/levien/synthesizer/core/model/oscillator/test/TriangleTest.java deleted file mode 100755 index f0668f0..0000000 --- a/test/src/com/levien/synthesizer/core/model/oscillator/test/TriangleTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.oscillator.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; -import com.levien.synthesizer.core.model.oscillator.Triangle; - -import junit.framework.TestCase; - -public class TriangleTest extends TestCase { - final private static double TOLERANCE = 0.0000001; - - public void testBasic() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Triangle triangle = new Triangle(frequency); - - assertEquals(1.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-2.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(2.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0/2.0, triangle.getValue(time), TOLERANCE); - } - - public void testFrequencyChange() { - SynthesizerInput frequency = new SynthesizerInput(0.0, 0.0, 1.0); // 1 Hz. - - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(8); // 8 samples per second. - Triangle triangle = new Triangle(frequency); - - assertEquals(1.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - - // Change the frequency. - frequency.setValue(-1.0); // 1/2 Hz. - - assertEquals(-1.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-2.0/2.0, triangle.getValue(time), TOLERANCE); - time.advance(); - - // The frequency change takes effect here at the end of the cycle. - - assertEquals(-3.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-2.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(-1.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(0.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(1.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(2.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(4.0/4.0, triangle.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.0/4.0, triangle.getValue(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/test/CachedFrequencyProviderTest.java b/test/src/com/levien/synthesizer/core/model/test/CachedFrequencyProviderTest.java deleted file mode 100644 index 219f5fa..0000000 --- a/test/src/com/levien/synthesizer/core/model/test/CachedFrequencyProviderTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.test; - -import com.levien.synthesizer.core.model.CachedFrequencyProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -import junit.framework.TestCase; - -public class CachedFrequencyProviderTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - // Make a simple subclass that just increments the output value. - private class MockCachedFrequencyProvider extends CachedFrequencyProvider { - public MockCachedFrequencyProvider() { - counter_ = 0; - } - protected double computeLogFrequency(SynthesisTime time) { - return counter_++; - } - private int counter_; - } - - // Check that the value doesn't change until the time is advanced. - public void testGetValue() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - - MockCachedFrequencyProvider mock = new MockCachedFrequencyProvider(); - - assertEquals(0, mock.getLogFrequency(time), TOLERANCE); - assertEquals(0, mock.getLogFrequency(time), TOLERANCE); - assertEquals(0, mock.getLogFrequency(time), TOLERANCE); - - time.advance(); - - assertEquals(1, mock.getLogFrequency(time), TOLERANCE); - assertEquals(1, mock.getLogFrequency(time), TOLERANCE); - - time.advance(); - - assertEquals(2, mock.getLogFrequency(time), TOLERANCE); - assertEquals(2, mock.getLogFrequency(time), TOLERANCE); - assertEquals(2, mock.getLogFrequency(time), TOLERANCE); - assertEquals(2, mock.getLogFrequency(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/test/CachedSignalProviderTest.java b/test/src/com/levien/synthesizer/core/model/test/CachedSignalProviderTest.java deleted file mode 100644 index 18b3ddf..0000000 --- a/test/src/com/levien/synthesizer/core/model/test/CachedSignalProviderTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.test; - -import com.levien.synthesizer.core.model.CachedSignalProvider; -import com.levien.synthesizer.core.model.SynthesisTime; - -import junit.framework.TestCase; - -public class CachedSignalProviderTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - // Make a simple subclass that just increments the output value. - private class MockCachedSignalProvider extends CachedSignalProvider { - public MockCachedSignalProvider() { - counter_ = 0; - } - protected double computeValue(SynthesisTime time) { - return counter_++; - } - private int counter_; - } - - // Check that the value doesn't change until the time is advanced. - public void testGetValue() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - - MockCachedSignalProvider mock = new MockCachedSignalProvider(); - - assertEquals(0, mock.getValue(time), TOLERANCE); - assertEquals(0, mock.getValue(time), TOLERANCE); - assertEquals(0, mock.getValue(time), TOLERANCE); - - time.advance(); - - assertEquals(1, mock.getValue(time), TOLERANCE); - assertEquals(1, mock.getValue(time), TOLERANCE); - - time.advance(); - - assertEquals(2, mock.getValue(time), TOLERANCE); - assertEquals(2, mock.getValue(time), TOLERANCE); - assertEquals(2, mock.getValue(time), TOLERANCE); - assertEquals(2, mock.getValue(time), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/test/SynthesisTimeTest.java b/test/src/com/levien/synthesizer/core/model/test/SynthesisTimeTest.java deleted file mode 100644 index 79e5679..0000000 --- a/test/src/com/levien/synthesizer/core/model/test/SynthesisTimeTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.test; - -import com.levien.synthesizer.core.model.SynthesisTime; - -import junit.framework.TestCase; - -public class SynthesisTimeTest extends TestCase { - private static final double TOLERANCE = 0.0000001; - - public void testZeroRate() { - SynthesisTime time = new SynthesisTime(); - assertEquals(0.0, time.getDeltaTime(), TOLERANCE); - assertEquals(0.0, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.0, time.getDeltaTime(), TOLERANCE); - assertEquals(0.0, time.getAbsoluteTime(), TOLERANCE); - } - - public void testAdvance() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(10.0); // 10 Hz - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.0, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.1, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.2, time.getAbsoluteTime(), TOLERANCE); - } - - public void testChangeSampleRate() { - // Set one sample rate. - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(10.0); // 10 Hz - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.0, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.1, time.getAbsoluteTime(), TOLERANCE); - - // Change the sample rate. - time.setSampleRate(5.0); // 5 Hz - assertEquals(0.2, time.getDeltaTime(), TOLERANCE); - assertEquals(0.1, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.2, time.getDeltaTime(), TOLERANCE); - assertEquals(0.3, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.2, time.getDeltaTime(), TOLERANCE); - assertEquals(0.5, time.getAbsoluteTime(), TOLERANCE); - } - - public void testReset() { - // Get it out of the default state. - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(10.0); // 10 Hz - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.0, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.1, time.getAbsoluteTime(), TOLERANCE); - - // Reset. - time.reset(); - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.0, time.getAbsoluteTime(), TOLERANCE); - time.advance(); - assertEquals(0.1, time.getDeltaTime(), TOLERANCE); - assertEquals(0.1, time.getAbsoluteTime(), TOLERANCE); - } -} diff --git a/test/src/com/levien/synthesizer/core/model/test/SynthesizerInputTest.java b/test/src/com/levien/synthesizer/core/model/test/SynthesizerInputTest.java deleted file mode 100644 index d0825b1..0000000 --- a/test/src/com/levien/synthesizer/core/model/test/SynthesizerInputTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.levien.synthesizer.core.model.test; - -import com.levien.synthesizer.core.model.SynthesisTime; -import com.levien.synthesizer.core.model.SynthesizerInput; - -import junit.framework.TestCase; - -public class SynthesizerInputTest extends TestCase { - final private static double TOLERANCE = 0.000001; - - public void testGetSynthesizerInputValue() { - SynthesizerInput input = new SynthesizerInput(3.2, 0.0, 1.0); - assertEquals(3.2, input.getSynthesizerInputValue(), TOLERANCE); - } - - public void testGetValue() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - - SynthesizerInput input = new SynthesizerInput(3.5, 1.0, 5.0); - assertEquals(3.5, input.getValue(time), TOLERANCE); - time.advance(); - assertEquals(3.5, input.getValue(time), TOLERANCE); - - input.setByteValue((byte)0); - assertEquals(1.0, input.getValue(time), TOLERANCE); - - input.setByteValue((byte)63); - assertEquals(3.0, input.getValue(time), 0.03); - - input.setByteValue((byte)127); - assertEquals(5.0, input.getValue(time), TOLERANCE); - } - - public void testGetLogFrequency() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - - SynthesizerInput input = new SynthesizerInput(7.1, 0.0, 1.0); - assertEquals(7.1, input.getLogFrequency(time), TOLERANCE); - time.advance(); - assertEquals(7.1, input.getLogFrequency(time), TOLERANCE); - } - - public void testChange() { - SynthesisTime time = new SynthesisTime(); - time.setSampleRate(44100.0); - - SynthesizerInput input = new SynthesizerInput(5.5, 0.0, 1.0); - assertEquals(5.5, input.getSynthesizerInputValue(), TOLERANCE); - assertEquals(5.5, input.getValue(time), TOLERANCE); - assertEquals(5.5, input.getLogFrequency(time), TOLERANCE); - time.advance(); - assertEquals(5.5, input.getSynthesizerInputValue(), TOLERANCE); - assertEquals(5.5, input.getValue(time), TOLERANCE); - assertEquals(5.5, input.getLogFrequency(time), TOLERANCE); - - // Change the value. - input.setValue(3.2); - assertEquals(3.2, input.getSynthesizerInputValue(), TOLERANCE); - assertEquals(3.2, input.getValue(time), TOLERANCE); - assertEquals(3.2, input.getLogFrequency(time), TOLERANCE); - time.advance(); - assertEquals(3.2, input.getSynthesizerInputValue(), TOLERANCE); - assertEquals(3.2, input.getValue(time), TOLERANCE); - assertEquals(3.2, input.getLogFrequency(time), TOLERANCE); - } -}