diff --git a/build.gradle b/build.gradle index 66dc0de..4ae35ce 100644 --- a/build.gradle +++ b/build.gradle @@ -1,29 +1,33 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.41' repositories { mavenCentral() + google() maven { url "https://plugins.gradle.org/m2/" } - google() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' - classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' - if(gradle.language.equals("kotlin")) classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.android.tools.build:gradle:4.2.2' + + // for mavenCentral publish + //classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' } } +/* + * mavenCentral publish script + * apply plugin: 'io.github.gradle-nexus.publish-plugin' apply from: file("publish-root.gradle") +*/ allprojects { repositories { mavenCentral() + google() maven { url "https://plugins.gradle.org/m2/" } - google() } } \ No newline at end of file diff --git a/euphony/build.gradle b/euphony/build.gradle index c09c19f..7b1c05f 100644 --- a/euphony/build.gradle +++ b/euphony/build.gradle @@ -1,41 +1,21 @@ apply plugin: 'com.android.library' -if(gradle.language.equals("kotlin")) { - apply plugin: 'kotlin-android-extensions' - apply plugin: 'kotlin-android' -} - -apply from: file('publish.gradle') android { compileSdkVersion(30) -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - if(gradle.language.equals("kotlin")) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test:runner:1.3.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' -} -android { defaultConfig { - minSdkVersion 14 + minSdkVersion 16 targetSdkVersion 30 - ndk { - moduleName "kissff" - } - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - sourceSets { - main { - java.srcDirs = ['src/main/' + gradle.language] - } - test { - java.srcDirs = ['src/test/' + gradle.language] + /* This externalNativeBuild block is different from the one which is on the outside of defaultConfig */ + externalNativeBuild { + cmake { + cppFlags "-std=c++14 -fopenmp" + arguments "-DANDROID_STL=c++_shared" + arguments "-DANDROID_SDK_ROOT=${android.getSdkDirectory().getAbsolutePath()}" + } } } @@ -49,13 +29,30 @@ android { testCoverageEnabled false } } + externalNativeBuild { - ndkBuild { - path file('src/main/jni/Android.mk') + cmake { + path "src/main/cpp/CMakeLists.txt" + version "3.10.2" } } + lintOptions { + warning 'MissingPermission' + } + + buildFeatures { + prefab true + } + testOptions { unitTests.returnDefaultValues = true } +} + +dependencies { + implementation 'com.google.oboe:oboe:1.6.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' } \ No newline at end of file diff --git a/euphony/src/androidTest/java/co/euphony/tx/EuTxManagerTest.java b/euphony/src/androidTest/java/co/euphony/tx/EuTxManagerTest.java new file mode 100644 index 0000000..f1a299d --- /dev/null +++ b/euphony/src/androidTest/java/co/euphony/tx/EuTxManagerTest.java @@ -0,0 +1,98 @@ +package co.euphony.tx; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; + +import co.euphony.util.EuOption; + +import static org.junit.Assert.*; + +@RunWith(Parameterized.class) +@SmallTest +public class EuTxManagerTest { + private static final String TX_TAG = "EU_TXMANAGER_TAG"; + + String code; + String expectedASCIICode; + String expectedGenCode; + int expectedStreamLength; + int expectedBufferLength; + + EuTxManager txManager = null; + public EuTxManagerTest(String code, String asciiCode, String expectedGenCode, int expectedStreamLength, int expectedBufferLength) { + this.code = code; + this.expectedASCIICode = asciiCode; + this.expectedGenCode = expectedGenCode; + this.expectedStreamLength = expectedStreamLength; + this.expectedBufferLength = expectedBufferLength; + } + + @Before + public void setup() { + txManager = new EuTxManager(ApplicationProvider.getApplicationContext()); + } + + @Test + public void getCode() { + txManager.setCode(code); + + String activeResult = txManager.getCode(); + assertEquals(expectedASCIICode, activeResult); + } + + @Test + public void getGenCode() { + txManager.setCode(code); + + String activeResult = txManager.getGenCode(); + assertEquals(expectedGenCode, activeResult); + } + + @Test + public void setGetCodeTest() { + txManager.setCode("a"); + String activeResult = txManager.getGenCode(); + assertEquals("S6197", activeResult); + + txManager.setCode("b"); + activeResult = txManager.getGenCode(); + assertEquals("S6284", activeResult); + + } + + @Test + public void getGenWaveSource() { + txManager.setCode(code); + txManager.setMode(EuOption.ModeType.DEFAULT); + float[] waveSourceData = txManager.getOutStream(); + assertEquals(waveSourceData.length, expectedStreamLength); + } + + @Test + public void testRun() { + txManager.callEuPI(18000, EuTxManager.EuPIDuration.LENGTH_SHORT); + } + + @Parameterized.Parameters + public static Iterable data() { + return Arrays.asList(new Object[][]{ + {"a", "61", "S6197", 5*2048, 5*8}, + {"b", "62", "S6284", 5*2048, 5*8}, + {"c", "63", "S6375", 5*2048, 5*8}, + {"abc", "616263", "S61626386", 9*2048, 9*8}, + {"Abc", "416263", "S416263a4", 9*2048, 9*8}, + {"lmno", "6c6d6e6f", "S6c6d6e6f20", 11*2048, 11*8}, + {"efg", "656667", "S656667c2", 9*2048, 9*8}, + {"abcdefghijklmnopqrstuvwxyz", "6162636465666768696a6b6c6d6e6f707172737475767778797a", "S6162636465666768696a6b6c6d6e6f707172737475767778797aaa", 55*2048, 55*8}, + {"ABC", "414243", "S414243e4", 9*2048, 9*8}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYZ", "4142434445464748494a4b4c4d4e4f505152535455565758595a", "S4142434445464748494a4b4c4d4e4f505152535455565758595aea", 55*2048, 55*8}, + }); + } +} \ No newline at end of file diff --git a/euphony/src/main/AndroidManifest.xml b/euphony/src/main/AndroidManifest.xml index 834086e..3c4fa8e 100644 --- a/euphony/src/main/AndroidManifest.xml +++ b/euphony/src/main/AndroidManifest.xml @@ -1,9 +1,7 @@ - - diff --git a/euphony/src/main/cpp/CMakeLists.txt b/euphony/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..5135069 --- /dev/null +++ b/euphony/src/main/cpp/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 3.4.1) + +project(euphony + VERSION 0.8) + +# Legacy JNI +set(LEGACY_SRC + arms/kiss_fft.c + arms/kiss_fftr.c + native-legacy.cpp + ) + +find_library( log-lib log ) +add_library( native-legacy SHARED ${LEGACY_SRC} ) +target_compile_definitions(native-legacy PUBLIC FIXED_POINT=16) +target_link_libraries( + native-legacy + ${log-lib} + -fopenmp + -static-openmp +) + +# Rearchitectured Euphony Native +set(EUPHONY_SRC + arms/kiss_fft.c + arms/kiss_fftr.c + core/source/AudioStreamCallback.cpp + core/source/ASCIICharset.cpp + core/source/Base2.cpp + core/source/Base16.cpp + core/source/Base16Exception.cpp + core/source/DefaultCharset.cpp + core/source/EuPIOscillator.cpp + core/source/EuPIRenderer.cpp + core/source/FFTModel.cpp + core/source/FFTProcessor.cpp + core/source/FSK.cpp + core/source/HexVector.cpp + core/source/Packet.cpp + core/source/PacketBuilder.cpp + core/source/PacketErrorDetector.cpp + core/source/TxEngine.cpp + core/source/Wave.cpp + core/source/WaveBuilder.cpp + core/source/WaveRenderer.cpp + native-connector.cpp + ) + +set(EUPHONY_HDR core) +set(DEBUG_HELPER debug-helper) +set(DEBUG_HELPER_SRC debug-helper/Trace.cpp) +set(SL_HEADERS arms/sl-headers) + +include_directories( ${EUPHONY_HDR} ${SL_HEADERS} ${DEBUG_HELPER}) + +add_library(euphony SHARED ${EUPHONY_SRC} ${DEBUG_HELPER_SRC}) +target_compile_definitions(euphony PUBLIC FIXED_POINT=16) + +find_package( + oboe REQUIRED CONFIG +) + +target_link_libraries( + euphony + ${log-lib} + OpenSLES + oboe::oboe + -fopenmp + -static-openmp +) + +# for c++ unit-test (gtest) +add_subdirectory(tests) \ No newline at end of file diff --git a/euphony/src/main/jni/_kiss_fft_guts.h b/euphony/src/main/cpp/arms/_kiss_fft_guts.h similarity index 100% rename from euphony/src/main/jni/_kiss_fft_guts.h rename to euphony/src/main/cpp/arms/_kiss_fft_guts.h diff --git a/euphony/src/main/jni/kiss_fft.c b/euphony/src/main/cpp/arms/kiss_fft.c similarity index 80% rename from euphony/src/main/jni/kiss_fft.c rename to euphony/src/main/cpp/arms/kiss_fft.c index 0e34159..683e87b 100644 --- a/euphony/src/main/jni/kiss_fft.c +++ b/euphony/src/main/cpp/arms/kiss_fft.c @@ -4,32 +4,17 @@ fixed or floating point complex numbers. It also delares the kf_ internal functions. */ -static kiss_fft_cpx *scratchbuf=NULL; -static size_t nscratchbuf=0; -static kiss_fft_cpx *tmpbuf=NULL; -static size_t ntmpbuf=0; - -#define CHECKBUF(buf,nbuf,n) \ - do { \ - if ( nbuf < (size_t)(n) ) {\ - free(buf); \ - buf = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx)*(n)); \ - nbuf = (size_t)(n); \ - } \ - }while(0) - - -static void kf_bfly2( +static +void kf_bfly2( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, int m ) { - kiss_fft_cpx * Fout2; - kiss_fft_cpx * tw1 = st->twiddles; + kiss_fft_cpx *tw1 = st->twiddles; kiss_fft_cpx t; - Fout2 = Fout + m; + kiss_fft_cpx *Fout2 = Fout + m; do{ C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); @@ -42,7 +27,8 @@ static void kf_bfly2( }while (--m); } -static void kf_bfly4( +static +void kf_bfly4( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, @@ -89,7 +75,8 @@ static void kf_bfly4( }while(--k); } -static void kf_bfly3( +static +void kf_bfly3( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, @@ -133,7 +120,8 @@ static void kf_bfly3( }while(--k); } -static void kf_bfly5( +static +void kf_bfly5( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, @@ -195,7 +183,8 @@ static void kf_bfly5( } /* perform the butterfly for one stage of a mixed radix FFT */ -static void kf_bfly_generic( +static +void kf_bfly_generic( kiss_fft_cpx * Fout, const size_t fstride, const kiss_fft_cfg st, @@ -208,12 +197,16 @@ static void kf_bfly_generic( kiss_fft_cpx t; int Norig = st->nfft; - CHECKBUF(scratchbuf,nscratchbuf,p); + kiss_fft_cpx *scratchbuf = (kiss_fft_cpx*) KISS_FFT_MALLOC(sizeof(kiss_fft_cpx) * p); + if(scratchbuf == NULL) { + __android_log_print(ANDROID_LOG_INFO,"KISS_FFT_BFLY_GENERIC","scratch buffer is NULL."); + return; + } for ( u=0; unfft); - //__android_log_print(ANDROID_LOG_INFO,"----","stride1"); - kf_work(tmpbuf,fin,1,in_stride, st->factors,st); - //__android_log_print(ANDROID_LOG_INFO,"----","stride2"); - memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); + if(fout == NULL) { + __android_log_print(ANDROID_LOG_INFO,"KISS_FFT_STRIDE","fout buffer is NULL."); + return; + } - }else{ - //__android_log_print(ANDROID_LOG_INFO,"----","stride!!!!!"); - kf_work( fout, fin, 1,in_stride, st->factors,st ); + int tmpBufMemorySize = sizeof(kiss_fft_cpx) * st->nfft; + kiss_fft_cpx *tmpbuf = (kiss_fft_cpx*) KISS_FFT_MALLOC(tmpBufMemorySize); + if(tmpbuf == NULL) { + __android_log_print(ANDROID_LOG_INFO,"KISS_FFT_STRIDE","Memory allocation failed."); + return; + } + + kf_work(tmpbuf, fin,1, in_stride, st->factors,st); + memcpy(fout, tmpbuf, tmpBufMemorySize); + free(tmpbuf); + } else { + kf_work( fout, fin, 1, in_stride, st->factors,st ); } } @@ -391,20 +382,6 @@ void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) kiss_fft_stride(cfg,fin,fout,1); } - -/* not really necessary to call, but if someone is doing in-place ffts, they may want to free the - buffers from CHECKBUF - */ -void kiss_fft_cleanup(void) -{ - free(scratchbuf); - scratchbuf = NULL; - nscratchbuf=0; - free(tmpbuf); - tmpbuf=NULL; - ntmpbuf=0; -} - int kiss_fft_next_fast_size(int n) { while(1) { diff --git a/euphony/src/main/jni/kiss_fft.h b/euphony/src/main/cpp/arms/kiss_fft.h similarity index 93% rename from euphony/src/main/jni/kiss_fft.h rename to euphony/src/main/cpp/arms/kiss_fft.h index 7ddc718..1cc06df 100644 --- a/euphony/src/main/jni/kiss_fft.h +++ b/euphony/src/main/cpp/arms/kiss_fft.h @@ -40,7 +40,7 @@ extern "C" { #include #include #include -#define kiss_fft_scalar short +#define kiss_fft_scalar short //int32_t #else # ifndef kiss_fft_scalar /* default is float */ @@ -101,13 +101,6 @@ void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout buffer and can be simply free()d when no longer needed*/ #define kiss_fft_free free -/* - Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up - your compiler output to call this before you exit. -*/ -void kiss_fft_cleanup(void); - - /* * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) */ diff --git a/euphony/src/main/jni/kiss_fftr.c b/euphony/src/main/cpp/arms/kiss_fftr.c similarity index 93% rename from euphony/src/main/jni/kiss_fftr.c rename to euphony/src/main/cpp/arms/kiss_fftr.c index 0b1dd8b..79b8487 100644 --- a/euphony/src/main/jni/kiss_fftr.c +++ b/euphony/src/main/cpp/arms/kiss_fftr.c @@ -16,7 +16,7 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme { int i; kiss_fftr_cfg st = NULL; - size_t subsize, memneeded; + size_t subsize = 0, memneeded; if (nfft & 1) { fprintf(stderr,"Real FFT optimization must be even.\n"); @@ -42,7 +42,8 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme st->super_twiddles = st->tmpbuf + nfft; kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); - for (i = 0; i < nfft/2; ++i) { + int nfft_half = (nfft >> 1); + for (i = 0; i < nfft_half; ++i) { double phase = -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5); if (inverse_fft) @@ -52,7 +53,7 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme return st; } -void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata, kiss_fft_cpx *freqdata) { /* input buffer timedata is stored row-wise */ @@ -63,12 +64,9 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr fprintf(stderr,"kiss fft usage error: improper alloc\n"); exit(1); } - // __android_log_print(ANDROID_LOG_INFO,"----","a"); ncfft = st->substate->nfft; - // __android_log_print(ANDROID_LOG_INFO,"----","b"); /*perform the parallel fft of two real signals packed in real,imag*/ kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); - // __android_log_print(ANDROID_LOG_INFO,"----","c"); /* The real part of the DC element of the frequency spectrum in st->tmpbuf * contains the sum of the even-numbered elements of the input time sequence * The imag part is the sum of the odd-numbered elements @@ -92,7 +90,8 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr freqdata[ncfft].i = freqdata[0].i = 0; #endif - for ( k=1;k <= ncfft/2 ; ++k ) { + int ncfft_half = (ncfft >> 1); + for ( k=1;k <= ncfft_half ; ++k ) { fpk = st->tmpbuf[k]; fpnk.r = st->tmpbuf[ncfft-k].r; fpnk.i = - st->tmpbuf[ncfft-k].i; diff --git a/euphony/src/main/jni/kiss_fftr.h b/euphony/src/main/cpp/arms/kiss_fftr.h similarity index 100% rename from euphony/src/main/jni/kiss_fftr.h rename to euphony/src/main/cpp/arms/kiss_fftr.h diff --git a/euphony/src/main/cpp/arms/sl-headers/DefaultAudioStreamCallback.h b/euphony/src/main/cpp/arms/sl-headers/DefaultAudioStreamCallback.h new file mode 100644 index 0000000..d717dce --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/DefaultAudioStreamCallback.h @@ -0,0 +1,139 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SAMPLES_DEFAULT_AUDIO_STREAM_CALLBACK_H +#define SAMPLES_DEFAULT_AUDIO_STREAM_CALLBACK_H + + +#include +#include +#include + +#include +#include + +/** + * This is a callback object which will render data from an `IRenderableAudio` source. It is + * constructed using an `IRestartable` which allows it to automatically restart the parent object + * if the stream is disconnected (for example, when headphones are attached). + * + * @param IRestartable - the object which should be restarted when the stream is disconnected + */ +class DefaultAudioStreamCallback : public oboe::AudioStreamCallback { +public: + DefaultAudioStreamCallback(IRestartable &parent): mParent(parent) {} + virtual ~DefaultAudioStreamCallback() = default; + + virtual oboe::DataCallbackResult + onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override { + + if (mIsThreadAffinityEnabled && !mIsThreadAffinitySet) { + setThreadAffinity(); + mIsThreadAffinitySet = true; + } + + float *outputBuffer = static_cast(audioData); + if (!mRenderable) { + LOGE("Renderable source not set!"); + return oboe::DataCallbackResult::Stop; + } + mRenderable->renderAudio(outputBuffer, numFrames); + return oboe::DataCallbackResult::Continue; + } + virtual void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override { + // Restart the stream when it errors out with disconnect + if (error == oboe::Result::ErrorDisconnected) { + LOGE("Restarting AudioStream after disconnect"); + mParent.restart(); + } else { + LOGE("Unknown error"); + } + mIsThreadAffinitySet = false; + } + + void setSource(std::shared_ptr renderable) { + mRenderable = renderable; + } + + std::shared_ptr getSource() { + return mRenderable; + } + + /** + * Set the CPU IDs to bind the audio callback thread to + * + * @param mCpuIds - the CPU IDs to bind to + */ + void setCpuIds(std::vector cpuIds){ + mCpuIds = std::move(cpuIds); + } + + /** + * Enable or disable binding the audio callback thread to specific CPU cores. The CPU core IDs + * can be specified using @see setCpuIds. If no CPU IDs are specified the initial core which the + * audio thread is called on will be used. + * + * @param isEnabled - whether the audio callback thread should be bound to specific CPU core(s) + */ + void setThreadAffinityEnabled(bool isEnabled){ + mIsThreadAffinityEnabled = isEnabled; + LOGD("Thread affinity enabled: %s", (isEnabled) ? "true" : "false"); + } + +private: + std::shared_ptr mRenderable; + IRestartable &mParent; + std::vector mCpuIds; // IDs of CPU cores which the audio callback should be bound to + std::atomic mIsThreadAffinityEnabled { false }; + std::atomic mIsThreadAffinitySet { false }; + + /** + * Set the thread affinity for the current thread to mCpuIds. This can be useful to call on the + * audio thread to avoid underruns caused by CPU core migrations to slower CPU cores. + */ + void setThreadAffinity() { + + pid_t current_thread_id = gettid(); + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + + // If the callback cpu ids aren't specified then bind to the current cpu + if (mCpuIds.empty()) { + int current_cpu_id = sched_getcpu(); + LOGD("Binding to current CPU ID %d", current_cpu_id); + CPU_SET(current_cpu_id, &cpu_set); + } else { + LOGD("Binding to %d CPU IDs", static_cast(mCpuIds.size())); + for (size_t i = 0; i < mCpuIds.size(); i++) { + int cpu_id = mCpuIds.at(i); + LOGD("CPU ID %d added to cores set", cpu_id); + CPU_SET(cpu_id, &cpu_set); + } + } + + int result = sched_setaffinity(current_thread_id, sizeof(cpu_set_t), &cpu_set); + if (result == 0) { + LOGV("Thread affinity set"); + } else { + LOGW("Error setting thread affinity. Error no: %d", result); + } + + mIsThreadAffinitySet = true; + } + +}; + +#endif //SAMPLES_DEFAULT_AUDIO_STREAM_CALLBACK_H diff --git a/euphony/src/main/cpp/arms/sl-headers/IRenderableAudio.h b/euphony/src/main/cpp/arms/sl-headers/IRenderableAudio.h new file mode 100644 index 0000000..da0b8cb --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/IRenderableAudio.h @@ -0,0 +1,31 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SAMPLES_IRENDERABLEAUDIO_H +#define SAMPLES_IRENDERABLEAUDIO_H + +#include +#include + +class IRenderableAudio { + +public: + virtual ~IRenderableAudio() = default; + virtual void renderAudio(float *audioData, int32_t numFrames) = 0; +}; + + +#endif //SAMPLES_IRENDERABLEAUDIO_H diff --git a/euphony/src/main/cpp/arms/sl-headers/IRestartable.h b/euphony/src/main/cpp/arms/sl-headers/IRestartable.h new file mode 100644 index 0000000..855fff3 --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/IRestartable.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SAMPLES_IRESTARTABLE_H +#define SAMPLES_IRESTARTABLE_H + +/** + * Represents an object which can be restarted. For example an audio engine which has one or more + * streams which can be restarted following a change in audio device configuration. For example, + * headphones being connected. + */ +class IRestartable { +public: + virtual void restart() = 0; +}; +#endif //SAMPLES_IRESTARTABLE_H diff --git a/euphony/src/main/cpp/arms/sl-headers/ITappable.h b/euphony/src/main/cpp/arms/sl-headers/ITappable.h new file mode 100644 index 0000000..40cb716 --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/ITappable.h @@ -0,0 +1,25 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SAMPLES_ITAPPABLE_H +#define SAMPLES_ITAPPABLE_H + +class ITappable { +public: + virtual ~ITappable() = default; + virtual void tap(bool isDown) = 0; +}; +#endif //SAMPLES_ITAPPABLE_H diff --git a/euphony/src/main/cpp/arms/sl-headers/Mixer.h b/euphony/src/main/cpp/arms/sl-headers/Mixer.h new file mode 100644 index 0000000..56926d8 --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/Mixer.h @@ -0,0 +1,63 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SHARED_MIXER_H +#define SHARED_MIXER_H + +#include +#include "IRenderableAudio.h" + +constexpr int32_t kBufferSize = 192*10; // Temporary buffer is used for mixing +constexpr uint8_t kMaxTracks = 100; + +/** + * A Mixer object which sums the output from multiple tracks into a single output. The number of + * input channels on each track must match the number of output channels (default 1=mono). This can + * be changed by calling `setChannelCount`. + * The inputs to the mixer are not owned by the mixer, they should not be deleted while rendering. + */ +class Mixer : public IRenderableAudio { + +public: + void renderAudio(float *audioData, int32_t numFrames) { + + // Zero out the incoming container array + memset(audioData, 0, sizeof(float) * numFrames * mChannelCount); + + for (int i = 0; i < mNextFreeTrackIndex; ++i) { + mTracks[i]->renderAudio(mixingBuffer, numFrames); + + for (int j = 0; j < numFrames * mChannelCount; ++j) { + audioData[j] += mixingBuffer[j]; + } + } + } + + void addTrack(IRenderableAudio *renderer){ + mTracks[mNextFreeTrackIndex++] = renderer; + } + + void setChannelCount(int32_t channelCount){ mChannelCount = channelCount; } + +private: + float mixingBuffer[kBufferSize]; + std::array mTracks; + uint8_t mNextFreeTrackIndex = 0; + int32_t mChannelCount = 1; // Default to mono +}; + + +#endif //SHARED_MIXER_H diff --git a/euphony/src/main/cpp/arms/sl-headers/MonoToStereo.h b/euphony/src/main/cpp/arms/sl-headers/MonoToStereo.h new file mode 100644 index 0000000..97ba349 --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/MonoToStereo.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SHARED_MONOTOSTEREO_H +#define SHARED_MONOTOSTEREO_H + +#include "IRenderableAudio.h" + + +class MonoToStereo : public IRenderableAudio { + +public: + + MonoToStereo(IRenderableAudio *input) : mInput(input){}; + + void renderAudio(float *audioData, int32_t numFrames) override { + + constexpr int kChannelCountStereo = 2; + + mInput->renderAudio(audioData, numFrames); + + // We assume that audioData has sufficient frames to hold the stereo output, so copy each + // frame in the input to the output twice, working our way backwards through the input array + // e.g. 123 => 112233 + for (int i = numFrames - 1; i >= 0; --i) { + + audioData[i * kChannelCountStereo] = audioData[i]; + audioData[i * kChannelCountStereo + 1] = audioData[i]; + } + } + + IRenderableAudio *mInput; +}; + + +#endif //SHARED_MONOTOSTEREO_H diff --git a/euphony/src/main/cpp/arms/sl-headers/Oscillator.h b/euphony/src/main/cpp/arms/sl-headers/Oscillator.h new file mode 100644 index 0000000..4847274 --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/Oscillator.h @@ -0,0 +1,94 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef SHARED_OSCILLATOR_H +#define SHARED_OSCILLATOR_H + + +#include +#include +#include +#include +#include "IRenderableAudio.h" + +constexpr double kDefaultFrequency = 440.0; +constexpr int32_t kDefaultSampleRate = 48000; +constexpr double kPi = M_PI; +constexpr double kTwoPi = kPi * 2; + +class Oscillator : public IRenderableAudio { + +public: + + ~Oscillator() = default; + + void setWaveOn(bool isWaveOn) { + mIsWaveOn.store(isWaveOn); + }; + + void setSampleRate(int32_t sampleRate) { + mSampleRate = sampleRate; + updatePhaseIncrement(); + }; + + void setFrequency(double frequency) { + mFrequency = frequency; + updatePhaseIncrement(); + }; + + inline void setAmplitude(float amplitude) { + mAmplitude = amplitude; + }; + + // From IRenderableAudio + void renderAudio(float *audioData, int32_t numFrames) override { + + if (mIsWaveOn){ + for (int i = 0; i < numFrames; ++i) { + + // Sine wave (sinf) + //data[i*kChannelCount] = sinf(mPhase) * mAmplitude; + + // Square wave + if (mPhase <= kPi){ + audioData[i] = -mAmplitude; + } else { + audioData[i] = mAmplitude; + } + + mPhase += mPhaseIncrement; + if (mPhase > kTwoPi) mPhase -= kTwoPi; + } + } else { + memset(audioData, 0, sizeof(float) * numFrames); + } + }; + +private: + std::atomic mIsWaveOn { false }; + float mPhase = 0.0; + std::atomic mAmplitude { 0 }; + std::atomic mPhaseIncrement { 0.0 }; + double mFrequency = kDefaultFrequency; + int32_t mSampleRate = kDefaultSampleRate; + + void updatePhaseIncrement(){ + mPhaseIncrement.store((kTwoPi * mFrequency) / static_cast(mSampleRate)); + }; +}; + +#endif //SHARED_OSCILLATOR_H diff --git a/euphony/src/main/cpp/arms/sl-headers/TappableAudioSource.h b/euphony/src/main/cpp/arms/sl-headers/TappableAudioSource.h new file mode 100644 index 0000000..fde3917 --- /dev/null +++ b/euphony/src/main/cpp/arms/sl-headers/TappableAudioSource.h @@ -0,0 +1,38 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SAMPLES_RENDERABLE_TAP_H +#define SAMPLES_RENDERABLE_TAP_H + +#include + +#include "IRenderableAudio.h" +#include "ITappable.h" + +/** + * This class renders Float audio, but can be tapped to control. + * It also contains members for sample rate and channel count + */ +class TappableAudioSource : public IRenderableAudio, public ITappable { +public: + TappableAudioSource(int32_t sampleRate, int32_t channelCount) : + mSampleRate(sampleRate), mChannelCount(channelCount) { } + + int32_t mSampleRate; + int32_t mChannelCount; +}; + +#endif //SAMPLES_RENDERABLE_TAP_H \ No newline at end of file diff --git a/euphony/src/main/cpp/core/ASCIICharset.h b/euphony/src/main/cpp/core/ASCIICharset.h new file mode 100644 index 0000000..13f9ff7 --- /dev/null +++ b/euphony/src/main/cpp/core/ASCIICharset.h @@ -0,0 +1,17 @@ +#ifndef EUPHONY_ASCIICHARSET_H +#define EUPHONY_ASCIICHARSET_H + +#include "Charset.h" + +namespace Euphony { + + class ASCIICharset : public Charset { + public: + ASCIICharset() = default; + ~ASCIICharset() = default; + HexVector encode(std::string src); + std::string decode(const HexVector &src); + }; +} + +#endif //EUPHONY_ASCIICHARSET_H diff --git a/euphony/src/main/cpp/core/AudioStreamCallback.h b/euphony/src/main/cpp/core/AudioStreamCallback.h new file mode 100644 index 0000000..2ed4718 --- /dev/null +++ b/euphony/src/main/cpp/core/AudioStreamCallback.h @@ -0,0 +1,58 @@ +// +// Created by designe on 20. 8. 24. +// + +#ifndef EUPHONY_AUDIOSTREAMCALLBACK_H +#define EUPHONY_AUDIOSTREAMCALLBACK_H + +#include +#include + +#include +#include +#include + +/** + * This callback object extends the functionality of `DefaultAudioStreamCallback` by automatically + * tuning the latency of the audio stream. @see onAudioReady for more details on this. + * + * It also demonstrates how to use tracing functions for logging inside the audio callback without + * blocking. + */ + +namespace Euphony { + class AudioStreamCallback : public DefaultAudioStreamCallback { + public: + AudioStreamCallback(IRestartable &mParent) : DefaultAudioStreamCallback(mParent) { + + // Initialize the trace functions, this enables you to output trace statements without + // blocking. See https://developer.android.com/studio/profile/systrace-commandline.html + Trace::initialize(); + } + + /** + * Every time the playback stream requires data this method will be called. + * + * @param audioStream the audio stream which is requesting data, this is the mPlayStream object + * @param audioData an empty buffer into which we can write our audio data + * @param numFrames the number of audio frames which are required + * @return Either oboe::DataCallbackResult::Continue if the stream should continue requesting data + * or oboe::DataCallbackResult::Stop if the stream should stop. + */ + oboe::DataCallbackResult + onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override; + + void setBufferTuneEnabled(bool enabled) { mBufferTuneEnabled = enabled; } + + void useStream(std::shared_ptr stream); + + private: + bool mBufferTuneEnabled = true; + + // This will be used to automatically tune the buffer size of the stream, obtaining optimal latency + std::unique_ptr mLatencyTuner; + oboe::AudioStream *mStream = nullptr; + }; +} + +#endif //EUPHONY_AUDIOSTREAMCALLBACK_H diff --git a/euphony/src/main/cpp/core/Base.h b/euphony/src/main/cpp/core/Base.h new file mode 100644 index 0000000..c89dd2b --- /dev/null +++ b/euphony/src/main/cpp/core/Base.h @@ -0,0 +1,19 @@ +#ifndef EUPHONY_BASE_H +#define EUPHONY_BASE_H + +#include +#include "HexVector.h" + +namespace Euphony { + class Base { + public: + virtual ~Base() = default; + + virtual std::string getBaseString() = 0; + virtual const HexVector &getHexVector() const = 0; + virtual int convertChar2Int(char src) const = 0; + virtual char convertInt2Char(int src) const = 0; + }; +} + +#endif //EUPHONY_BASE_H diff --git a/euphony/src/main/cpp/core/Base16.h b/euphony/src/main/cpp/core/Base16.h new file mode 100644 index 0000000..bbc83de --- /dev/null +++ b/euphony/src/main/cpp/core/Base16.h @@ -0,0 +1,23 @@ +#ifndef EUPHONY_BASE16_H +#define EUPHONY_BASE16_H + +#include "Base.h" +#include "Base16Exception.h" + +namespace Euphony { + + class Base16 : public Base { + public: + Base16(const HexVector &hexVectorSrc); + ~Base16() = default; + std::string getBaseString(); + const HexVector &getHexVector() const; + int convertChar2Int(char source) const; + char convertInt2Char(int source) const; + + private: + HexVector hexVector; + }; +} + +#endif //EUPHONY_BASE16_H diff --git a/euphony/src/main/cpp/core/Base16Exception.h b/euphony/src/main/cpp/core/Base16Exception.h new file mode 100644 index 0000000..7ed43c0 --- /dev/null +++ b/euphony/src/main/cpp/core/Base16Exception.h @@ -0,0 +1,27 @@ +#ifndef EUPHONY_BASE16EXCEPTION_H +#define EUPHONY_BASE16EXCEPTION_H + +#include +#include + +namespace Euphony { + + class Base16Exception : public std::exception { + public: + Base16Exception(); + Base16Exception(int line, const std::string & file ); + + ~Base16Exception() throw(); + + const char *what() const throw(); + const std::string & MSG() const; + + int LINE() const; + const std::string & FILE() const; + + private: + std::string msg, file; + int line; + }; +} +#endif //EUPHONY_BASE16EXCEPTION_H diff --git a/euphony/src/main/cpp/core/Base2.h b/euphony/src/main/cpp/core/Base2.h new file mode 100644 index 0000000..ced3014 --- /dev/null +++ b/euphony/src/main/cpp/core/Base2.h @@ -0,0 +1,24 @@ +#ifndef EUPHONY_BASE2_H +#define EUPHONY_BASE2_H + +#include "Base.h" + +namespace Euphony { + + class Base2 : public Base { + public: + Base2(const HexVector &hexVectorSrc); + ~Base2() = default; + std::string getBaseString(); + const HexVector &getHexVector() const; + int convertChar2Int(char source) const; + char convertInt2Char(int source) const; + + private: + HexVector hexVector; + + std::string hexToBase2(u_int8_t hex); + }; +} + +#endif //EUPHONY_BASE2_H diff --git a/euphony/src/main/cpp/core/BaseFactory.h b/euphony/src/main/cpp/core/BaseFactory.h new file mode 100644 index 0000000..7c32500 --- /dev/null +++ b/euphony/src/main/cpp/core/BaseFactory.h @@ -0,0 +1,27 @@ +#ifndef EUPHONY_BASEFACTORY_H +#define EUPHONY_BASEFACTORY_H + +#include "Definitions.h" +#include "Base2.h" +#include "Base16.h" + + +namespace Euphony { + class BaseFactory { + public: + static std::shared_ptr create(BaseType type, const HexVector &hexVectorSrc) { + switch(type) { + case BaseType::BASE2: + return std::make_shared(hexVectorSrc); + case BaseType::BASE16: + default: + return std::make_shared(hexVectorSrc); + } + } + }; +} + + + + +#endif //EUPHONY_BASEFACTORY_H diff --git a/euphony/src/main/cpp/core/Charset.h b/euphony/src/main/cpp/core/Charset.h new file mode 100644 index 0000000..5e932f9 --- /dev/null +++ b/euphony/src/main/cpp/core/Charset.h @@ -0,0 +1,16 @@ +#ifndef EUPHONY_CHARSET_H +#define EUPHONY_CHARSET_H + +#include +#include "HexVector.h" + +namespace Euphony { + class Charset { + public: + virtual ~Charset() = default; + + virtual HexVector encode(std::string src) = 0; + virtual std::string decode(const HexVector &src) = 0; + }; +} +#endif //EUPHONY_CHARSET_H diff --git a/euphony/src/main/cpp/core/DefaultCharset.h b/euphony/src/main/cpp/core/DefaultCharset.h new file mode 100644 index 0000000..e89b311 --- /dev/null +++ b/euphony/src/main/cpp/core/DefaultCharset.h @@ -0,0 +1,18 @@ +#ifndef EUPHONY_DEFAULTCHARSET_H +#define EUPHONY_DEFAULTCHARSET_H + +#include "Charset.h" + +namespace Euphony { + + class DefaultCharset : public Charset { + public: + DefaultCharset() = default; + ~DefaultCharset() = default; + HexVector encode(std::string src); + std::string decode(const HexVector &src); + }; +} + + +#endif //EUPHONY_DEFAULTCHARSET_H diff --git a/euphony/src/main/cpp/core/Definitions.h b/euphony/src/main/cpp/core/Definitions.h new file mode 100644 index 0000000..e7ab6eb --- /dev/null +++ b/euphony/src/main/cpp/core/Definitions.h @@ -0,0 +1,58 @@ +#ifndef EUPHONY_DEFINITIONS_H +#define EUPHONY_DEFINITIONS_H + +#include +#include +#include "Wave.h" + +namespace Euphony { + typedef std::vector> WaveList; + + constexpr int32_t kChannelCount = 1; + constexpr int32_t kSampleRate = 44100; + constexpr int32_t kFFTSize = 512; + constexpr int32_t kBufferSize = 2048; + constexpr int32_t kBufferFadeLength = 128; + constexpr int32_t kFrequencyInterval = kSampleRate / kFFTSize; + constexpr int32_t kStandardFrequency = 18001; + constexpr int32_t kStartSignalFrequency = kStandardFrequency - kFrequencyInterval; + constexpr double kPi = M_PI; + constexpr double kTwoPi = kPi * 2.0; + + static constexpr const char* BASE16_EXCEPTION_MSG = "BASE16 couldn't support this code value"; + + enum class ModeType : int32_t { + DEFAULT = 0, // Default Soundless Communication + DETECT = 1, // For Wave Detection + EUPI = 2, // For EUPI Mode + /* + * TODO: DISTANCE CALCULATION (Distance = Speed * Time) + DISTANCE = 4 + */ + }; + + enum class ModulationType : int32_t { + FSK = 0, + /* + TODO: v0.7.1.6 had ASK feature. but v0.8 has to create it. + ASK, + */ + /* + TODO: Rearchitecturing necessary because the CPFSK modulation type has some glitch sound. + CPFSK + */ + }; + + enum class BaseType : int32_t { + BASE2 = 0, + BASE16 = 1, + }; + + enum class CharsetType : int32_t { + ASCII = 0, + /* TODO: Develop Charset for UTF8 */ + UTF8 = 1 + }; +} + +#endif \ No newline at end of file diff --git a/euphony/src/main/cpp/core/EuPIOscillator.h b/euphony/src/main/cpp/core/EuPIOscillator.h new file mode 100644 index 0000000..e6c51df --- /dev/null +++ b/euphony/src/main/cpp/core/EuPIOscillator.h @@ -0,0 +1,62 @@ +// +// Created by designe on 20. 8. 25. +// + +#ifndef EUPHONY_EUPIOSCILLATOR_H +#define EUPHONY_EUPIOSCILLATOR_H + +#include "Definitions.h" +#include +#include +#include +#include +#include +#include + +namespace Euphony { + class EuPIOscillator : public IRenderableAudio { + public: + ~EuPIOscillator() = default; + void setWaveOn(bool isWaveOn); + void setSampleRate(int32_t sampleRate); + void setFrequency(double frequency); + inline void setAmplitude(float amplitude) { + mAmplitude = amplitude; + } + // From IRenderableAudio + void renderAudio(float *data, int32_t numFrames); + static double getPhaseIncrement(double frequency){ + return ((kTwoPi * frequency) / static_cast (kSampleRate)); + } + static std::unique_ptr makeStaticWave(int freq, int waveLength) { + std::unique_ptr source = std::make_unique(waveLength); + + double phase = 0.0; + double phaseIncrement = Euphony::EuPIOscillator::getPhaseIncrement(freq); + for(int i = 0; i < waveLength; i++) { + source[i] = sin(phase); + phase += phaseIncrement; + if(phase > kTwoPi) phase -= kTwoPi; + } + + return std::unique_ptr(); + } + + private: + std::atomic mIsFirstWave{false}; + std::atomic mIsLastWave{false}; + std::atomic mIsWaveOn{false}; + float mPhase = 0.0; + std::atomic mAmplitude{0}; + std::atomic mPhaseIncrement{0.0}; + double mFrequency = 0.0; + std::vector mTimeArray; + int32_t mSampleRate = kSampleRate; + + void updatePhaseIncrement() { + mPhaseIncrement.store((kTwoPi * mFrequency) / static_cast(mSampleRate)); + } + }; +} + +#endif //EUPHONY_EUPIOSCILLATOR_H diff --git a/euphony/src/main/cpp/core/EuPIRenderer.h b/euphony/src/main/cpp/core/EuPIRenderer.h new file mode 100644 index 0000000..dc2baac --- /dev/null +++ b/euphony/src/main/cpp/core/EuPIRenderer.h @@ -0,0 +1,34 @@ +// +// Created by desig on 2020-08-15. +// + +#ifndef EUPHONY_EUPIRENDERER_H +#define EUPHONY_EUPIRENDERER_H + + +#include "EuPIOscillator.h" +#include "EuphonyAudioSource.h" + +namespace Euphony { + class EuPIRenderer : public EuphonyAudioSource { + public: + EuPIRenderer(int32_t sampleRate, int32_t channelCount); + EuPIRenderer(EuPIRenderer &&other) = default; + EuPIRenderer &operator=(EuPIRenderer &&other) = default; + ~EuPIRenderer() = default; + + void tap(bool isDown) override; + void renderAudio(float *audioData, int32_t numFrames) override; // from IRenderableAudio + void setFrequency(double frequency); + std::unique_ptr makeStaticWave(int freq); + + private: + std::unique_ptr mOscillators; + std::unique_ptr mBuffer = std::make_unique(kBufferSize); + int32_t mChannelCount; + int32_t mSampleRate; + }; +} + + +#endif //EUPHONY_EUPIRENDERER_H diff --git a/euphony/src/main/cpp/core/EuphonyAudioSource.h b/euphony/src/main/cpp/core/EuphonyAudioSource.h new file mode 100644 index 0000000..1ff5303 --- /dev/null +++ b/euphony/src/main/cpp/core/EuphonyAudioSource.h @@ -0,0 +1,11 @@ +#ifndef EUPHONY_EUPHONYAUDIOSOURCE_H +#define EUPHONY_EUPHONYAUDIOSOURCE_H + +#include "IRenderableAudio.h" + +class EuphonyAudioSource : public IRenderableAudio { +public: + ~EuphonyAudioSource() = default; + virtual void tap(bool isDown) = 0; +}; +#endif //EUPHONY_EUPHONYAUDIOSOURCE_H diff --git a/euphony/src/main/cpp/core/FFTModel.h b/euphony/src/main/cpp/core/FFTModel.h new file mode 100644 index 0000000..0e40e2b --- /dev/null +++ b/euphony/src/main/cpp/core/FFTModel.h @@ -0,0 +1,28 @@ +// +// Created by desig on 2020-11-15. +// + +#ifndef EUPHONY_FFTMODEL_H +#define EUPHONY_FFTMODEL_H + +namespace Euphony { + class FFTModel { + public: + FFTModel(int fftSizeSrc, int sampleRateSrc); + virtual ~FFTModel() = default; + + virtual float *makeSpectrum(short *pcmSrc) = 0; + + int getFFTSize() const; + void setFFTSize(int fftSize); + int getSampleRate() const; + void setSampleRate(int sampleRate); + + private: + int fftSize; + int sampleRate; + + }; +} + +#endif //EUPHONY_FFTMODEL_H diff --git a/euphony/src/main/cpp/core/FFTProcessor.h b/euphony/src/main/cpp/core/FFTProcessor.h new file mode 100644 index 0000000..a1d7f19 --- /dev/null +++ b/euphony/src/main/cpp/core/FFTProcessor.h @@ -0,0 +1,42 @@ +// +// Created by opener on 20. 11. 30. +// + +#ifndef EUPHONY_FFTPROCESSOR_H +#define EUPHONY_FFTPROCESSOR_H + +#include +#include "../arms/kiss_fftr.h" +#include "FFTModel.h" + +/* + * Define FFT Structure + * This space is similar to device driver's structure. + * Euphony is now using KissFFT Library. + * If you want to change FFT Library, Just fulfill FFTModel interface. + */ + +namespace Euphony { + + class FFTProcessor : public FFTModel { + public: + FFTProcessor(int fft_size, int sample_rate); + ~FFTProcessor(); + virtual float* makeSpectrum(short* src); + int getResultSize() const; + + private: + static inline float shortToFloat(const short val); + inline int frequencyToIndex(const int freq) const; + + kiss_fftr_cfg config; + /* unique_ptr's array version. it is available on c++14. */ + kiss_fft_cpx* spectrum; + float* result; + int fftSize; + int halfOfFFTSize; + }; +} + + +#endif //EUPHONY_FFTPROCESSOR_H diff --git a/euphony/src/main/cpp/core/FSK.h b/euphony/src/main/cpp/core/FSK.h new file mode 100644 index 0000000..dc87a34 --- /dev/null +++ b/euphony/src/main/cpp/core/FSK.h @@ -0,0 +1,27 @@ +#ifndef EUPHONY_FSK_H +#define EUPHONY_FSK_H + +#include "FFTModel.h" +#include "Modem.h" +#include +#include + +namespace Euphony { + class FSK : public Modem { + public: + FSK(); + WaveList modulate(std::string code); + WaveList modulate(Packet* packet); + static int getMaxIdxFromSource(const float* fft_source); + static int getMaxIdxFromSource(const float* fft_source, const int baseSize, const int sampleRate, const int fftSize); + std::shared_ptr demodulate(const WaveList& waveList); + std::shared_ptr demodulate(const float* source, int sourceLength, int bufferSize); + private: + std::unique_ptr fftModel; + static int getStartFreqIdx() ; + static int getEndFreqIdx() ; + static int getStartFreqIdx(const int sampleRate, const int fftSize); + static int getEndFreqIdx(const int sampleRate, const int fftSize); + }; +} +#endif //EUPHONY_FSK_H diff --git a/euphony/src/main/cpp/core/HexVector.h b/euphony/src/main/cpp/core/HexVector.h new file mode 100644 index 0000000..6ae33ae --- /dev/null +++ b/euphony/src/main/cpp/core/HexVector.h @@ -0,0 +1,34 @@ +#ifndef EUPHONY_HEXVECTOR_H +#define EUPHONY_HEXVECTOR_H + +#include +#include + +namespace Euphony { + class HexVector { + public: + HexVector(int size); + HexVector(const HexVector& copy); + HexVector(const std::string& hexString); + HexVector(const std::vector& hexVectorCopy); + ~HexVector(); + + void pushBack(u_int8_t hexByte); + void popBack(); + std::string toString() const; + const std::vector &getHexSource() const; + void setHexSource(const std::vector &hexSource); + int getSize() const; + void clear(); + + std::__wrap_iter>::const_pointer> + begin() const; + std::__wrap_iter>::const_pointer> + end() const; + + private: + std::vector hexSource; + }; +} + +#endif //EUPHONY_HEXVECTOR_H diff --git a/euphony/src/main/cpp/core/Modem.h b/euphony/src/main/cpp/core/Modem.h new file mode 100644 index 0000000..bf92eb6 --- /dev/null +++ b/euphony/src/main/cpp/core/Modem.h @@ -0,0 +1,25 @@ +#ifndef EUPHONY_MODEM_H +#define EUPHONY_MODEM_H + +#include +#include "Definitions.h" +#include "Packet.h" +#include "Wave.h" + +using std::string; +using std::vector; +using std::shared_ptr; + +namespace Euphony { + + class Modem { + public: + virtual ~Modem() = default; + virtual WaveList modulate(string code) = 0; + virtual WaveList modulate(Packet* packet) = 0; + virtual std::shared_ptr demodulate(const WaveList& waveList) = 0; + virtual std::shared_ptr demodulate(const float* source, int sourceLength, int bufferSize) = 0; + }; +} + +#endif //EUPHONY_MODEM_H diff --git a/euphony/src/main/cpp/core/ModemFactory.h b/euphony/src/main/cpp/core/ModemFactory.h new file mode 100644 index 0000000..ec17665 --- /dev/null +++ b/euphony/src/main/cpp/core/ModemFactory.h @@ -0,0 +1,21 @@ +#ifndef EUPHONY_MODEMFACTORY_H +#define EUPHONY_MODEMFACTORY_H + +#include "Definitions.h" +#include "Modem.h" +#include "FSK.h" + +namespace Euphony { + class ModemFactory { + public: + static std::shared_ptr create(ModulationType type) { + switch(type) { + default: + case ModulationType::FSK : + return std::make_shared(); + } + } + }; +} + +#endif //EUPHONY_MODEMFACTORY_H diff --git a/euphony/src/main/cpp/core/Packet.h b/euphony/src/main/cpp/core/Packet.h new file mode 100644 index 0000000..7fe26e7 --- /dev/null +++ b/euphony/src/main/cpp/core/Packet.h @@ -0,0 +1,40 @@ +#ifndef EUPHONY_PACKET_H +#define EUPHONY_PACKET_H + +#include "Definitions.h" +#include "Base.h" +#include + +namespace Euphony { + class PacketBuilder; + + class Packet { + public: + Packet(); + Packet(const HexVector& source); + Packet(const BaseType type, const HexVector& source); + static PacketBuilder create(); + void clear(); + + std::shared_ptr getChecksum(); + std::shared_ptr getParityCode(); + std::string getPayloadStr() const; + void setPayload(std::shared_ptr payloadSrc); + void setPayload(const HexVector& source); + BaseType getBaseType() const; + void setBaseType(BaseType baseTypeSrc); + + std::string toString(); + + private: + friend class PacketBuilder; + BaseType baseType; + std::shared_ptr payload; + std::shared_ptr checksum; + std::shared_ptr parityCode; + bool isVerified; + void initialize(); + }; +} + +#endif //EUPHONY_PACKET_H diff --git a/euphony/src/main/cpp/core/PacketBuilder.h b/euphony/src/main/cpp/core/PacketBuilder.h new file mode 100644 index 0000000..954e89c --- /dev/null +++ b/euphony/src/main/cpp/core/PacketBuilder.h @@ -0,0 +1,19 @@ +#ifndef EUPHONY_PACKETBUILDER_H +#define EUPHONY_PACKETBUILDER_H + +#include "Packet.h" + +namespace Euphony { + class PacketBuilder { + public: + PacketBuilder& setPayload(const HexVector& source); + PacketBuilder& setPayloadWithASCII(std::string asciiSrc); + PacketBuilder& basedOnBase16(); + PacketBuilder& basedOnBase2(); + std::shared_ptr build(); + + private: + Packet packet; + }; +} +#endif //EUPHONY_PACKETBUILDER_H diff --git a/euphony/src/main/cpp/core/PacketErrorDetector.h b/euphony/src/main/cpp/core/PacketErrorDetector.h new file mode 100644 index 0000000..b4ef1ea --- /dev/null +++ b/euphony/src/main/cpp/core/PacketErrorDetector.h @@ -0,0 +1,20 @@ +#ifndef EUPHONY_PACKETERRORDETECTOR_H +#define EUPHONY_PACKETERRORDETECTOR_H + +#include +#include +#include "HexVector.h" + +namespace Euphony { + + class PacketErrorDetector { + public: + static std::string makeParityAndChecksum(const HexVector& payload); + static std::string makeParityAndChecksum(std::string payloadStr); + static HexVector makeChecksum(const HexVector& payload); + static HexVector makeParallelParity(const HexVector& payload); + static bool verifyChecksum(const HexVector& payload, int checksum); + static bool verifyParallelParity(const HexVector& payload, int parity); + }; +} +#endif //EUPHONY_PACKETERRORDETECTOR_H diff --git a/euphony/src/main/cpp/core/TxEngine.h b/euphony/src/main/cpp/core/TxEngine.h new file mode 100644 index 0000000..dcc4a72 --- /dev/null +++ b/euphony/src/main/cpp/core/TxEngine.h @@ -0,0 +1,54 @@ +// +// Created by desig on 2020-08-15. +// + +#ifndef EUPHONY_TXENGINE_H +#define EUPHONY_TXENGINE_H + +#include + +constexpr int32_t kBufferSizeAutomatic = 0; + +namespace Euphony { + enum Status { + RUNNING, STOP + }; + + class TxEngine { + public: + TxEngine(); + ~TxEngine(); + + void tap(bool isDown); + void tapCount(bool isDown, int count); + void stop(); + void start(); + void setCode(std::string data); + std::string getCode(); + std::string getGenCode(); + float* getGenWaveSource(); + int getGenWaveSourceSize(); + void setCodingType(int codingTypeSrc); + void setMode(int modeSrc); + void setModulation(int modulationTypeSrc); + void setAudioApi(oboe::AudioApi audioApi); + void setChannelCount(int channelCount); + void setDeviceId(int32_t deviceId); + int getFramesPerBursts(); + void setBufferSizeInBursts(int32_t numBursts); + void setPerformance(oboe::PerformanceMode mode); + void setEupiFrequency(double freq); + double getCurrentOutputLatencyMillis(); + Status getStatus(); + bool isLatencyDetectionSupported(); + + private: + //Do Not Copy EpnyTxEngine + TxEngine(const TxEngine &); + const TxEngine &operator=(const TxEngine &); + class TxEngineImpl; + std::unique_ptr pImpl; + }; +} + +#endif //EUPHONY_TXENGINE_H diff --git a/euphony/src/main/cpp/core/Wave.h b/euphony/src/main/cpp/core/Wave.h new file mode 100644 index 0000000..6a6fd04 --- /dev/null +++ b/euphony/src/main/cpp/core/Wave.h @@ -0,0 +1,55 @@ +// +// Created by designe on 20. 9. 16. +// + +#ifndef EUPHONY_WAVE_H +#define EUPHONY_WAVE_H + +#include + +namespace Euphony { + + class WaveBuilder; + + enum CrossfadeType { + FRONT, END, BOTH, NONE + }; + + class Wave { + public: + Wave(); + Wave(int hz, int bufferSize); + Wave(const float* src, int bufferSize); + explicit Wave(const Wave& copy); + + static WaveBuilder create(); + void oscillate(); + void oscillate(int hz, int size); + void setCrossfade(CrossfadeType crossfadeType); + + int getHz() const; + void setHz(int hz); + int getSize() const; + void setSize(int size); + + std::vector getSource() const; + void setSource(const std::vector &source); + std::vector getInt16Source(); + static int16_t convertFloat2Int16(float source); + + private: + friend class WaveBuilder; + + int mHz; + int mSize; + CrossfadeType crossfadeType; + std::vector mSource; + float mPhase = 0.0; + std::atomic mPhaseIncrement{0.0}; + void updatePhaseIncrement(int hz); + + }; + +} + +#endif //EUPHONY_WAVE_H diff --git a/euphony/src/main/cpp/core/WaveBuilder.h b/euphony/src/main/cpp/core/WaveBuilder.h new file mode 100644 index 0000000..d22be41 --- /dev/null +++ b/euphony/src/main/cpp/core/WaveBuilder.h @@ -0,0 +1,18 @@ +#ifndef EUPHONY_WAVEBUILDER_H +#define EUPHONY_WAVEBUILDER_H + +#include "Wave.h" + +namespace Euphony { + class WaveBuilder { + private: + Wave wave; + + public: + WaveBuilder& vibratesAt(int hz); + WaveBuilder& setSize(int size); + WaveBuilder& setCrossfade(CrossfadeType type); + std::shared_ptr build(); + }; +}; +#endif //EUPHONY_WAVEBUILDER_H diff --git a/euphony/src/main/cpp/core/WaveRenderer.h b/euphony/src/main/cpp/core/WaveRenderer.h new file mode 100644 index 0000000..42a3a23 --- /dev/null +++ b/euphony/src/main/cpp/core/WaveRenderer.h @@ -0,0 +1,32 @@ +#ifndef EUPHONY_WAVERENDERER_H +#define EUPHONY_WAVERENDERER_H + +#include "Definitions.h" +#include "EuphonyAudioSource.h" + +namespace Euphony { + + class WaveRenderer : public EuphonyAudioSource{ + public: + WaveRenderer(WaveList waveListSrc, int32_t channelCountSrc); + ~WaveRenderer() = default; + + void renderAudio(float *targetData, int32_t numFrames) override; //From IRenderableAudio + void tap(bool isDown) override; + void tapCount(bool isDown, int count); + float* getWaveSource(); + int32_t getWaveSourceSize() const; + void setWaveList(WaveList waveListSrc); + + private: + void renderSilence(float *targetData, int32_t numFrames); + std::unique_ptr waveSource; + std::atomic isWaveOn { false }; + int32_t channelCount; + int32_t readFrameIndex; + int32_t waveSourceSize; + int32_t renderIndex; + int32_t renderTotalCount; + }; +} +#endif //EUPHONY_WAVERENDERER_H diff --git a/euphony/src/main/cpp/core/source/ASCIICharset.cpp b/euphony/src/main/cpp/core/source/ASCIICharset.cpp new file mode 100644 index 0000000..98d8b37 --- /dev/null +++ b/euphony/src/main/cpp/core/source/ASCIICharset.cpp @@ -0,0 +1,27 @@ +#include "../ASCIICharset.h" +#include +#include + +using namespace Euphony; + +HexVector ASCIICharset::encode(std::string src) { + HexVector result(src.size()); + + for(char &c : src) { + result.pushBack(c); + } + + return result; +} + +std::string ASCIICharset::decode(const HexVector &src) { + std::string result; + + std::string stringSrc = src.toString(); + for(int i = 0; i < stringSrc.size() - 1; i+=2) { + std::string c = stringSrc.substr(i, 2); + result.push_back((char) (int) strtol(c.c_str(), nullptr, 16)); + } + + return result; +} diff --git a/euphony/src/main/cpp/core/source/AudioStreamCallback.cpp b/euphony/src/main/cpp/core/source/AudioStreamCallback.cpp new file mode 100644 index 0000000..f962eba --- /dev/null +++ b/euphony/src/main/cpp/core/source/AudioStreamCallback.cpp @@ -0,0 +1,31 @@ +// +// Created by designe on 20. 8. 24. +// + +#include + +oboe::DataCallbackResult Euphony::AudioStreamCallback::onAudioReady( + oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) { + if (oboeStream != mStream) { + mStream = oboeStream; + mLatencyTuner = std::make_unique(*oboeStream); + } + if (mBufferTuneEnabled + && mLatencyTuner + && oboeStream->getAudioApi() == oboe::AudioApi::AAudio) { + mLatencyTuner->tune(); + } + auto underrunCountResult = oboeStream->getXRunCount(); + int bufferSize = oboeStream->getBufferSizeInFrames(); + /** + * The following output can be seen by running a systrace. Tracing is preferable to logging + * inside the callback since tracing does not block. + * + * See https://developer.android.com/studio/profile/systrace-commandline.html + */ + if (Trace::isEnabled()) Trace::beginSection("numFrames %d, Underruns %d, buffer size %d", + numFrames, underrunCountResult.value(), bufferSize); + auto result = DefaultAudioStreamCallback::onAudioReady(oboeStream, audioData, numFrames); + if (Trace::isEnabled()) Trace::endSection(); + return result; +} \ No newline at end of file diff --git a/euphony/src/main/cpp/core/source/Base16.cpp b/euphony/src/main/cpp/core/source/Base16.cpp new file mode 100644 index 0000000..3866886 --- /dev/null +++ b/euphony/src/main/cpp/core/source/Base16.cpp @@ -0,0 +1,41 @@ +#include "../Base16.h" +#include + +using namespace Euphony; + +Base16::Base16(const HexVector &hexVectorSrc) +: hexVector(hexVectorSrc) { } + +std::string Base16::getBaseString() { + return hexVector.toString(); +} + +int Euphony::Base16::convertChar2Int(char source) const { + switch(source) { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + return source - '0'; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + return source - 'a' + 10; + default: + throw Base16Exception(); + } +} + +char Base16::convertInt2Char(int source) const { + const char hexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + + return hexArray[source]; +} + +const Euphony::HexVector &Euphony::Base16::getHexVector() const { + return hexVector; +} + + + + diff --git a/euphony/src/main/cpp/core/source/Base16Exception.cpp b/euphony/src/main/cpp/core/source/Base16Exception.cpp new file mode 100644 index 0000000..784430e --- /dev/null +++ b/euphony/src/main/cpp/core/source/Base16Exception.cpp @@ -0,0 +1,29 @@ +#include "../Definitions.h" +#include "../Base16Exception.h" + +using namespace Euphony; + +Base16Exception::Base16Exception() +: msg(BASE16_EXCEPTION_MSG), file(""), line(0) {} + +Base16Exception::Base16Exception(int _line, const std::string &_file) +: msg(BASE16_EXCEPTION_MSG), file(_file), line(_line) {} + +Base16Exception::~Base16Exception() throw() {} + +const char* Base16Exception::what() const throw() { + return msg.c_str(); +} + +const std::string &Base16Exception::MSG() const { + return msg; +} + +int Base16Exception::LINE() const { + return line; +} + +const std::string &Base16Exception::FILE() const { + return file; +} + diff --git a/euphony/src/main/cpp/core/source/Base2.cpp b/euphony/src/main/cpp/core/source/Base2.cpp new file mode 100644 index 0000000..00b23dd --- /dev/null +++ b/euphony/src/main/cpp/core/source/Base2.cpp @@ -0,0 +1,41 @@ +#include "../Base2.h" +#include + +using namespace Euphony; + +Base2::Base2(const HexVector &hexVectorSrc) +: hexVector(hexVectorSrc) { } + +std::string Base2::getBaseString() { + std::stringstream ss; + + for(u_int8_t hex : hexVector) { + ss << hexToBase2(hex); + } + + return ss.str(); +} + +const HexVector &Base2::getHexVector() const { + return hexVector; +} + +int Base2::convertChar2Int(char source) const { + return 0; +} + +char Base2::convertInt2Char(int source) const { + return 0; +} + +std::string Base2::hexToBase2(u_int8_t hex) { + std::string result; + + result.push_back(((hex & 0x8) >> 3) ? '1' : '0'); + result.push_back(((hex & 0x4) >> 2) ? '1' : '0'); + result.push_back(((hex & 0x2) >> 1) ? '1' : '0'); + result.push_back((hex & 0x1) ? '1' : '0'); + + return result; +} + diff --git a/euphony/src/main/cpp/core/source/DefaultCharset.cpp b/euphony/src/main/cpp/core/source/DefaultCharset.cpp new file mode 100644 index 0000000..d6c9213 --- /dev/null +++ b/euphony/src/main/cpp/core/source/DefaultCharset.cpp @@ -0,0 +1,10 @@ +#include "../DefaultCharset.h" +using namespace Euphony; + +HexVector DefaultCharset::encode(std::string src) { + return HexVector(src); +} + +std::string DefaultCharset::decode(const HexVector& src) { + return src.toString(); +} diff --git a/euphony/src/main/cpp/core/source/EuPIOscillator.cpp b/euphony/src/main/cpp/core/source/EuPIOscillator.cpp new file mode 100644 index 0000000..4712133 --- /dev/null +++ b/euphony/src/main/cpp/core/source/EuPIOscillator.cpp @@ -0,0 +1,51 @@ +// +// Created by designe on 20. 8. 25. +// + +#include "../EuPIOscillator.h" + +/* + * Frequencies Methods + * */ +void Euphony::EuPIOscillator::setFrequency(double frequency) { + mFrequency = frequency; + mPhaseIncrement.store((kTwoPi * mFrequency) / static_cast(mSampleRate)); +} + +void Euphony::EuPIOscillator::setSampleRate(int32_t sampleRate) { + mSampleRate = sampleRate; + mPhaseIncrement.store((kTwoPi * mFrequency) / static_cast(mSampleRate)); +} + +void Euphony::EuPIOscillator::setWaveOn(bool isWaveOn) { + mIsWaveOn.store(isWaveOn); +} + +void Euphony::EuPIOscillator::renderAudio(float *data, int32_t numFrames) { + if(mIsWaveOn) { + for(int i = 0; i < numFrames; ++i) { + data[i] = (float) (sin(mPhase) * mAmplitude); + mPhase += mPhaseIncrement; + if (mPhase > kTwoPi) mPhase -= kTwoPi; + } + if(mIsFirstWave != true) { + /* Crossfade in first */ + for(int i = 0; i < numFrames; i++) { + data[i] *= ((float)i / (float)numFrames); + } + } + mIsFirstWave.store(true); + mIsLastWave.store(false); + } else { + if(mIsLastWave != true) { + for(int i = 0; i < numFrames; ++i) { + data[i] = (sin(mPhase) * ((float)(numFrames-i) / (float)numFrames)); + mPhase += mPhaseIncrement; + if (mPhase > kTwoPi) mPhase -= kTwoPi; + } + mIsLastWave.store(true); + mIsFirstWave.store(false); + } + else memset(data, 0, sizeof(float) * numFrames); + } +} diff --git a/euphony/src/main/cpp/core/source/EuPIRenderer.cpp b/euphony/src/main/cpp/core/source/EuPIRenderer.cpp new file mode 100644 index 0000000..d5c2f08 --- /dev/null +++ b/euphony/src/main/cpp/core/source/EuPIRenderer.cpp @@ -0,0 +1,58 @@ +// +// Created by desig on 2020-08-15. +// + +#include "EuPIRenderer.h" + +using namespace Euphony; + +EuPIRenderer::EuPIRenderer(int32_t sampleRate, int32_t channelCount) + : mSampleRate(sampleRate), + mChannelCount(channelCount), + mOscillators(std::make_unique(channelCount)){ + + constexpr float amplitude = 1.0; + + // Set up the oscillators + for (int i = 0; i < mChannelCount; ++i) { + mOscillators[i].setFrequency(kStandardFrequency); + mOscillators[i].setSampleRate(mSampleRate); + mOscillators[i].setAmplitude(amplitude); + } +} + +void EuPIRenderer::renderAudio(float *audioData, int32_t numFrames) { + // Render each oscillator into its own channel + std::fill_n(mBuffer.get(), kBufferSize, 0); + for (int i = 0; i < mChannelCount; ++i) { + mOscillators[i].renderAudio(mBuffer.get(), numFrames); + for (int j = 0; j < numFrames; ++j) { + audioData[(j * mChannelCount) + i] = mBuffer[j]; + } + } +} + +void EuPIRenderer::setFrequency(double frequency) { + for(int i = 0; i< mChannelCount; ++i) { + mOscillators[i].setFrequency(frequency); + } +} + +void EuPIRenderer::tap(bool isDown) { + for (int i = 0; i < mChannelCount; ++i) { + mOscillators[i].setWaveOn(isDown); + } +} + +std::unique_ptr EuPIRenderer::makeStaticWave(int freq) { + std::unique_ptr waveArray = std::make_unique(kBufferSize); + float phase = 0.0; + double phaseIncrement = (kTwoPi * freq) / static_cast(kSampleRate); + for (int i = 0; i < kBufferSize; i++) { + waveArray[i] = sin(phase); + phase += phaseIncrement; + if (phase > kTwoPi) phase -= kTwoPi; + } + + return waveArray; +} \ No newline at end of file diff --git a/euphony/src/main/cpp/core/source/FFTModel.cpp b/euphony/src/main/cpp/core/source/FFTModel.cpp new file mode 100644 index 0000000..89a8e89 --- /dev/null +++ b/euphony/src/main/cpp/core/source/FFTModel.cpp @@ -0,0 +1,26 @@ +#include "../FFTModel.h" +#include "../Definitions.h" + +using namespace Euphony; + +FFTModel::FFTModel(int fftSizeSrc, int sampleRateSrc) +: fftSize(fftSizeSrc) +, sampleRate(sampleRateSrc) +{ } + +int FFTModel::getFFTSize() const { + return fftSize; +} + +void FFTModel::setFFTSize(int fftSizeSrc) { + fftSize = fftSizeSrc; +} + +int FFTModel::getSampleRate() const { + return sampleRate; +} + +void FFTModel::setSampleRate(int sampleRateSrc) { + sampleRate = sampleRateSrc; +} + diff --git a/euphony/src/main/cpp/core/source/FFTProcessor.cpp b/euphony/src/main/cpp/core/source/FFTProcessor.cpp new file mode 100644 index 0000000..69c2a6e --- /dev/null +++ b/euphony/src/main/cpp/core/source/FFTProcessor.cpp @@ -0,0 +1,54 @@ +// +// Created by opener on 20. 11. 30. +// + +#include "../FFTProcessor.h" +#include "../Definitions.h" + +Euphony::FFTProcessor::FFTProcessor(int fft_size, int samplerate) +: FFTModel(fft_size, samplerate) +, fftSize(fft_size) +, halfOfFFTSize(fft_size >> 1) +{ + config = kiss_fftr_alloc(fft_size, 0, nullptr, nullptr); + spectrum = (kiss_fft_cpx*) malloc(sizeof(kiss_fft_cpx) * (int)fft_size); + result = new float[halfOfFFTSize](); +} + +Euphony::FFTProcessor::~FFTProcessor() { + free(config); + free(spectrum); + delete result; +} + +inline float Euphony::FFTProcessor::shortToFloat(const short val) { + if( val < 0 ) + return val * ( 1 / 32768.0f ); + else + return val * ( 1 / 32767.0f ); +} + + +inline int Euphony::FFTProcessor::frequencyToIndex(const int freq) const { + return (int)(((halfOfFFTSize) + 1) * ((double)freq / (double)getSampleRate())); +} + +float* Euphony::FFTProcessor::makeSpectrum(short* src) { + int startIdx = frequencyToIndex(kStartSignalFrequency) - 1; + int lenHalfOfNumSamples = halfOfFFTSize; // spectrum size must be half of numSamples; + + kiss_fftr(config, src, spectrum); + + for(int i = startIdx; i <= lenHalfOfNumSamples; ++i) { + float re = shortToFloat(spectrum[i].r) * (float)fftSize; + float im = shortToFloat(spectrum[i].i) * (float)fftSize; + + result[i] = sqrtf(re * re + im * im) / (float)lenHalfOfNumSamples; + } + + return result; +} + +int Euphony::FFTProcessor::getResultSize() const { + return halfOfFFTSize + 1; +} diff --git a/euphony/src/main/cpp/core/source/FSK.cpp b/euphony/src/main/cpp/core/source/FSK.cpp new file mode 100644 index 0000000..c952e1b --- /dev/null +++ b/euphony/src/main/cpp/core/source/FSK.cpp @@ -0,0 +1,135 @@ +#include "../FSK.h" +#include "../FFTProcessor.h" +#include "../Definitions.h" +#include "../WaveBuilder.h" +#include "../Base16Exception.h" +#include "../Packet.h" +#include + +using namespace Euphony; + + +FSK::FSK() : fftModel(std::make_unique(kFFTSize, kSampleRate)){ } + +WaveList FSK::modulate(Packet* packet) +{ + return this->modulate(packet->toString()); +} + +WaveList FSK::modulate(string code) { + + vector> result; + + for (char c : code ) { + switch(c) { + case 'S': + result.push_back( + Wave::create() + .vibratesAt(kStartSignalFrequency) + .setSize(kBufferSize) + .setCrossfade(BOTH) + .build() + ); + break; + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': + result.push_back( + Wave::create() + .vibratesAt(kStandardFrequency + ((c - '0') * kFrequencyInterval)) + .setSize(kBufferSize) + .setCrossfade(BOTH) + .build() + ); + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + result.push_back( + Wave::create() + .vibratesAt(kStandardFrequency + ((c - 'a' + 10) * kFrequencyInterval)) + .setSize(kBufferSize) + .setCrossfade(BOTH) + .build() + ); + break; + default: + throw Base16Exception(); + } + } + + return result; +} + +int FSK::getMaxIdxFromSource(const float *fft_source) { + int maxIndex = 0; + float maxValue = 0; + const int startIdx = getStartFreqIdx(); + const int endIdx = getEndFreqIdx(); + for(int i = startIdx - 1; i < endIdx; i++) { + if(fft_source[i] > maxValue) { + maxValue = fft_source[i]; + maxIndex = i; + } + } + + return maxIndex - getStartFreqIdx(); +} + + +int FSK::getMaxIdxFromSource(const float *fft_source, const int baseSize, const int sampleRate, const int fftSize) { + int maxIndex = 0; + float maxValue = 0; + const int startIdx = getStartFreqIdx(sampleRate, fftSize); + const int endIdx = startIdx + baseSize; + for(int i = startIdx - 1; i < endIdx; i++) { + if(fft_source[i] > maxValue) { + maxValue = fft_source[i]; + maxIndex = i; + } + } + + return maxIndex - getStartFreqIdx(); +} + + +shared_ptr FSK::demodulate(const WaveList& waveList) { + HexVector hexVector = HexVector(waveList.size()); + + for(const auto& wave : waveList) { + auto vectorInt16Source = wave->getInt16Source(); + int16_t* int16Source = &vectorInt16Source[0]; + float *resultBuf = fftModel->makeSpectrum(int16Source); + hexVector.pushBack(getMaxIdxFromSource(resultBuf)); + } + + return std::make_shared(hexVector); +} + +std::shared_ptr FSK::demodulate(const float *source, int sourceLength, int bufferSize) { + int dataSize = sourceLength / bufferSize; + HexVector hexVector = HexVector(dataSize); + + WaveList waveList; + for(int i = 0; i < dataSize; i++) { + waveList.push_back(std::make_shared(source + (i * bufferSize), bufferSize)); + } + + return demodulate(waveList); +} + +int FSK::getStartFreqIdx() { + return std::lround((static_cast(static_cast(kStandardFrequency) / static_cast(kSampleRate >> 1)) * (kFFTSize >> 1))); +} + +int FSK::getStartFreqIdx(const int sampleRate, const int fftSize) { + return std::lround((static_cast(static_cast(kStandardFrequency) / static_cast(sampleRate >> 1)) * (fftSize >> 1))); +} + +int FSK::getEndFreqIdx() { + return std::lround((static_cast(static_cast(kStandardFrequency) / static_cast(kSampleRate >> 1)) * (kFFTSize >> 1))) + 16; +} + +int FSK::getEndFreqIdx(const int sampleRate, const int fftSize) { + return std::lround((static_cast(static_cast(kStandardFrequency) / static_cast(sampleRate >> 1)) * (fftSize >> 1))) + 16; +} diff --git a/euphony/src/main/cpp/core/source/HexVector.cpp b/euphony/src/main/cpp/core/source/HexVector.cpp new file mode 100644 index 0000000..1c98722 --- /dev/null +++ b/euphony/src/main/cpp/core/source/HexVector.cpp @@ -0,0 +1,91 @@ +#include "../HexVector.h" +#include +#include + +using namespace Euphony; + +HexVector::HexVector(int size) { + hexSource.reserve(size); +} + +HexVector::HexVector(const HexVector ©) { + setHexSource(copy.getHexSource()); +} + +HexVector::HexVector(const std::string& hexString) { + for(char c : hexString) { + switch(c) { + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': case '8': + case '9': default: + hexSource.push_back(c - '0'); + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + hexSource.push_back(10 + c - 'a'); + break; + } + } +} + +HexVector::HexVector(const std::vector &hexVectorCopy) { + setHexSource(hexVectorCopy); +} + + +HexVector::~HexVector() { + hexSource.clear(); +} + +void HexVector::pushBack(u_int8_t hexByte) { + if(hexByte <= 0x0f) { + hexSource.push_back(hexByte); + } else { + hexSource.push_back((hexByte >> 4)); + hexSource.push_back(hexByte & 0x0f); + } +} + +void HexVector::popBack() { + hexSource.pop_back(); +} + +std::string HexVector::toString() const{ + std::stringstream result; + + for(auto data : hexSource) { + result << std::hex << (int) data; + } + + return result.str(); +} + +const std::vector &HexVector::getHexSource() const { + return hexSource; +} + +void HexVector::setHexSource(const std::vector &hexSrc) { + this->clear(); + for(u_int8_t hex : hexSrc) { + this->pushBack(hex); + } +} + +int HexVector::getSize() const { + return hexSource.size(); +} + +std::__wrap_iter>::const_pointer> +HexVector::begin() const{ + return hexSource.begin(); +} + +std::__wrap_iter>::const_pointer> +HexVector::end() const{ + return hexSource.end(); +} + +void HexVector::clear(){ + hexSource.clear(); +} diff --git a/euphony/src/main/cpp/core/source/Packet.cpp b/euphony/src/main/cpp/core/source/Packet.cpp new file mode 100644 index 0000000..397a158 --- /dev/null +++ b/euphony/src/main/cpp/core/source/Packet.cpp @@ -0,0 +1,108 @@ +#include "../Packet.h" +#include "../PacketBuilder.h" +#include "../PacketErrorDetector.h" +#include "../BaseFactory.h" +#include +using namespace Euphony; + + +Packet::Packet() + : baseType(BaseType::BASE16), + payload(nullptr), + checksum(nullptr), + parityCode(nullptr), + isVerified(false) { +} + +Packet::Packet(const HexVector& source) + : baseType(BaseType::BASE16), + payload(nullptr), + checksum(nullptr), + parityCode(nullptr), + isVerified(false) { + payload = BaseFactory::create(baseType, source); + initialize(); +} + +Packet::Packet(const BaseType baseTypeSrc, const HexVector& source) +: baseType(baseTypeSrc), + payload(nullptr), + checksum(nullptr), + parityCode(nullptr), + isVerified(false) { + payload = BaseFactory::create(baseType, source); + initialize(); +} + + +PacketBuilder Packet::create() { + return PacketBuilder(); +} + +void Packet::initialize() { + //std::string errorCode = PacketErrorDetector::makeParityAndChecksum(payload->getBaseString()); + //this->checksum = BaseFactory::create(baseType, ) + this->checksum = BaseFactory::create( + baseType, + PacketErrorDetector::makeChecksum(payload->getHexVector()) + ); + this->parityCode = BaseFactory::create( + baseType, + PacketErrorDetector::makeParallelParity(payload->getHexVector()) + ); + + this->isVerified = true; +} + +void Packet::clear() { + this->checksum = nullptr; + this->parityCode = nullptr; + this->isVerified = false; + + payload = nullptr; +} + +std::string Packet::getPayloadStr() const { + return payload->getBaseString(); +} + +std::string Packet::toString() { + std::stringstream result; + + result << "S" << + payload->getBaseString() << + checksum->getBaseString() << + parityCode->getBaseString(); + + return result.str(); +} + +void Packet::setPayload(std::shared_ptr payloadSrc) { + payload = std::move(payloadSrc); + initialize(); +} + +void Packet::setPayload(const HexVector &source) { + payload = BaseFactory::create(baseType, source); + initialize(); +} + +std::shared_ptr Packet::getChecksum() { + return checksum; +} + +std::shared_ptr Packet::getParityCode() { + return parityCode; +} + +BaseType Packet::getBaseType() const { + return baseType; +} + +void Packet::setBaseType(BaseType baseTypeSrc) { + baseType = baseTypeSrc; + if(payload != nullptr) { + payload = BaseFactory::create(baseType, payload->getHexVector()); + initialize(); + } +} diff --git a/euphony/src/main/cpp/core/source/PacketBuilder.cpp b/euphony/src/main/cpp/core/source/PacketBuilder.cpp new file mode 100644 index 0000000..48d5d08 --- /dev/null +++ b/euphony/src/main/cpp/core/source/PacketBuilder.cpp @@ -0,0 +1,30 @@ +#include "../DefaultCharset.h" +#include "../ASCIICharset.h" +#include "../Definitions.h" +#include "../PacketBuilder.h" + +using namespace Euphony; + +PacketBuilder &Euphony::PacketBuilder::setPayload(const HexVector &source) { + packet.setPayload(source); + return *this; +} + +std::shared_ptr Euphony::PacketBuilder::build() { + return std::make_shared(packet); +} + +PacketBuilder &PacketBuilder::basedOnBase16() { + packet.setBaseType(BaseType::BASE16); + return *this; +} + +PacketBuilder &PacketBuilder::basedOnBase2() { + packet.setBaseType(BaseType::BASE2); + return *this; +} + +PacketBuilder &PacketBuilder::setPayloadWithASCII(std::string asciiSrc) { + packet.setPayload(HexVector(ASCIICharset().encode(asciiSrc))); + return *this; +} \ No newline at end of file diff --git a/euphony/src/main/cpp/core/source/PacketErrorDetector.cpp b/euphony/src/main/cpp/core/source/PacketErrorDetector.cpp new file mode 100644 index 0000000..9b07877 --- /dev/null +++ b/euphony/src/main/cpp/core/source/PacketErrorDetector.cpp @@ -0,0 +1,91 @@ +#include "../PacketErrorDetector.h" +#include + +using namespace Euphony; + +std::string PacketErrorDetector::makeParityAndChecksum(const HexVector& payload) { + char hexArray[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + + int evenParity[4] = {0,}; + int payloadSum = 0; + + for(int v : payload) { + evenParity[0] += ((0x8 & v) >> 3); + evenParity[1] += ((0x4 & v) >> 2); + evenParity[2] += ((0x2 & v) >> 1); + evenParity[3] += (0x1 & v); + payloadSum += v; + } + + payloadSum &= 0xF; + payloadSum = (~payloadSum + 1) & 0xF; + int evenParityResult = + (evenParity[0] & 0x1) * 8 + (evenParity[1] & 0x1) * 4 + + (evenParity[2] & 0x1) * 2 + (evenParity[3] & 0x1); + + std::stringstream result; + result << hexArray[payloadSum] << hexArray[evenParityResult]; + + return result.str(); +} + +std::string PacketErrorDetector::makeParityAndChecksum(std::string payload) { + HexVector hexVector = HexVector(payload); + return makeParityAndChecksum(hexVector); +} + +HexVector PacketErrorDetector::makeChecksum(const HexVector& payload) { + int payloadSum = 0; + + for(int v : payload) { + payloadSum += v; + } + + payloadSum &= 0xF; + payloadSum = (~payloadSum + 1) & 0xF; + + HexVector result(1); + result.pushBack(payloadSum); + + return result; +} + +HexVector PacketErrorDetector::makeParallelParity(const HexVector& payload) { + int evenParity[4] = {0,}; + + for(int v : payload) { + evenParity[0] += ((0x8 & v) >> 3); + evenParity[1] += ((0x4 & v) >> 2); + evenParity[2] += ((0x2 & v) >> 1); + evenParity[3] += (0x1 & v); + } + + int evenParityResult = + (evenParity[0] & 0x1) * 8 + (evenParity[1] & 0x1) * 4 + + (evenParity[2] & 0x1) * 2 + (evenParity[3] & 0x1); + + + HexVector result(1); + result.pushBack(evenParityResult); + + return result; +} + +bool PacketErrorDetector::verifyChecksum(const HexVector& payload, int checksum) { + HexVector checksumResult = makeChecksum(payload); + + if(checksumResult.getHexSource()[0] != checksum) + return false; + else + return true; +} + +bool PacketErrorDetector::verifyParallelParity(const HexVector& payload, int parity) { + HexVector parityResult = makeParallelParity(payload); + + if(parityResult.getHexSource()[0] != parity) + return false; + else + return true; +} diff --git a/euphony/src/main/cpp/core/source/TxEngine.cpp b/euphony/src/main/cpp/core/source/TxEngine.cpp new file mode 100644 index 0000000..675ea84 --- /dev/null +++ b/euphony/src/main/cpp/core/source/TxEngine.cpp @@ -0,0 +1,355 @@ +// +// Created by desig on 2020-08-15. +// +#include + +#include +#include +#include "../Base2.h" +#include "../ModemFactory.h" +#include "../PacketBuilder.h" +#include "../TxEngine.h" +#include "../EuPIRenderer.h" +#include "../AudioStreamCallback.h" +#include "../WaveRenderer.h" + +using namespace Euphony; + +class TxEngine::TxEngineImpl : public IRestartable{ +public: + std::mutex mLock; + std::shared_ptr mStream; + oboe::AudioStreamBuilder mStreamBuilder; + std::unique_ptr mCallback; + std::shared_ptr mAudioSource = nullptr; + bool mIsLatencyDetectionSupported = false; + + double eupiFreq; + int32_t mDeviceId = oboe::Unspecified; + int32_t mChannelCount = oboe::Unspecified; + oboe::AudioApi mAudioApi = oboe::AudioApi::Unspecified; + + std::shared_ptr txPacket = nullptr; + std::shared_ptr mModem = nullptr; + ModulationType mModulationType; + BaseType mBaseCodingType; + ModeType mModeType; + Status mStatus; + + TxEngineImpl() + : mModulationType(ModulationType::FSK) + , mBaseCodingType(BaseType::BASE16) + , mModeType(ModeType::DEFAULT) + , mStatus(STOP){ + createCallback(); + setModulation(ModulationType::FSK); + //start(); + } + + virtual ~TxEngineImpl() = default; + + void createCallback() { + mCallback = std::make_unique(*this); + } + + oboe::Result createPlaybackStream() { + return mStreamBuilder.setSharingMode(oboe::SharingMode::Exclusive) + ->setPerformanceMode(oboe::PerformanceMode::LowLatency) + ->setFormat(oboe::AudioFormat::Float) + ->setCallback(mCallback.get()) + ->setChannelCount(kChannelCount) + ->setSampleRate(kSampleRate) + ->setDeviceId(mDeviceId) + ->openStream(mStream); + } + + std::shared_ptr createAudioSource(ModeType modeType) { + switch(modeType) { + default: + case ModeType::DEFAULT: { + auto modulationResult = mModem->modulate(txPacket->toString()); + return std::make_shared(modulationResult, kChannelCount); + } + case ModeType::EUPI: + return std::make_shared(kSampleRate, kChannelCount); + } + } + + void setPerformance(oboe::PerformanceMode mode) { + mStreamBuilder.setPerformanceMode(mode)->openStream(mStream); + } + + void restart() override { + start(); + } + + void stop() { + std::lock_guard lock(mLock); + if(mStream) { + mStream->stop(); + mStatus = STOP; + } + } + + oboe::Result reopenStream() { + { + // Stop and close in case not already closed. + std::lock_guard lock(mLock); + if (mStream) { + mStream->stop(); + mStream->close(); + } + } + return start(); + } + + oboe::Result start() { + std::lock_guard lock(mLock); + auto result = createPlaybackStream(); + if(result == oboe::Result::OK) { + mCallback->setSource(std::dynamic_pointer_cast(mAudioSource)); + mStream->start(); + mIsLatencyDetectionSupported = (mStream->getTimestamp((CLOCK_MONOTONIC)) != oboe::Result::ErrorUnimplemented); + mStatus = RUNNING; + LOGD("EUPHONY / EpnyTxEngine: %s", oboe::convertToText(result)); + } else { + mStatus = STOP; + LOGE("Error creating playback stream. Error: %s", oboe::convertToText(result)); + } + + return result; + } + + void setCode(std::string data) { + txPacket = Packet::create() + .setPayloadWithASCII(std::move(data)) + .basedOnBase16() + .build(); + + txPacket->setBaseType(mBaseCodingType); + + if (mAudioSource != nullptr) { + auto waveList = mModem->modulate(txPacket->toString()); + std::dynamic_pointer_cast(mAudioSource)->setWaveList(waveList); + } + } + + void setCodingType(int codingTypeSrc) { + switch(codingTypeSrc) { + case 0: + mBaseCodingType = BaseType::BASE2; + break; + default: + case 1: + mBaseCodingType = BaseType::BASE16; + break; + } + + if(txPacket != nullptr) { + txPacket->setBaseType(mBaseCodingType); + } + } + + void setMode(int modeSrc) { + switch(modeSrc) { + case 0: + default: + mModeType = ModeType::DEFAULT; + break; + case 1: + if(mModeType == ModeType::EUPI) + return; + + mModeType = ModeType::EUPI; + break; + } + + + mAudioSource = createAudioSource(mModeType); + } + + void setModulation(int modulationTypeSrc) { + switch(modulationTypeSrc) { + case 0: + default: + mModulationType = ModulationType::FSK; + break; + } + + mModem = ModemFactory::create(mModulationType); + } + + void setModulation(ModulationType modulationTypeSrc) { + switch(modulationTypeSrc) { + case ModulationType::FSK: + default: + mModulationType = ModulationType::FSK; + break; + } + + mModem = ModemFactory::create(mModulationType); + } + + void setEupiFrequency(double freq) { + eupiFreq = freq; + } + + void setBufferSizeInBursts(int32_t numBursts) + { + std::lock_guard lock(mLock); + if (!mStream) return; + + mIsLatencyDetectionSupported = false; + mCallback->setBufferTuneEnabled(numBursts == kBufferSizeAutomatic); + auto result = mStream->setBufferSizeInFrames( + numBursts * mStream->getFramesPerBurst()); + if (result) { + LOGD("Buffer size successfully changed to %d", result.value()); + } else { + LOGW("Buffer size could not be changed, %d", result.error()); + } + } + + double getCurrentOutputLatencyMillis() { + if (!mIsLatencyDetectionSupported) return -1.0; + + std::lock_guard lock(mLock); + if (!mStream) return -1.0; + + // Get the time that a known audio frame was presented for playing + auto result = mStream->getTimestamp(CLOCK_MONOTONIC); + double outputLatencyMillis = -1; + const int64_t kNanosPerMillisecond = 1000000; + if (result == oboe::Result::OK) { + oboe::FrameTimestamp playedFrame = result.value(); + // Get the write index for the next audio frame + int64_t writeIndex = mStream->getFramesWritten(); + // Calculate the number of frames between our known frame and the write index + int64_t frameIndexDelta = writeIndex - playedFrame.position; + // Calculate the time which the next frame will be presented + int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / (mStream->getSampleRate()); + int64_t nextFramePresentationTime = playedFrame.timestamp + frameTimeDelta; + // Assume that the next frame will be written at the current time + using namespace std::chrono; + int64_t nextFrameWriteTime = + duration_cast(steady_clock::now().time_since_epoch()).count(); + // Calculate the latency + outputLatencyMillis = static_cast(nextFramePresentationTime - nextFrameWriteTime) + / kNanosPerMillisecond; + } else { + LOGE("Error calculating latency: %s", oboe::convertToText(result.error())); + } + + return outputLatencyMillis; + } + + bool isLatencyDetectionSupported() const { + return mIsLatencyDetectionSupported; + } +}; + +TxEngine::TxEngine() +: pImpl(std::make_unique()) { } + + +TxEngine::~TxEngine() = default; + + +void TxEngine::tap(bool isDown) { + if(pImpl->mAudioSource != nullptr) + pImpl->mAudioSource->tap(isDown); +} + +void TxEngine::tapCount(bool isDown, int count) { + if(pImpl->mAudioSource != nullptr) + std::dynamic_pointer_cast(pImpl->mAudioSource)->tapCount(isDown, count); +} + +void TxEngine::setEupiFrequency(double freq) { + pImpl->setEupiFrequency(freq); + + if(pImpl->mAudioSource != nullptr) + std::dynamic_pointer_cast(pImpl->mAudioSource)->setFrequency(freq); +} + +void TxEngine::stop() { + pImpl->stop(); +} + +void TxEngine::start() { + pImpl->start(); +} + +void TxEngine::setCode(std::string data) { + pImpl->setCode(std::move(data)); +} + +void TxEngine::setCodingType(int codingTypeSrc) { + pImpl->setModulation(codingTypeSrc); +} + +void TxEngine::setMode(int modeSrc) { + pImpl->setMode(modeSrc); +} + +void TxEngine::setModulation(int modulationTypeSrc) { + pImpl->setModulation(modulationTypeSrc); +} + +bool TxEngine::isLatencyDetectionSupported() { + return pImpl->isLatencyDetectionSupported(); +} + +void TxEngine::setAudioApi(oboe::AudioApi audioApi) { + pImpl->mAudioApi = audioApi; +} + +void TxEngine::setPerformance(oboe::PerformanceMode mode) { + pImpl->setPerformance(mode); +} + +void TxEngine::setChannelCount(int channelCount) { + pImpl->mChannelCount = channelCount; +} + +void TxEngine::setDeviceId(int32_t deviceId) { + pImpl->mDeviceId = deviceId; +} + +int TxEngine::getFramesPerBursts() { + return pImpl->mStream->getFramesPerBurst(); +} + +void TxEngine::setBufferSizeInBursts(int32_t numBursts) { + pImpl->setBufferSizeInBursts(numBursts); +} + +double TxEngine::getCurrentOutputLatencyMillis() { + return pImpl->getCurrentOutputLatencyMillis(); +} + +Status Euphony::TxEngine::getStatus() { + return pImpl->mStatus; +} + +std::string TxEngine::getCode() { + return pImpl->txPacket->getPayloadStr(); +} + +std::string TxEngine::getGenCode() { + return pImpl->txPacket->toString(); +} + +float *Euphony::TxEngine::getGenWaveSource() { + if(pImpl->mAudioSource != nullptr) + return std::dynamic_pointer_cast(pImpl->mAudioSource)->getWaveSource(); + else + return nullptr; +} + +int Euphony::TxEngine::getGenWaveSourceSize() { + if(pImpl->mAudioSource != nullptr) + return std::dynamic_pointer_cast(pImpl->mAudioSource)->getWaveSourceSize(); + else + return 0; +} diff --git a/euphony/src/main/cpp/core/source/Wave.cpp b/euphony/src/main/cpp/core/source/Wave.cpp new file mode 100644 index 0000000..3d1f9d6 --- /dev/null +++ b/euphony/src/main/cpp/core/source/Wave.cpp @@ -0,0 +1,143 @@ +// +// Created by designe on 20. 9. 16. +// + +#include "../Definitions.h" +#include "../Wave.h" +#include "../WaveBuilder.h" + +using namespace Euphony; + +Euphony::Wave::Wave() +: mHz(0), +mSize(0), +crossfadeType(NONE) +{} + +Euphony::Wave::Wave(int hz, int bufferSize) +: mHz(hz), +mSize(bufferSize), +crossfadeType(NONE) +{ + oscillate(); +} + +Wave::Wave(const float *src, int bufferSize) +: mHz(0) +, mSize(bufferSize) +, crossfadeType(NONE) +{ + for(int i = 0; i < bufferSize; ++i) { + mSource.push_back(src[i]); + } +} + +Euphony::Wave::Wave(const Wave& copy) +: mHz(copy.mHz), +mSize(copy.mSize), +crossfadeType(copy.crossfadeType) +{ + oscillate(); +} + +WaveBuilder Euphony::Wave::create() { + return WaveBuilder(); +} + +void Euphony::Wave::updatePhaseIncrement(int hz) { + mPhaseIncrement.store((kTwoPi * hz) / static_cast(kSampleRate)); +} + +void Euphony::Wave::oscillate() { + if(this->mHz > 0 && this->mSize > 0) { + updatePhaseIncrement(this->mHz); + + float phase = 0.0; + + for(int i = 0; i < this->mSize; ++i) { + mSource.push_back(sin(phase)); + phase += mPhaseIncrement; + if(phase > kTwoPi) phase -= kTwoPi; + } + + if(crossfadeType != NONE) { + for (int i = 0; i < kBufferFadeLength; ++i) { + float miniWindow = static_cast(i) / static_cast(kBufferFadeLength); + switch (crossfadeType) { + case BOTH: + mSource[i] *= miniWindow; + mSource[this->mSize - 1 - i] *= miniWindow; + break; + case END: + mSource[this->mSize - 1 - i] *= miniWindow; + break; + case FRONT: + mSource[i] *= miniWindow; + break; + default: + continue; + } + } + } + } +} + +void Euphony::Wave::oscillate(int hz, int size) { + this->setHz(hz); + this->setSize(size); + this->oscillate(); +} + +int Euphony::Wave::getHz() const { + return mHz; +} + +void Euphony::Wave::setHz(int hz) { + mHz = hz; + this->updatePhaseIncrement(hz); +} + +int Euphony::Wave::getSize() const { + return mSize; +} + +void Euphony::Wave::setSize(int size) { + mSize = size; + mSource.reserve(size); +} + +std::vector Euphony::Wave::getSource() const { + std::vector result; + result.reserve(mSource.capacity()); + result.assign(mSource.begin(), mSource.end()); + return result; +} + +std::vector Euphony::Wave::getInt16Source() { + std::vector result; + + if(mSource.empty()) { + return result; + } + + result.reserve(mSource.size()); + + for(float src : mSource) { + result.push_back(convertFloat2Int16(src)); + } + + return result; +} + +void Euphony::Wave::setSource(const std::vector &source) { + mSource = source; +} + +int16_t Euphony::Wave::convertFloat2Int16(float source) { + return static_cast(SHRT_MAX) * source; +} + +void Wave::setCrossfade(CrossfadeType crossfadeType) { + this->crossfadeType = crossfadeType; +} + diff --git a/euphony/src/main/cpp/core/source/WaveBuilder.cpp b/euphony/src/main/cpp/core/source/WaveBuilder.cpp new file mode 100644 index 0000000..213e52e --- /dev/null +++ b/euphony/src/main/cpp/core/source/WaveBuilder.cpp @@ -0,0 +1,32 @@ +#include "../WaveBuilder.h" + +using namespace Euphony; + +WaveBuilder& WaveBuilder::vibratesAt(int hz) { + wave.setHz(hz); + return *this; +} + +WaveBuilder& WaveBuilder::setSize(int size) { + wave.setSize(size); + return *this; +} + +WaveBuilder& WaveBuilder::setCrossfade(CrossfadeType type) { + wave.setCrossfade(type); + return *this; +} + +std::shared_ptr WaveBuilder::build() { + if(wave.getSize() > 0 && wave.getHz() > 0) { + wave.oscillate(); + } + + return std::make_shared(wave); +} + + + + + + diff --git a/euphony/src/main/cpp/core/source/WaveRenderer.cpp b/euphony/src/main/cpp/core/source/WaveRenderer.cpp new file mode 100644 index 0000000..870a8f4 --- /dev/null +++ b/euphony/src/main/cpp/core/source/WaveRenderer.cpp @@ -0,0 +1,82 @@ +#include + +#include "../WaveRenderer.h" + +using namespace Euphony; + +WaveRenderer::WaveRenderer(WaveList waveListSrc, int32_t channelCountSrc) +: channelCount (channelCountSrc) +, waveSourceSize(0) +, readFrameIndex(0) +, renderIndex(0) +, renderTotalCount(0) +{ + setWaveList(std::move(waveListSrc)); +} + +void WaveRenderer::renderAudio(float *targetData, int32_t numFrames) { + if(isWaveOn) { + int64_t framesToRenderFromData = numFrames; + const float *waveSrcData = waveSource.get(); + + if (readFrameIndex + numFrames >= waveSourceSize) { + framesToRenderFromData = waveSourceSize - readFrameIndex; + } + + for (int i = 0; i < framesToRenderFromData; ++i) { + for (int j = 0; j < channelCount; ++j) { + targetData[(i * channelCount) + j] = waveSrcData[readFrameIndex]; + } + if (++readFrameIndex >= waveSourceSize){ + readFrameIndex = 0; + if(renderTotalCount > 0) { + if(++renderIndex >= renderTotalCount) + isWaveOn.store(false); + } + } + } + + if(framesToRenderFromData < numFrames){ + renderSilence(&targetData[framesToRenderFromData], numFrames * channelCount); + } + + } else { + renderSilence(targetData, numFrames * channelCount); + } +} + +void WaveRenderer::tap(bool isDown) { + isWaveOn.store(isDown); +} + +void WaveRenderer::tapCount(bool isDown, int count) { + isWaveOn.store(isDown); + renderIndex = 0; + renderTotalCount = count; +} + +float* WaveRenderer::getWaveSource() { + return waveSource.get(); +} + +int32_t WaveRenderer::getWaveSourceSize() const { + return waveSourceSize; +} + +void WaveRenderer::renderSilence(float *targetData, int32_t numFrames) { + for(int i = 0; i < numFrames; ++i) { + targetData[i] = 0; + } +} + +void WaveRenderer::setWaveList(WaveList waveListSrc) { + waveSourceSize = waveListSrc.size() * kBufferSize; + waveSource = std::make_unique(waveSourceSize); + std::fill_n(waveSource.get(), waveSourceSize, 0); + for(int i = 0; i < waveListSrc.size(); i++) { + auto waveSrc = waveListSrc[i]->getSource(); + for(int j = 0; j < kBufferSize; j++) { + waveSource[j + (i * kBufferSize)] = waveSrc[j]; + } + } +} diff --git a/euphony/src/main/cpp/debug-helper/Log.h b/euphony/src/main/cpp/debug-helper/Log.h new file mode 100644 index 0000000..f1c5a25 --- /dev/null +++ b/euphony/src/main/cpp/debug-helper/Log.h @@ -0,0 +1,22 @@ +// +// Created by desig on 2020-07-30. +// + +#ifndef EUPHONY_LOG_H +#define EUPHONY_LOG_H +#include + +#define LOG_TAG "NDK_TEST" +#define LOGUNK(...) __android_log_print(ANDROID_LOG_UNKNOWN,LOG_TAG,__VA_ARGS__) +#define LOGDEF(...) __android_log_print(ANDROID_LOG_DEFAULT,LOG_TAG,__VA_ARGS__) +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#define LOGF(...) __android_log_print(ANDROID_FATAL_ERROR,LOG_TAG,__VA_ARGS__) +#define LOGS(...) __android_log_print(ANDROID_SILENT_ERROR,LOG_TAG,__VA_ARGS__) + +#define ASSERT(cond, ...) if (!(cond)) {__android_log_assert(#cond, MODULE_NAME, __VA_ARGS__);} + +#endif //EUPHONY_LOG_H diff --git a/euphony/src/main/cpp/debug-helper/Trace.cpp b/euphony/src/main/cpp/debug-helper/Trace.cpp new file mode 100644 index 0000000..60ea454 --- /dev/null +++ b/euphony/src/main/cpp/debug-helper/Trace.cpp @@ -0,0 +1,73 @@ +// +// Created by opener on 20. 8. 24. +// + +#include +#include "Log.h" +#include +#include "Trace.h" + +static const int TRACE_MAX_SECTION_NAME_LENGTH = 100; + +// Tracing functions +static void *(*ATrace_beginSection)(const char *sectionName); + +static void *(*ATrace_endSection)(void); + +static bool *(*ATrace_isEnabled)(void); + +typedef void *(*fp_ATrace_beginSection)(const char *sectionName); + +typedef void *(*fp_ATrace_endSection)(void); + +typedef bool *(*fp_ATrace_isEnabled)(void); + +bool Trace::is_enabled_ = false; +bool Trace::has_error_been_shown_ = false; + +void Trace::beginSection(const char *fmt, ...) { + + if (is_enabled_) { + static char buff[TRACE_MAX_SECTION_NAME_LENGTH]; + va_list args; + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + ATrace_beginSection(buff); + } else if (!has_error_been_shown_) { + LOGE("Tracing is either not initialized (call Trace::initialize()) " + "or not supported on this device"); + has_error_been_shown_ = true; + } +} + +void Trace::endSection() { + + if (is_enabled_) { + ATrace_endSection(); + } +} + +void Trace::initialize() { + + // Using dlsym allows us to use tracing on API 21+ without needing android/trace.h which wasn't + // published until API 23 + void *lib = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL); + if (lib == nullptr) { + LOGE("Could not open libandroid.so to dynamically load tracing symbols"); + } else { + ATrace_beginSection = + reinterpret_cast( + dlsym(lib, "ATrace_beginSection")); + ATrace_endSection = + reinterpret_cast( + dlsym(lib, "ATrace_endSection")); + ATrace_isEnabled = + reinterpret_cast( + dlsym(lib, "ATrace_isEnabled")); + + if (ATrace_isEnabled != nullptr && ATrace_isEnabled()) { + is_enabled_ = true; + } + } +} \ No newline at end of file diff --git a/euphony/src/main/cpp/debug-helper/Trace.h b/euphony/src/main/cpp/debug-helper/Trace.h new file mode 100644 index 0000000..1d8d99a --- /dev/null +++ b/euphony/src/main/cpp/debug-helper/Trace.h @@ -0,0 +1,22 @@ +// +// Created by opener on 20. 8. 24. +// + +#ifndef EUPHONY_TRACE_H +#define EUPHONY_TRACE_H + + +class Trace { +public: + static void beginSection(const char *format, ...); + static void endSection(); + static bool isEnabled() { return is_enabled_; } + static void initialize(); + +private: + static bool is_enabled_; + static bool has_error_been_shown_; +}; + + +#endif //EUPHONY_TRACE_H diff --git a/euphony/src/main/cpp/native-connector.cpp b/euphony/src/main/cpp/native-connector.cpp new file mode 100644 index 0000000..2cdcedc --- /dev/null +++ b/euphony/src/main/cpp/native-connector.cpp @@ -0,0 +1,325 @@ +// +// Created by opener on 20. 8. 25. +// + +#include +#include +#include "debug-helper/Log.h" +#include "core/TxEngine.h" + +using namespace Euphony; + +extern "C" { + JNIEXPORT jlong JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1createEngine(JNIEnv *env, jobject thiz) { + auto engine = new(std::nothrow) TxEngine(); + return reinterpret_cast(engine); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1deleteEngine(JNIEnv *env, jobject thiz, + jlong engine_handle) { + delete reinterpret_cast(engine_handle); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setToneOn(JNIEnv *env, jobject thiz, + jlong engine_handle, + jboolean is_tone_on) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->tap(is_tone_on); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setCountToneOn(JNIEnv *env, jobject thiz, jlong engine_handle, + jboolean is_tone_on, jint count) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->tapCount(is_tone_on, count); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setCode(JNIEnv *env, jobject thiz, jlong engine_handle, + jstring data) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + const char* inputData = env->GetStringUTFChars(data, 0); + const std::string inputStr = std::string(inputData); + + engine->setCode(inputStr); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setCodingType(JNIEnv *env, jobject thiz, jlong engine_handle, + jint type) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setCodingType(type); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setMode(JNIEnv *env, jobject thiz, jlong engine_handle, + jint mode) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setMode(mode); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setModulation(JNIEnv *env, jobject thiz, jlong engine_handle, + jint modulation_type) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setModulation(modulation_type); + } + + JNIEXPORT jstring JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1getCode(JNIEnv *env, jobject thiz, jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return nullptr; + } + + return env->NewStringUTF(engine->getCode().c_str()); + } + + JNIEXPORT jstring JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1getGenCode(JNIEnv *env, jobject thiz, jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return nullptr; + } + + return env->NewStringUTF(engine->getGenCode().c_str()); + } + + JNIEXPORT jfloatArray JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1getGenWaveSource(JNIEnv *env, jobject thiz, + jlong engine_handle) { + jfloatArray result; + + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return nullptr; + } + + float* genWaveSource = engine->getGenWaveSource(); + int genWaveSourceSize = engine->getGenWaveSourceSize(); + + result = env->NewFloatArray(genWaveSourceSize); + env->SetFloatArrayRegion(result, 0, genWaveSourceSize, genWaveSource); + + return result; + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1start(JNIEnv *env, jobject thiz, + jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->start(); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1stop(JNIEnv *env, jobject thiz, + jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->stop(); + } + + JNIEXPORT jint JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1getStatus(JNIEnv *env, jobject thiz, + jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if (engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return 2; + } + + switch(engine->getStatus()) { + case RUNNING: + return 0; + case STOP: + return 1; + } + + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setAudioApi(JNIEnv *env, jobject thiz, + jlong engine_handle, + jint audio_api) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + auto api = static_cast(audio_api); + engine->setAudioApi(api); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setAudioDeviceId(JNIEnv *env, jobject thiz, + jlong engine_handle, + jint device_id) { + auto engine = reinterpret_cast (engine_handle); + if (engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setDeviceId(device_id); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setAudioFrequency(JNIEnv *env, jobject thiz, + jlong engine_handle, + jdouble frequency) { + auto engine = reinterpret_cast (engine_handle); + if (engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setEupiFrequency(frequency); + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setChannelCount(JNIEnv *env, jobject thiz, + jlong engine_handle, + jint channel_count) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setChannelCount(channel_count); + + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setBufferSizeInBursts(JNIEnv *env, jobject thiz, + jlong engine_handle, + jint buffer_size_in_bursts) { + + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + engine->setBufferSizeInBursts(buffer_size_in_bursts); + } + + + JNIEXPORT jdouble JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1getCurrentOutputLatencyMillis(JNIEnv *env, + jobject thiz, + jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return static_cast(-1.0); + } + + return static_cast(engine->getCurrentOutputLatencyMillis()); + } + + JNIEXPORT jboolean JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1isLatencyDetectionSupported(JNIEnv *env, + jobject thiz, + jlong engine_handle) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return JNI_FALSE; + } + + return (engine->isLatencyDetectionSupported()) ? JNI_TRUE : JNI_FALSE; + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setPerformance(JNIEnv *env, jobject thiz, + jlong engine_handle, + jint performance_level) { + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return; + } + + switch(performance_level) { + case 0: + engine->setPerformance(oboe::PerformanceMode::PowerSaving); + break; + case 1: + engine->setPerformance(oboe::PerformanceMode::None); + break; + case 2: + default: + engine->setPerformance(oboe::PerformanceMode::LowLatency); + break; + } + } + + JNIEXPORT void JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1setDefaultStreamValues(JNIEnv *env, jobject thiz, + jint sample_rate, + jint frames_per_burst) { + oboe::DefaultStreamValues::SampleRate = (int32_t) sample_rate; + oboe::DefaultStreamValues::FramesPerBurst = (int32_t) frames_per_burst; + } + + JNIEXPORT jint JNICALL + Java_co_euphony_tx_EuTxNativeConnector_native_1getFramesPerBursts(JNIEnv *env, jobject thiz, + jlong engine_handle) { + + auto engine = reinterpret_cast (engine_handle); + if(engine == nullptr) { + LOGE("Engine handle is invalid, call createHandle() to create a new one"); + return -1; + } + + return engine->getFramesPerBursts(); + + } +} \ No newline at end of file diff --git a/euphony/src/main/cpp/native-legacy.cpp b/euphony/src/main/cpp/native-legacy.cpp new file mode 100644 index 0000000..22a1934 --- /dev/null +++ b/euphony/src/main/cpp/native-legacy.cpp @@ -0,0 +1,157 @@ +// +// Created by desig on 2020-07-16. +// + +#include +#include +#include "arms/kiss_fftr.h" +#include +#include +#include + +#define MAX_SHORT 32767.0f + +static inline float scale( kiss_fft_scalar val ) +{ + if( val < 0 ) + return val * ( 1 / 32768.0f ); + else + return val * ( 1 / 32767.0f ); +} + +struct KissFFT +{ + kiss_fftr_cfg config; + kiss_fft_cpx* spectrum; + int numSamples; +}; + +extern "C" JNIEXPORT jlong +Java_co_euphony_rx_KissFFT_create(JNIEnv *env, jobject thiz, jint numSamples) { + KissFFT* fft = new KissFFT(); + + fft->config = kiss_fftr_alloc(numSamples,0,nullptr,nullptr); + fft->spectrum = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * (int)numSamples); + fft->numSamples = numSamples; + return (jlong)fft; +} + +/* + * Class: euphony_lib_receiver_KissFFT + * Method: destroy + * Signature: (J)V + */ +extern "C" +JNIEXPORT void JNICALL +Java_co_euphony_rx_KissFFT_destroy(JNIEnv *env, jobject thiz, jlong handle) { + KissFFT* fft = (KissFFT*)handle; + free(fft->config); + free(fft->spectrum); + free(fft); +} + +extern "C" +JNIEXPORT void JNICALL +Java_co_euphony_rx_KissFFT_doSpectrum(JNIEnv *env, jobject thiz, jlong handle, jobject source, + jint sample_idx, jlong mag_address, jlong dbfs_address) { + KissFFT* fft = (KissFFT*)handle; + kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetDirectBufferAddress( source ); + float* mag = (float*) mag_address; + float* dbfs = (float*) dbfs_address; + + kiss_fftr( fft->config, samples, fft->spectrum ); + + float re = scale(fft->spectrum[sample_idx].r) * fft->numSamples; + float im = scale(fft->spectrum[sample_idx].i) * fft->numSamples; + + *mag = sqrtf( re * re + im * im ) / (fft->numSamples / 2); + *dbfs = 10 * log10(4 * (re * re + im * im) / (fft->numSamples * fft->numSamples)); +} + +extern "C" +JNIEXPORT void JNICALL +Java_co_euphony_rx_KissFFT_doSpectrums(JNIEnv *env, jobject thiz, jlong handle, + jobject source, jobject target) { + KissFFT* fft = (KissFFT*)handle; + kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetDirectBufferAddress( source ); + float* spectrum = (float*)env->GetDirectBufferAddress( target ); + + + kiss_fftr( fft->config, samples, fft->spectrum ); //<--- fatal signal 11 (SIGSEV) at 0x00000400 + + int len = fft->numSamples / 2 + 1; // <=--- <--- fatal signal 11 (SIGSEV) at 0x00000408 + int len_halfOfNumSamples = fft->numSamples / 2; + // int len = 6; // <-- for debugging + int start = len * (17500.0 / 22050.0); + for( int i = start; i < len; i++ ) + { + float re = scale(fft->spectrum[i].r) * fft->numSamples; + float im = scale(fft->spectrum[i].i) * fft->numSamples; + + // mag(k) = 2 * SQUARE_ROOT(re * re + im * im) / number of samples + spectrum[i] = sqrtf(re*re + im*im) / len_halfOfNumSamples; + + /* + if( i > 0 ) spectrum[i] = sqrtf(re*re + im*im) / (fft->numSamples / 2); + else spectrum[i] = sqrtf(re*re + im*im) / (fft->numSamples); + */ + } +} + + +/* + * Class: euphony_lib_receiver_KissFFT + * Method: spectrum_for_phase + * Signature: (JLjava/nio/ShortBuffer;Ljava/nio/FloatBuffer;)V + */ +extern "C" +JNIEXPORT void JNICALL +Java_co_euphony_rx_KissFFT_spectrum_1for_1phase(JNIEnv *env, jobject thiz, jlong handle, + jobject source, jobject target) { + KissFFT* fft = (KissFFT*)handle; + kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetDirectBufferAddress( source ); + float* spectrum = (float*)env->GetDirectBufferAddress( target ); + + kiss_fftr( fft->config, samples, fft->spectrum ); + + int len = fft->numSamples / 2 + 1; + int start = (int)(len * (16500.0 / 22050.0)); + + for( int i = start; i < len; i++ ) + { + float re = scale(fft->spectrum[i].r) * fft->numSamples; + float im = scale(fft->spectrum[i].i) * fft->numSamples; + + spectrum[i] = atan2(im,re) * 180.0 / 3.141592; + } +} + +/* + * Class: euphony_lib_receiver_KissFFT + * Method: getRealPart + * Signature: (JLjava/nio/ShortBuffer;)V + */ +extern "C" +JNIEXPORT void JNICALL +Java_co_euphony_rx_KissFFT_getRealPart(JNIEnv *env, jobject thiz, jlong handle, + jobject real) { + KissFFT* fft = (KissFFT*)handle; + short* target = (short*)env->GetDirectBufferAddress(real); + for( int i = 0; i < fft->numSamples / 2; i++ ) + target[i] = fft->spectrum[i].r; +} + +/* + * Class: euphony_lib_receiver_KissFFT + * Method: getImagPart + * Signature: (JLjava/nio/ShortBuffer;)V + */ +extern "C" +JNIEXPORT void JNICALL +Java_co_euphony_rx_KissFFT_getImagePart(JNIEnv *env, jobject thiz, jlong handle, + jobject imag) { + KissFFT* fft = (KissFFT*)handle; + short* target = (short*)env->GetDirectBufferAddress(imag); + for( int i = 0; i < fft->numSamples / 2; i++ ) + target[i] = fft->spectrum[i].i; +} \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/CMakeLists.txt b/euphony/src/main/cpp/tests/CMakeLists.txt new file mode 100644 index 0000000..d5c9eba --- /dev/null +++ b/euphony/src/main/cpp/tests/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 3.4.1) + +set(TEST_EUPHONY testEuphony) + +# Include GoogleTest library +set (GOOGLETEST_ROOT ${ANDROID_NDK}/sources/third_party/googletest) +add_library (gtest STATIC ${GOOGLETEST_ROOT}/src/gtest_main.cc ${GOOGLETEST_ROOT}/src/gtest-all.cc) +target_include_directories (gtest PRIVATE ${GOOGLETEST_ROOT}) +target_include_directories (gtest PUBLIC ${GOOGLETEST_ROOT}/include) + +add_executable( + ${TEST_EUPHONY} + asciiCharsetTest.cpp + base2Test.cpp + base16Test.cpp + defaultCharsetTest.cpp + FFTTest.cpp + FSKTest.cpp + hexVectorTest.cpp + packetTest.cpp + packetBuilderTest.cpp + packetErrorDetectorTest.cpp + packetWithFSKTest.cpp + waveTest.cpp + waveBuilderTest.cpp + waveRendererTest.cpp +) + +target_link_libraries(${TEST_EUPHONY} PUBLIC euphony gtest) + +set(TARGET_TEST_DIR /data/local/tmp/${TEST_EUPHONY}) # Directory on device to push tests. +set(TARGET_TEST_LIB_DIR ${TARGET_TEST_DIR}/${ANDROID_ABI}) +set(LIBCPP_SHARED_PATH ${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${ANDROID_ABI}/libc++_shared.so) + +get_target_property( OBOE_LIBRARY_PATH oboe::oboe IMPORTED_LOCATION) +find_program(ADB NAMES adb PATHS ${ANDROID_SDK_ROOT}/platform-tools) # Verified to be working on Linux. + +execute_process(COMMAND ${ADB} shell getprop ro.product.cpu.abi + OUTPUT_VARIABLE ADB_DEVICE_ABI + RESULT_VARIABLE ADB_DEVICE_ABI_RESULT) + +if( ${ADB_DEVICE_ABI_RESULT} ) + message("NO ABI OR MORE THAN ONE DEVICE/EMULATOR") +else() + string(STRIP ${ADB_DEVICE_ABI} ADB_DEVICE_ABI) + if(${ANDROID_ABI} STREQUAL ${ADB_DEVICE_ABI}) + # Prepare gtest for unit-test + add_custom_command(TARGET ${TEST_EUPHONY} POST_BUILD + COMMAND ${ADB} shell mkdir -p ${TARGET_TEST_LIB_DIR} + + # Push necessary libraries + COMMAND ${ADB} push $ ${TARGET_TEST_LIB_DIR}/ + COMMAND ${ADB} push ${OBOE_LIBRARY_PATH} ${TARGET_TEST_LIB_DIR}/ + COMMAND ${ADB} push ${LIBCPP_SHARED_PATH} ${TARGET_TEST_LIB_DIR}/ + + # Push Euphony Test Binary + COMMAND ${ADB} push $ ${TARGET_TEST_LIB_DIR}/ + COMMAND ${ADB} shell chmod 755 ${TARGET_TEST_LIB_DIR}/${TEST_EUPHONY} + ) + + # Run gtest & get the result. + add_custom_command(TARGET ${TEST_EUPHONY} POST_BUILD + COMMAND ${CMAKE_COMMAND} -DADB:STRING="${ADB}" -DTARGET_TEST_LIB_DIR:STRING="${TARGET_TEST_LIB_DIR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake.run.test.script + ) + endif() +endif() \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/FFTTest.cpp b/euphony/src/main/cpp/tests/FFTTest.cpp new file mode 100644 index 0000000..aa204d8 --- /dev/null +++ b/euphony/src/main/cpp/tests/FFTTest.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class FFTTestFixture : public ::testing::TestWithParam { + +public: + std::unique_ptr fft = nullptr; +}; + +TEST_P(FFTTestFixture, FFTDefaultTest) +{ + int inputFrequency, inputFFTSize, inputSampleRate, expectedSpectrumIndex; + std::tie(inputFrequency, inputFFTSize, inputSampleRate, expectedSpectrumIndex) = GetParam(); + + fft = std::make_unique(inputFFTSize, inputSampleRate); + + auto wave = Wave::create() + .vibratesAt(inputFrequency) + .setSize(2048) + .build(); + + auto shortWaveSourceVector = wave->getInt16Source(); + int16_t* shortWaveSource = &shortWaveSourceVector[0]; + float* resultBuf = fft->makeSpectrum(shortWaveSource); + const int activeResult = FSK::getMaxIdxFromSource(resultBuf, 32, inputSampleRate, inputFFTSize); + + EXPECT_EQ(expectedSpectrumIndex, activeResult); +} + +INSTANTIATE_TEST_SUITE_P( + FFTTest, + FFTTestFixture, + ::testing::Values( + /* + * Frequency, FFTSize, sampleRate, expectedSpectrumIndex + * kStartSignalFrequency = 17950 + */ + TestParamType(17924, 512, 44100, -1), + TestParamType(18000, 512, 44100, 0), + TestParamType(18086, 512, 44100, 1), + TestParamType(18172, 512, 44100, 2), + TestParamType(18258, 512, 44100, 3), + TestParamType(18345, 512, 44100, 4), + TestParamType(18431, 512, 44100, 5), + TestParamType(18517, 512, 44100, 6), + TestParamType(18603, 512, 44100, 7), + TestParamType(18689, 512, 44100, 8), + TestParamType(18775, 512, 44100, 9), + TestParamType(18861, 512, 44100, 10), + TestParamType(18947, 512, 44100, 11), + TestParamType(19033, 512, 44100, 12), + TestParamType(19119, 512, 44100, 13), + TestParamType(19205, 512, 44100, 14), + TestParamType(19291, 512, 44100, 15), + TestParamType(19377, 512, 44100, 16), + TestParamType(19463, 512, 44100, 17), + TestParamType(19549, 512, 44100, 18), + TestParamType(19635, 512, 44100, 19), + TestParamType(19721, 512, 44100, 20), + TestParamType(19807, 512, 44100, 21), + TestParamType(19893, 512, 44100, 22), + TestParamType(19979, 512, 44100, 23), + TestParamType(20065, 512, 44100, 24), + TestParamType(20151, 512, 44100, 25), + TestParamType(20237, 512, 44100, 26), + TestParamType(20323, 512, 44100, 27), + TestParamType(20409, 512, 44100, 28), + TestParamType(20495, 512, 44100, 29), + TestParamType(20581, 512, 44100, 30), + TestParamType(20667, 512, 44100, 31), + TestParamType(17956, 512, 44100, -1), + TestParamType(17957, 512, 44100, -1), + TestParamType(17958, 512, 44100, -1), + TestParamType(17959, 512, 44100, 0), + TestParamType(17960, 512, 44100, 0), + TestParamType(18001, 512, 44100, 0), + TestParamType(18043, 512, 44100, 0), + TestParamType(18044, 512, 44100, 0), + TestParamType(18045, 512, 44100, 1), + TestParamType(18046, 512, 44100, 1), + TestParamType(18087, 512, 44100, 1), + TestParamType(18129, 512, 44100, 1), + TestParamType(18130, 512, 44100, 1), + TestParamType(18131, 512, 44100, 2), + TestParamType(18132, 512, 44100, 2), + TestParamType(18173, 512, 44100, 2), + TestParamType(18215, 512, 44100, 2), + TestParamType(18216, 512, 44100, 2), + TestParamType(18217, 512, 44100, 3), + TestParamType(18218, 512, 44100, 3), + TestParamType(18259, 512, 44100, 3), + TestParamType(18301, 512, 44100, 3), + TestParamType(18302, 512, 44100, 3), + TestParamType(18303, 512, 44100, 4), + TestParamType(18304, 512, 44100, 4), + TestParamType(18346, 512, 44100, 4), + TestParamType(18324, 512, 44100, 4), + TestParamType(18389, 512, 44100, 4), + TestParamType(18390, 512, 44100, 5), + TestParamType(18391, 512, 44100, 5), + TestParamType(18432, 512, 44100, 5), + TestParamType(18392, 512, 44100, 5), + TestParamType(18475, 512, 44100, 5), + TestParamType(18476, 512, 44100, 6), + TestParamType(18477, 512, 44100, 6), + TestParamType(18518, 512, 44100, 6), + TestParamType(18560, 512, 44100, 6), + TestParamType(18561, 512, 44100, 6), + TestParamType(18562, 512, 44100, 7), + TestParamType(18604, 512, 44100, 7), + TestParamType(18647, 512, 44100, 7), + TestParamType(18648, 512, 44100, 8), + TestParamType(18690, 512, 44100, 8), + TestParamType(18733, 512, 44100, 8), + TestParamType(18734, 512, 44100, 9), + TestParamType(18776, 512, 44100, 9), + TestParamType(18819, 512, 44100, 9), + TestParamType(18820, 512, 44100, 10), + TestParamType(18863, 512, 44100, 10), + TestParamType(18905, 512, 44100, 10), + TestParamType(18906, 512, 44100, 11), + TestParamType(18949, 512, 44100, 11), + TestParamType(18991, 512, 44100, 11), + TestParamType(18992, 512, 44100, 12), + TestParamType(19035, 512, 44100, 12), + TestParamType(19078, 512, 44100, 12), + TestParamType(19079, 512, 44100, 13), + TestParamType(19122, 512, 44100, 13), + TestParamType(19164, 512, 44100, 13), + TestParamType(19165, 512, 44100, 14), + TestParamType(19208, 512, 44100, 14), + TestParamType(19250, 512, 44100, 14), + TestParamType(19251, 512, 44100, 15), + TestParamType(19294, 512, 44100, 15), + TestParamType(19336, 512, 44100, 15), + TestParamType(19337, 512, 44100, 16) + ) +); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/FSKTest.cpp b/euphony/src/main/cpp/tests/FSKTest.cpp new file mode 100644 index 0000000..dfc9e68 --- /dev/null +++ b/euphony/src/main/cpp/tests/FSKTest.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class FSKTestFixture : public ::testing::TestWithParam { + +public: + void createFSK() { + EXPECT_EQ(fsk, nullptr); + fsk = new FSK(); + ASSERT_NE(fsk, nullptr); + } + + void createFFT() { + EXPECT_EQ(fft, nullptr); + fft = new FFTProcessor(kFFTSize, kSampleRate); + ASSERT_NE(fft, nullptr); + } + + FSK* fsk = nullptr; + FFTProcessor* fft = nullptr; + +}; + +TEST_P(FSKTestFixture, FSKModulationString2StringTest) +{ + createFSK(); + + string inputCode; + int expectedCodeLength; + int expectedFreqIndex; + + std::tie(inputCode, expectedCodeLength, expectedFreqIndex) = GetParam(); + + auto modulateFSK = fsk->modulate(inputCode); + EXPECT_EQ(modulateFSK.size(), expectedCodeLength); + + auto demodulateResult = fsk->demodulate(modulateFSK); + EXPECT_EQ(inputCode, demodulateResult->getPayloadStr()); +} + +TEST_F(FSKTestFixture, FSKCodeThrowTest) +{ + createFSK(); + + string inputCode = "K"; + try { + auto resultFSK = fsk->modulate(inputCode); + } catch(Base16Exception e) { + EXPECT_EQ(BASE16_EXCEPTION_MSG, e.MSG()); + } +} + +INSTANTIATE_TEST_CASE_P( + FSKTestSuite, + FSKTestFixture, + ::testing::Values( + TestParamType("0", 1, 0), + TestParamType("1", 1, 1), + TestParamType("2", 1, 2), + TestParamType("3", 1, 3), + TestParamType("4", 1, 4), + TestParamType("5", 1, 5), + TestParamType("012345", 6, 0), + TestParamType("0123456789", 10, 0), + TestParamType("abcdef", 6, 10), + TestParamType("0123456789abcdef", 16, 0) +)); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/asciiCharsetTest.cpp b/euphony/src/main/cpp/tests/asciiCharsetTest.cpp new file mode 100644 index 0000000..420689b --- /dev/null +++ b/euphony/src/main/cpp/tests/asciiCharsetTest.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class ASCIICharsetTestFixture : public ::testing::TestWithParam { + +public: + void openCharset() { + EXPECT_EQ(charset, nullptr); + charset = new ASCIICharset(); + ASSERT_NE(charset, nullptr); + } + + Charset* charset = nullptr; +}; + + +TEST_P(ASCIICharsetTestFixture, EncodingTest) +{ + openCharset(); + + std::string source; + std::string expectedResult; + + std::tie(source, expectedResult) = GetParam(); + + HexVector actualResult = charset->encode(source); + EXPECT_EQ(actualResult.toString(), expectedResult); +} + + +TEST_P(ASCIICharsetTestFixture, DecodingTest) +{ + openCharset(); + + std::string source; + std::string expectedResult; + + std::tie(expectedResult, source) = GetParam(); + HexVector hv = HexVector(source); + + std::string actualResult = charset->decode(hv); + EXPECT_EQ(actualResult, expectedResult); +} + +INSTANTIATE_TEST_CASE_P( + ChrasetDecodingTestSuite, + ASCIICharsetTestFixture, + ::testing::Values( + TestParamType("a", "61"), + TestParamType("b", "62"), + TestParamType("c", "63"), + TestParamType("abc", "616263"), + TestParamType("lmno", "6c6d6e6f"), + TestParamType("efg", "656667"), + TestParamType("abcdefghijklmnopqrstuvwxyz", "6162636465666768696a6b6c6d6e6f707172737475767778797a"), + TestParamType("ABC", "414243"), + TestParamType("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "4142434445464748494a4b4c4d4e4f505152535455565758595a") + )); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/base16Test.cpp b/euphony/src/main/cpp/tests/base16Test.cpp new file mode 100644 index 0000000..8bd8c7f --- /dev/null +++ b/euphony/src/main/cpp/tests/base16Test.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple, std::string> TestParamType; + +class Base16TranslationFixture : public ::testing::TestWithParam { + +public: + Base* base16 = nullptr; +}; + +TEST_P(Base16TranslationFixture, DefaultEncodingTest) +{ + std::vector source; + std::string expectedEncodedResult; + + std::tie(source, expectedEncodedResult) = GetParam(); + HexVector hv = HexVector(source); + base16 = new Base16(hv); + std::string actualResult = base16->getBaseString(); + EXPECT_EQ(actualResult, expectedEncodedResult); +} + +INSTANTIATE_TEST_SUITE_P( + Base16TranslationTest, + Base16TranslationFixture, + ::testing::Values( + TestParamType(std::vector{ 0x61 }, "61"), + TestParamType(std::vector{ 0x62 }, "62"), + TestParamType(std::vector{ 0x63 }, "63"), + TestParamType(std::vector{ 0x61, 0x62, 0x63 }, "616263"), + TestParamType(std::vector{ 0x6c, 0x6d, 0x6e, 0x6f }, "6c6d6e6f"), + TestParamType(std::vector{ 0x65, 0x66, 0x67 }, "656667"), + TestParamType(std::vector{ + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, + 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a + }, "6162636465666768696a6b6c6d6e6f707172737475767778797a"), + TestParamType(std::vector{ 0x41, 0x42, 0x43 }, "414243"), + TestParamType(std::vector{ + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a + }, "4142434445464748494a4b4c4d4e4f505152535455565758595a") + )); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/base2Test.cpp b/euphony/src/main/cpp/tests/base2Test.cpp new file mode 100644 index 0000000..eec9151 --- /dev/null +++ b/euphony/src/main/cpp/tests/base2Test.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple, std::string> TestParamType; + +class Base2TranslationFixture : public ::testing::TestWithParam { +public: + Base* base2 = nullptr; +}; + +TEST_P(Base2TranslationFixture, DefaultBase2Test) +{ + std::vector source; + std::string expectedEncodedResult; + + std::tie(source, expectedEncodedResult) = GetParam(); + HexVector hv = HexVector(source); + base2 = new Base2(hv); + std::string actualResult = base2->getBaseString(); + EXPECT_EQ(actualResult, expectedEncodedResult); +} + +INSTANTIATE_TEST_SUITE_P( + Base2TranslationTest, + Base2TranslationFixture, + ::testing::Values( + TestParamType(std::vector{ 0x61 }, "01100001"), + TestParamType(std::vector{ 0x62 }, "01100010"), + TestParamType(std::vector{ 0x63 }, "01100011"), + TestParamType(std::vector{ 0x61, 0x62, 0x63 }, "011000010110001001100011"), + TestParamType(std::vector{ 0x78, 0x79, 0x7a }, "011110000111100101111010") +)); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/cmake.run.test.script b/euphony/src/main/cpp/tests/cmake.run.test.script new file mode 100644 index 0000000..252bd54 --- /dev/null +++ b/euphony/src/main/cpp/tests/cmake.run.test.script @@ -0,0 +1,14 @@ +execute_process(COMMAND ${ADB} shell LD_LIBRARY_PATH=${TARGET_TEST_LIB_DIR} ${TARGET_TEST_LIB_DIR}/testEuphony + OUTPUT_VARIABLE GTEST_EUPHONY_OUTPUT + RESULT_VARIABLE GTEST_RESULT + ERROR_VARIABLE GTEST_ERROR_OUTPUT + ) + +if( ${GTEST_RESULT} GREATER 0 ) + string(STRIP ${GTEST_EUPHONY_OUTPUT} GTEST_EUPHONY_OUTPUT) + string(REPLACE "\n\n" "\r[NEXT]\r" GTEST_EUPHONY_OUTPUT ${GTEST_EUPHONY_OUTPUT}) + string(REPLACE "\n" "\r" GTEST_EUPHONY_OUTPUT ${GTEST_EUPHONY_OUTPUT}) + message(FATAL_ERROR "** Gtest Failure (${GTEST_RESULT}) **\r${GTEST_EUPHONY_OUTPUT}") +else() + message("**** Gtest Success ****") +endif() \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/defaultCharsetTest.cpp b/euphony/src/main/cpp/tests/defaultCharsetTest.cpp new file mode 100644 index 0000000..34d5a3f --- /dev/null +++ b/euphony/src/main/cpp/tests/defaultCharsetTest.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class DefaultCharsetTestFixture : public ::testing::TestWithParam { + +public: + void openCharset() { + EXPECT_EQ(charset, nullptr); + charset = new DefaultCharset(); + ASSERT_NE(charset, nullptr); + } + + Charset* charset = nullptr; +}; + +TEST_P(DefaultCharsetTestFixture, DecodingTest) +{ + openCharset(); + + std::string source; + + std::tie(source) = GetParam(); + + std::string actualResult = charset->decode(source); + EXPECT_EQ(actualResult, source); +} + +INSTANTIATE_TEST_CASE_P( + ChrasetDecodingTestSuite, + DefaultCharsetTestFixture, + ::testing::Values( + TestParamType("61"), + TestParamType("62"), + TestParamType("63"), + TestParamType("616263"), + TestParamType("6c6d6e6f"), + TestParamType("656667"), + TestParamType("6162636465666768696a6b6c6d6e6f707172737475767778797a"), + TestParamType("414243"), + TestParamType("4142434445464748494a4b4c4d4e4f505152535455565758595a") +)); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/hexVectorTest.cpp b/euphony/src/main/cpp/tests/hexVectorTest.cpp new file mode 100644 index 0000000..ac73ec9 --- /dev/null +++ b/euphony/src/main/cpp/tests/hexVectorTest.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple, std::string> TestParamType; + +class HexVectorTestFixture : public ::testing::TestWithParam { + +public: + void createHexVector() { + EXPECT_EQ(hexVector, nullptr); + hexVector = new HexVector(0); + ASSERT_NE(hexVector, nullptr); + } + + HexVector* hexVector = nullptr; +}; + +TEST_P(HexVectorTestFixture, DefaultHex2StringTest) +{ + createHexVector(); + + std::vector source; + std::string expectedToStringResult; + + std::tie(source, expectedToStringResult) = GetParam(); + hexVector->setHexSource(source); + + EXPECT_EQ(hexVector->toString(), expectedToStringResult); +} + +INSTANTIATE_TEST_SUITE_P( + hexVectorTest, + HexVectorTestFixture, + ::testing::Values( + TestParamType(std::vector { 0 }, "0"), + TestParamType(std::vector { 1 }, "1"), + TestParamType(std::vector { 2 }, "2"), + TestParamType(std::vector { 0, 1 }, "01"), + TestParamType(std::vector { 0x01 }, "1"), + TestParamType(std::vector { 0x01, 0x0f }, "1f"), + TestParamType(std::vector { 1, 2 }, "12"), + TestParamType(std::vector { 1, 3, 5 }, "135"), + TestParamType(std::vector { 1, 0xa, 0xf }, "1af"), + TestParamType(std::vector { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf }, "abcdef"), + TestParamType(std::vector { 0x1f, 0x2f, 0x3f, 0x4f }, "1f2f3f4f"), + TestParamType(std::vector { 0xff, 0xff, 0xff, 0x4f }, "ffffff4f") + ) +); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/packetBuilderTest.cpp b/euphony/src/main/cpp/tests/packetBuilderTest.cpp new file mode 100644 index 0000000..01a3e1e --- /dev/null +++ b/euphony/src/main/cpp/tests/packetBuilderTest.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class PacketBuilderTestFixture : public ::testing::TestWithParam { + +public: + std::shared_ptr pkt = nullptr; +}; + +TEST_P(PacketBuilderTestFixture, CreationForASCIIAndBase16TestByPacketBuilder) +{ + std::string source; + std::string expectedResult; + + std::tie(source, expectedResult) = GetParam(); + + pkt = Packet::create() + .setPayloadWithASCII(source) + .basedOnBase16() + .build(); + + // Check total result + EXPECT_EQ(pkt->toString(), expectedResult); +} + +TEST_F(PacketBuilderTestFixture, CreationForASCIIAndBase2TestByPacketBuilder) +{ + std::string source = "a"; + std::string expectedResult = "S0110000110010111"; + pkt = Packet::create() + .setPayloadWithASCII(source) + .basedOnBase2() + .build(); + // Check total result + EXPECT_EQ(pkt->toString(), expectedResult); + + pkt->clear(); + source = "abc"; + expectedResult = "S01100001011000100110001110000110"; + pkt = Packet::create() + .setPayloadWithASCII(source) + .basedOnBase2() + .build(); + + EXPECT_EQ(pkt->toString(), expectedResult); +} + +INSTANTIATE_TEST_SUITE_P( + PacketBuilderTest, + PacketBuilderTestFixture, + ::testing::Values( + TestParamType("a", "S6197"), + TestParamType("b", "S6284"), + TestParamType("c", "S6375"), + TestParamType("abc", "S61626386"), + TestParamType("lmno", "S6c6d6e6f20"), + TestParamType("efg", "S656667c2"), + TestParamType("abcdefghijklmnopqrstuvwxyz", "S6162636465666768696a6b6c6d6e6f707172737475767778797aaa"), + TestParamType("ABC", "S414243e4"), + TestParamType("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "S4142434445464748494a4b4c4d4e4f505152535455565758595aea") + ) +); diff --git a/euphony/src/main/cpp/tests/packetErrorDetectorTest.cpp b/euphony/src/main/cpp/tests/packetErrorDetectorTest.cpp new file mode 100644 index 0000000..1452a2e --- /dev/null +++ b/euphony/src/main/cpp/tests/packetErrorDetectorTest.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class PacketErrorDetectorTestFixture : public ::testing::TestWithParam { +}; + +TEST_P(PacketErrorDetectorTestFixture, PacketErrorDetectorTest) +{ + std::string source; + std::string expectedResult; + + std::tie(source, expectedResult) = GetParam(); + + std::string actualResult = PacketErrorDetector::makeParityAndChecksum(source); + EXPECT_EQ(expectedResult, actualResult); +} + +TEST_F(PacketErrorDetectorTestFixture, ErrorCodeTest) +{ + + std::vector source {0x6, 0x1}; + std::string expectedResult = "97"; + HexVector hv = HexVector(source); + EXPECT_EQ(expectedResult, PacketErrorDetector::makeParityAndChecksum(hv.getHexSource())); + + std::vector source2 {0x61, 0x62, 0x63}; + std::string expectedResult2 = "86"; + HexVector hv2 = HexVector(source2); + EXPECT_EQ(expectedResult2, PacketErrorDetector::makeParityAndChecksum(hv2.getHexSource())); +} + + +TEST_F(PacketErrorDetectorTestFixture, ChecksumTest) +{ + std::vector source {0x6, 0x8, 0x6, 0x5, 0x6, 0xc, 0x6, 0xc, 0x6, 0xf}; + + HexVector hv = HexVector(source); + HexVector actualResult = HexVector(1); + actualResult.pushBack(14); + EXPECT_EQ(PacketErrorDetector::makeChecksum(hv).toString(), actualResult.toString()); + EXPECT_EQ(PacketErrorDetector::verifyChecksum(hv, 14), true); + EXPECT_EQ(PacketErrorDetector::verifyChecksum(hv, 13), false); +} + +TEST_F(PacketErrorDetectorTestFixture, ParityCodeTest) +{ + std::vector source {0x6, 0x8, 0x6, 0x5, 0x6, 0xc, 0x6, 0xc, 0x6, 0xf}; + + HexVector hv = HexVector(source); + HexVector actualResult = HexVector(1); + actualResult.pushBack(4); + EXPECT_EQ(PacketErrorDetector::makeParallelParity(hv).toString(), actualResult.toString()); + EXPECT_EQ(PacketErrorDetector::verifyParallelParity(hv, 4), true); + EXPECT_EQ(PacketErrorDetector::verifyParallelParity(hv, 5), false); +} + +INSTANTIATE_TEST_CASE_P( + PacketErrorDetectorTestSuite, + PacketErrorDetectorTestFixture, + ::testing::Values( + TestParamType("61", "97"), + TestParamType("62", "84"), + TestParamType("63", "75"), + TestParamType("616263", "86"), + TestParamType("6c6d6e6f", "20"), + TestParamType("656667", "c2"), + TestParamType("6162636465666768696a6b6c6d6e6f707172737475767778797a", "aa"), + TestParamType("414243", "e4"), + TestParamType("4142434445464748494a4b4c4d4e4f505152535455565758595a", "ea") +)); diff --git a/euphony/src/main/cpp/tests/packetTest.cpp b/euphony/src/main/cpp/tests/packetTest.cpp new file mode 100644 index 0000000..ebbed84 --- /dev/null +++ b/euphony/src/main/cpp/tests/packetTest.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class PacketTestFixture : public ::testing::TestWithParam { + +public: + Packet* pkt = nullptr; +}; + +TEST_P(PacketTestFixture, PacketCreationForASCIIAndBase16Test) +{ + std::string source; + std::string expectedResult; + + std::tie(source, expectedResult) = GetParam(); + + HexVector hv = ASCIICharset().encode(source); + pkt = new Packet(hv); + + // Check total result + EXPECT_EQ(pkt->toString(), expectedResult); +} + +TEST_F(PacketTestFixture, PacketCreationForASCIIAndBase2Test) +{ + std::string source = "a"; + std::string expectedResult = "S0110000110010111"; + HexVector hv = ASCIICharset().encode(source); + pkt = new Packet(BaseType::BASE2, hv); + // Check total result + EXPECT_EQ(pkt->toString(), expectedResult); + + pkt->clear(); + source = "abc"; + expectedResult = "S01100001011000100110001110000110"; + hv = ASCIICharset().encode(source); + pkt->setPayload(hv); + EXPECT_EQ(pkt->toString(), expectedResult); +} + +INSTANTIATE_TEST_CASE_P( + PacketTestSuite, + PacketTestFixture, + ::testing::Values( + TestParamType("a", "S6197"), + TestParamType("b", "S6284"), + TestParamType("c", "S6375"), + TestParamType("abc", "S61626386"), + TestParamType("lmno", "S6c6d6e6f20"), + TestParamType("efg", "S656667c2"), + TestParamType("abcdefghijklmnopqrstuvwxyz", "S6162636465666768696a6b6c6d6e6f707172737475767778797aaa"), + TestParamType("ABC", "S414243e4"), + TestParamType("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "S4142434445464748494a4b4c4d4e4f505152535455565758595aea") + )); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/packetWithFSKTest.cpp b/euphony/src/main/cpp/tests/packetWithFSKTest.cpp new file mode 100644 index 0000000..03a5ca6 --- /dev/null +++ b/euphony/src/main/cpp/tests/packetWithFSKTest.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class PacketWithFSKTestFixture : public ::testing::TestWithParam { + +public: + void createFSK() { + EXPECT_EQ(fsk, nullptr); + fsk = new FSK(); + ASSERT_NE(fsk, nullptr); + } + + FSK* fsk = nullptr; + Packet* pkt = nullptr; +}; + +TEST_P(PacketWithFSKTestFixture, PacketFSKTest) +{ + createFSK(); + + string source; + string expectedResult; + + std::tie(source, expectedResult) = GetParam(); + HexVector hv = ASCIICharset().encode(source); + pkt = new Packet(hv); + + string actualResultCode = pkt->toString(); + EXPECT_EQ(actualResultCode, expectedResult); + + auto modulateResult = fsk->modulate(pkt->getPayloadStr()); + EXPECT_EQ(modulateResult.size(), source.size() * 2); + + auto demodulateResult = fsk->demodulate(modulateResult); + + EXPECT_EQ(expectedResult, demodulateResult->toString()); + pkt->clear(); +} + +INSTANTIATE_TEST_CASE_P( + PacketFSKTestSuite, + PacketWithFSKTestFixture, + ::testing::Values( + TestParamType("a", "S6197"), + TestParamType("b", "S6284"), + TestParamType("c", "S6375"), + TestParamType("abc", "S61626386"), + TestParamType("lmno", "S6c6d6e6f20"), + TestParamType("efg", "S656667c2"), + TestParamType("abcdefghijklmnopqrstuvwxyz", "S6162636465666768696a6b6c6d6e6f707172737475767778797aaa"), + TestParamType("ABC", "S414243e4"), + TestParamType("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "S4142434445464748494a4b4c4d4e4f505152535455565758595aea") +)); diff --git a/euphony/src/main/cpp/tests/waveBuilderTest.cpp b/euphony/src/main/cpp/tests/waveBuilderTest.cpp new file mode 100644 index 0000000..dece23c --- /dev/null +++ b/euphony/src/main/cpp/tests/waveBuilderTest.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include + +using std::string; +using namespace Euphony; + +typedef std::tuple TestParamType; + +class WaveBuilderTestFixture : public ::testing::TestWithParam { + +public: + std::shared_ptr wave = nullptr; +}; + +TEST_P(WaveBuilderTestFixture, WaveBuilderUnitTest) +{ +int inputHz; +int inputSize; + +std::tie(inputHz, inputSize) = GetParam(); + +wave = Wave::create() + .vibratesAt(inputHz) + .setSize(inputSize) + .build(); + +EXPECT_EQ(wave->getHz(), inputHz); +EXPECT_EQ(wave->getSize(), inputSize); +EXPECT_EQ(wave->getSource().size(), inputSize); +} + +INSTANTIATE_TEST_SUITE_P( + WaveBuilderTest, + WaveBuilderTestFixture, + ::testing::Values( + TestParamType(18000, 512), + TestParamType(18000, 1024), + TestParamType(18000, 2048), + TestParamType(20000, 2048), + TestParamType(21000, 2048) +)); diff --git a/euphony/src/main/cpp/tests/waveRendererTest.cpp b/euphony/src/main/cpp/tests/waveRendererTest.cpp new file mode 100644 index 0000000..74eb9dc --- /dev/null +++ b/euphony/src/main/cpp/tests/waveRendererTest.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace Euphony; + +typedef std::tuple TestParamType; + +class WaveRendererTestFixture : public ::testing::TestWithParam { + +public: + std::shared_ptr wave = nullptr; + std::unique_ptr waveRenderer = nullptr; +}; + +TEST_P(WaveRendererTestFixture, WaveBuilderUnitTest) +{ + std::string inputString; + int expectedBufferSize; + int expectedStartData; + + std::tie(inputString, expectedBufferSize, expectedStartData) = GetParam(); + + auto fsk = new FSK(); + auto waveList = fsk->modulate(inputString); + + waveRenderer = std::make_unique(waveList, 2); + const auto actualWaveSourceSize = waveRenderer->getWaveSourceSize(); + EXPECT_EQ(actualWaveSourceSize, expectedBufferSize); + + auto demodulateResult = fsk->demodulate(waveRenderer->getWaveSource(), actualWaveSourceSize, kBufferSize); + EXPECT_EQ(inputString, demodulateResult->getPayloadStr()); + + delete fsk; +} + +INSTANTIATE_TEST_SUITE_P( + WaveRendererTest, + WaveRendererTestFixture, + ::testing::Values( + TestParamType("0", 2048, 0), + TestParamType("1", 2048, 1), + TestParamType("2", 2048, 2), + TestParamType("3", 2048, 3), + TestParamType("4", 2048, 4), + TestParamType("5", 2048, 5), + TestParamType("012345", 2048*6, 0), + TestParamType("0123456789", 2048*10, 0), + TestParamType("abcdef", 2048*6, 10), + TestParamType("0123456789abcdef", 2048*16, 0) + ) +); \ No newline at end of file diff --git a/euphony/src/main/cpp/tests/waveTest.cpp b/euphony/src/main/cpp/tests/waveTest.cpp new file mode 100644 index 0000000..a29ca3c --- /dev/null +++ b/euphony/src/main/cpp/tests/waveTest.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + +using std::string; +using namespace Euphony; + +typedef std::tuple TestParamType; + +class WaveTestFixture : public ::testing::TestWithParam { + +public: + void makeFrequency() { + EXPECT_EQ(wave, nullptr); + wave = new Wave(); + ASSERT_NE(wave, nullptr); + } + + Wave* wave = nullptr; +}; + +TEST_P(WaveTestFixture, WaveUnitTest) +{ + makeFrequency(); + + int inputHz; + int inputSize; + + std::tie(inputHz, inputSize) = GetParam(); + + wave->setHz(inputHz); + EXPECT_EQ(wave->getHz(), inputHz); + wave->setSize(inputSize); + EXPECT_EQ(wave->getSize(), inputSize); + + auto source = wave->getSource(); + EXPECT_EQ(source.capacity(), inputSize); + EXPECT_EQ(source.size(), 0); + + EXPECT_EQ(wave->getSource().capacity(), inputSize); + EXPECT_EQ(wave->getSource().size(), 0); + + wave->oscillate(); + auto source2 = wave->getSource(); + EXPECT_EQ(source2.capacity(), inputSize); + EXPECT_EQ(source2.size(), inputSize); + + int zeroCount = 0; + for(float floatSrc : source2) { + if(floatSrc == 0) + zeroCount++; + else + break; + } + EXPECT_EQ(zeroCount, 1); // because wave is sin + + EXPECT_EQ(wave->getInt16Source().capacity(), inputSize); + EXPECT_EQ(wave->getInt16Source().size(), inputSize); + + std::vector int16Source = wave->getInt16Source(); + EXPECT_EQ(int16Source.capacity(), inputSize); + EXPECT_EQ(int16Source.size(), inputSize); + + zeroCount = 0; + for(short shortSrc : int16Source) { + if(shortSrc == 0) { + zeroCount++; + } + else + break; + } + EXPECT_EQ(zeroCount, 1); // because wave is sin + //int16_t data = wave->convertFloat2Int16(0.02); + //EXPECT_EQ(data, 0); +} + +INSTANTIATE_TEST_SUITE_P( + WaveTest, + WaveTestFixture, + ::testing::Values( + TestParamType(18000, 512), + TestParamType(18000, 1024), + TestParamType(18000, 2048), + TestParamType(20000, 2048), + TestParamType(21000, 2048) +)); \ No newline at end of file diff --git a/euphony/src/main/java/co/euphony/common/Constants.java b/euphony/src/main/java/co/euphony/common/Constants.java new file mode 100644 index 0000000..bd5bef7 --- /dev/null +++ b/euphony/src/main/java/co/euphony/common/Constants.java @@ -0,0 +1,23 @@ +package co.euphony.common; + +public class Constants { + + // RX & TX COMMON VARIABLES + public static final int SAMPLERATE = 44100; + public static final int HALF_SAMPLERATE = (SAMPLERATE >> 1); + public static final int FFT_SIZE = 512; + + public static final int CHANNEL = 16; + public static final int CHANNEL_INTERVAL = SAMPLERATE / FFT_SIZE; // Frequency Interval + + public static final int STANDARD_FREQ = 18001; + public static final int START_SIGNAL_FREQ = STANDARD_FREQ - CHANNEL_INTERVAL; + + public static final int BUNDLE_INTERVAL = CHANNEL_INTERVAL * CHANNEL; + + // RX + public static final int MAX_REF = 4000; + public static final int MIN_REF = 50; + + public static final int DEFAULT_REF = 500; // BASE Reference value +} diff --git a/euphony/src/main/java/euphony/lib/receiver/AcousticSensor.java b/euphony/src/main/java/co/euphony/rx/AcousticSensor.java similarity index 69% rename from euphony/src/main/java/euphony/lib/receiver/AcousticSensor.java rename to euphony/src/main/java/co/euphony/rx/AcousticSensor.java index fffd91a..4e31784 100644 --- a/euphony/src/main/java/euphony/lib/receiver/AcousticSensor.java +++ b/euphony/src/main/java/co/euphony/rx/AcousticSensor.java @@ -1,4 +1,4 @@ -package euphony.lib.receiver; +package co.euphony.rx; public interface AcousticSensor { void notify(String letters); diff --git a/euphony/src/main/java/euphony/lib/receiver/AudioRecorder.java b/euphony/src/main/java/co/euphony/rx/AudioRecorder.java similarity index 97% rename from euphony/src/main/java/euphony/lib/receiver/AudioRecorder.java rename to euphony/src/main/java/co/euphony/rx/AudioRecorder.java index c624bcc..6ab5297 100644 --- a/euphony/src/main/java/euphony/lib/receiver/AudioRecorder.java +++ b/euphony/src/main/java/co/euphony/rx/AudioRecorder.java @@ -1,11 +1,10 @@ -package euphony.lib.receiver; +package co.euphony.rx; import java.nio.ByteBuffer; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; -import android.util.Log; public class AudioRecorder { diff --git a/euphony/src/main/java/euphony/lib/receiver/EuDataDecoder.java b/euphony/src/main/java/co/euphony/rx/EuDataDecoder.java similarity index 91% rename from euphony/src/main/java/euphony/lib/receiver/EuDataDecoder.java rename to euphony/src/main/java/co/euphony/rx/EuDataDecoder.java index 279fbbd..60fbef7 100644 --- a/euphony/src/main/java/euphony/lib/receiver/EuDataDecoder.java +++ b/euphony/src/main/java/co/euphony/rx/EuDataDecoder.java @@ -1,7 +1,6 @@ -package euphony.lib.receiver; +package co.euphony.rx; -import android.util.Log; -import euphony.lib.util.EuCodec; +import co.euphony.util.EuCodec; public class EuDataDecoder extends EuCodec { private String mOriginalSource; diff --git a/euphony/src/main/java/euphony/lib/receiver/EuFreqObject.java b/euphony/src/main/java/co/euphony/rx/EuFreqObject.java similarity index 64% rename from euphony/src/main/java/euphony/lib/receiver/EuFreqObject.java rename to euphony/src/main/java/co/euphony/rx/EuFreqObject.java index 6cfd635..2f7414e 100644 --- a/euphony/src/main/java/euphony/lib/receiver/EuFreqObject.java +++ b/euphony/src/main/java/co/euphony/rx/EuFreqObject.java @@ -1,4 +1,4 @@ -package euphony.lib.receiver; +package co.euphony.rx; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -7,25 +7,16 @@ import java.util.ArrayList; import android.util.Log; -import euphony.lib.util.COMMON; -import euphony.lib.util.PacketErrorDetector; +import co.euphony.common.Constants; +import co.euphony.util.PacketErrorDetector; public class EuFreqObject { - public final int SAMPLERATE = COMMON.SAMPLERATE;//44100; - public final int fftsize = COMMON.FFT_SIZE;//512; - public final int MAXREFERENCE = COMMON.MAX_REF;//4000; - public final int MINREFERENCE = COMMON.MIN_REF;//50; - public final double MAXFREQUENCY = COMMON.MAX_FREQ;//22050.0; - public final int DEFAULT_REF = COMMON.DEFAULT_REF;//500 - public final int START_FREQ = COMMON.START_FREQ; //18000 - public final int RXCHANNEL = COMMON.CHANNEL;// 16 - private final int STARTCHANNEL = 1; - private int mFreqSpan = COMMON.CHANNEL_SPAN; // 86 - public final int START_BIT = START_FREQ - mFreqSpan; - public final int START_BIT_IDX = RXCHANNEL; - public int[] DATA_FREQ = new int[RXCHANNEL]; - public int[] DATA_FREQ_INDEX_FOR_FFT = new int[RXCHANNEL + 1]; + private final int STARTCHANNEL = 1; + public final int START_BIT_IDX = Constants.CHANNEL; + + public int[] DATA_FREQ = new int[Constants.CHANNEL]; + public int[] DATA_FREQ_INDEX_FOR_FFT = new int[Constants.CHANNEL + 1]; private Boolean isStarted = false; private Boolean isCompleted = false; @@ -33,60 +24,51 @@ public class EuFreqObject { public Boolean getStarted() { return isStarted; } - public void setStarted(Boolean started) { isStarted = started; } - public Boolean getCompleted() { return isCompleted; } - public void setCompleted(Boolean completed) { isCompleted = completed; } - private Boolean isRecording = false; - private ByteBuffer samples = allocateByteBuffer(fftsize); - private FloatBuffer spectrum = allocateFloatBuffer(fftsize/2+1); - private FloatBuffer spectrum_p = allocateFloatBuffer(fftsize/2+1); - public static String receiveStr = ""; + private ByteBuffer samples = allocateByteBuffer(Constants.FFT_SIZE); + private FloatBuffer spectrum = allocateFloatBuffer(Constants.FFT_SIZE / 2 + 1); + private FloatBuffer spectrum_p = allocateFloatBuffer(Constants.FFT_SIZE / 2 + 1); private String mReceivedData; - public String getReceivedData() { - return mReceivedData; - } + private int[] mFreqArray = new int[Constants.CHANNEL + STARTCHANNEL]; + private int[] mTempRef = new int[Constants.CHANNEL + STARTCHANNEL]; + private int[] mRefCntIndexArray = new int[Constants.CHANNEL + STARTCHANNEL]; + private int[] mDynamicRefArray = new int[Constants.CHANNEL + STARTCHANNEL]; - - public void setReceivedData(String _receivedData) { - this.mReceivedData = _receivedData; - } - - private int[] mFreqArray = new int[RXCHANNEL + STARTCHANNEL]; - private int[] mTempRef = new int[RXCHANNEL + STARTCHANNEL]; - private int[] mRefCntIndexArray = new int[RXCHANNEL + STARTCHANNEL]; - private int[] mDynamicRefArray = new int[RXCHANNEL + STARTCHANNEL]; - - private ArrayList mChannelArrayList = new ArrayList(); + private ArrayList mChannelArrayList = new ArrayList<>(); private AudioRecorder recorder; - private KissFFT FFT = new KissFFT(fftsize); + private KissFFT FFT = new KissFFT(Constants.FFT_SIZE); + + private int []mArrMaxIndex = new int [Constants.CHANNEL + STARTCHANNEL]; + private int []mArrSampleIndex = new int [Constants.CHANNEL + STARTCHANNEL]; + private int []mArrSampleTemp = new int [Constants.CHANNEL + STARTCHANNEL]; + private int []mArrChannelTemp = new int [Constants.CHANNEL + STARTCHANNEL]; + public int []mArrcntCheck = new int [Constants.CHANNEL + STARTCHANNEL]; public EuFreqObject() { - recorder = new AudioRecorder(SAMPLERATE); + recorder = new AudioRecorder(Constants.SAMPLERATE); //INIT DYNAMIC REFERENCE ARRAY.. - for (int i = 0; i < RXCHANNEL; i++) { - DATA_FREQ[i] = START_FREQ + mFreqSpan * i; - DATA_FREQ_INDEX_FOR_FFT[i] = ((int)((DATA_FREQ[i] / MAXFREQUENCY) * fftsize / 2)) + 1; - mDynamicRefArray[i] = DEFAULT_REF; + for (int i = 0; i < Constants.CHANNEL; i++) { + DATA_FREQ[i] = Constants.STANDARD_FREQ + Constants.CHANNEL_INTERVAL * i; + DATA_FREQ_INDEX_FOR_FFT[i] = Math.round((DATA_FREQ[i] / (float)Constants.HALF_SAMPLERATE) * (Constants.FFT_SIZE >> 1)); + mDynamicRefArray[i] = Constants.DEFAULT_REF; } - DATA_FREQ_INDEX_FOR_FFT[RXCHANNEL] = ((int)((START_BIT / MAXFREQUENCY) * fftsize / 2)) + 1; - mDynamicRefArray[RXCHANNEL] = DEFAULT_REF; + DATA_FREQ_INDEX_FOR_FFT[Constants.CHANNEL] = Math.round((Constants.START_SIGNAL_FREQ / (float)Constants.HALF_SAMPLERATE) * (Constants.FFT_SIZE >> 1)); + mDynamicRefArray[Constants.CHANNEL] = Constants.DEFAULT_REF; - isRecording = false; } @@ -97,11 +79,8 @@ public void processFFT() recorder.start(); isRecording = true; } - recorder.read(samples, fftsize); - FFT.spectrum(samples, spectrum); - //FFT.spectrum_for_phase(samples, spectrum_p); - //FFT.getRealPart(real); - //FFT.getImagPart(image); + recorder.read(samples, Constants.FFT_SIZE); + FFT.doSpectrums(samples, spectrum); } public void processFFT(short windowsNum) @@ -110,8 +89,8 @@ public void processFFT(short windowsNum) recorder.start(); isRecording = true; } - recorder.read(samples, fftsize, windowsNum); - FFT.spectrum(samples, spectrum); + recorder.read(samples, Constants.FFT_SIZE, windowsNum); + FFT.doSpectrums(samples, spectrum); } public void destroyFFT() @@ -122,33 +101,25 @@ public void destroyFFT() } public int detectFreq(int fFrequency){ - - double fFreqRatio; - int freqIndex; - float fmax; - - fFreqRatio = fFrequency / MAXFREQUENCY; - freqIndex = ( (int) (fFreqRatio * fftsize / 2) ) + 1; - - //f1 = spectrum.get(freqIndex-1); - fmax = spectrum.get(freqIndex); - //f3 = spectrum_p.get(freqIndex); - //r1 = real.get(freqIndex); - //i1 = image.get(freqIndex); - /* - String s = ""; - for(int i = freqIndex - 1; i <= freqIndex + 1; i++) - s += " " + spectrum.get(i); - Log.i("HELLO FREQ", freqIndex + "::" + s); - */ - //f3 = spectrum.get(freqIndex+1); - - //if( fmax < f2 ) fmax = f2; - //if( fmax < f3 ) fmax = f3; + final float fFreqRatio = fFrequency / (float) Constants.HALF_SAMPLERATE; + final int freqIndex = Math.round(fFreqRatio * (Constants.FFT_SIZE >> 1)); + final float fmax = spectrum.get(freqIndex); return (int)(fmax*100000); } + public String getReceivedData() { + return mReceivedData; + } + + public void setReceivedData(String _receivedData) { + this.mReceivedData = _receivedData; + } + + public float getSpectrumValue(int idx) { + return spectrum.get(idx); + } + public int detectFreqByIdx(int idx) { float fmax = spectrum.get(DATA_FREQ_INDEX_FOR_FFT[idx]); return (int) (fmax * 100000); @@ -170,13 +141,13 @@ public void catchSingleData() int currentFreq = 0; // UPDATED ON 1/2/2014 // START BIT's Frequency Detection - mSampleTemp = detectFreqByIdx(START_BIT_IDX); - mMaxIndex = RXCHANNEL; + mSampleTemp = detectFreqByIdx(Constants.CHANNEL); + mMaxIndex = Constants.CHANNEL; // START BIT's Dynamic Reference Catch - mDynamicRefArray[RXCHANNEL] = getDynamicReference(mSampleTemp, RXCHANNEL); + mDynamicRefArray[Constants.CHANNEL] = getDynamicReference(mSampleTemp, Constants.CHANNEL); // Rest of frequency processing - for(int i = 0; i < RXCHANNEL; i++) + for(int i = 0; i < Constants.CHANNEL; i++) { currentFreq = detectFreqByIdx(i); mDynamicRefArray[i] = getDynamicReference(currentFreq, i); @@ -196,14 +167,13 @@ public void catchSingleData() } else { - for(int i = 0; i < RXCHANNEL + STARTCHANNEL ; i++) + for(int i = 0; i < Constants.CHANNEL + STARTCHANNEL; i++) { - if(mFreqArray[i]>mChannelTemp) + if(mFreqArray[i] > mChannelTemp) { mChannelTemp = mFreqArray[i]; mMaxIndex = i; } - //mbFreqArray[i] = 0; } if(mChannelTemp > 2 && mMaxIndex != -1) @@ -222,11 +192,14 @@ public void catchSingleData() else mReceivedData += "" + a[i]; } - - if(PacketErrorDetector.makeCheckSum(a) == mChannelArrayList.get(mChannelArrayList.size()-2) && (PacketErrorDetector.makeParellelParity(a) == mChannelArrayList.get(mChannelArrayList.size()-1))) { + + if(PacketErrorDetector.makeCheckSum(a) == mChannelArrayList.get(mChannelArrayList.size()-2) && (PacketErrorDetector.makeParallelParity(a) == mChannelArrayList.get(mChannelArrayList.size()-1))) { isStarted = false; isCompleted = true; - receiveStr = EuDataDecoder.decodeStaticHexCharSource(a); + } else { + Log.v("DATA","Parity Error Check = " + PacketErrorDetector.makeParallelParity(a)); + Log.v("DATA","Checksum Error Check = " + PacketErrorDetector.makeCheckSum(a)); + Log.v("DATA","ReceivedData = " + mReceivedData); } mChannelArrayList.clear(); } @@ -250,20 +223,16 @@ public void catchSingleData() mSampleIndex = 0 ; mSampleTemp = 0; mChannelTemp = 0; - for(int i = 0; i < RXCHANNEL + STARTCHANNEL ; i++){//// - mFreqArray[i] = 0;//// - }///// + for(int i = 0; i < Constants.CHANNEL + STARTCHANNEL ; i++){ + mFreqArray[i] = 0; + } } } - private int []mArrMaxIndex = new int [RXCHANNEL + STARTCHANNEL]; - private int []mArrSampleIndex = new int [RXCHANNEL + STARTCHANNEL]; - private int []mArrSampleTemp = new int [RXCHANNEL + STARTCHANNEL]; - private int []mArrChannelTemp = new int [RXCHANNEL + STARTCHANNEL]; - public int []mArrcntCheck = new int [RXCHANNEL + STARTCHANNEL]; + public void catchMultiData() { - for(int j = 0; j < RXCHANNEL + STARTCHANNEL ; j++) + for(int j = 0; j < Constants.CHANNEL + STARTCHANNEL ; j++) { mArrMaxIndex[j] = -1; mArrSampleIndex[j] = 0; @@ -272,10 +241,11 @@ public void catchMultiData() mArrcntCheck[j] = 0; mFreqArray[j] = 0; } - int []arrCurrentFreq = new int[RXCHANNEL + STARTCHANNEL]; - for(int i = 0; i < RXCHANNEL + STARTCHANNEL ; i++) + + int []arrCurrentFreq = new int[Constants.CHANNEL + STARTCHANNEL]; + for(int i = 0; i < Constants.CHANNEL + STARTCHANNEL ; i++) { - arrCurrentFreq[i] = (int) this.detectFreq(START_FREQ + mFreqSpan*i); + arrCurrentFreq[i] = (int) this.detectFreq(Constants.STANDARD_FREQ + Constants.CHANNEL_INTERVAL * i); if(arrCurrentFreq[i] >=200){ //mArrSampleTemp[i] = arrCurrentFreq[i]; mArrMaxIndex[i] = i; @@ -297,16 +267,6 @@ public void setmArrMaxIndex(int[] mArrMaxIndex) { this.mArrMaxIndex = mArrMaxIndex; } - /* - public void makeData(int a[]){ - for(int i = 0; i < a.length-1; i+=2){ - char charData = (char)(a[i]*16 + a[i+1]); - receiveStr += charData; - Log.d("charData", a[i]+" "+a[i+1]+" "+receiveStr); - } - } - */ - public int mStartSampleCnt = 0; public Boolean checkStartPoint() { @@ -351,8 +311,8 @@ private Boolean euSpecificFreqSensor(int _freq) dynRef = euGetDynamicRef(curFreq, dynRef, preservedRef, dynRefCnt); if(curFreq >= dynRef){ - int prevFreq = this.detectFreq(_freq - mFreqSpan); - int nextFreq = this.detectFreq(_freq + mFreqSpan); + int prevFreq = this.detectFreq(_freq - Constants.CHANNEL_INTERVAL); + int nextFreq = this.detectFreq(_freq + Constants.CHANNEL_INTERVAL); if(prevFreq > curFreq || nextFreq > curFreq) continue; @@ -402,10 +362,10 @@ public int euGetDynamicRef(int curFreq, int dynRef, int preservedRef, int dynRef } // MAXIMUM and MIMINUM DATA CATCHING - if(dynRef > MAXREFERENCE) - dynRef = MAXREFERENCE; - if(dynRef < MINREFERENCE) - dynRef = MINREFERENCE; + if(dynRef > Constants.MAX_REF) + dynRef = Constants.MAX_REF; + if(dynRef < Constants.MIN_REF) + dynRef = Constants.MIN_REF; return dynRef; } @@ -437,10 +397,10 @@ public int getDynamicReference(int nfreq, int freqIndex) } // MAXIMUM and MIMINUM DATA CATCHING - if(mDynamicRefArray[freqIndex] > MAXREFERENCE) - mDynamicRefArray[freqIndex] = MAXREFERENCE; - if(mDynamicRefArray[freqIndex] < MINREFERENCE) - mDynamicRefArray[freqIndex] = MINREFERENCE; + if(mDynamicRefArray[freqIndex] > Constants.MAX_REF) + mDynamicRefArray[freqIndex] = Constants.MAX_REF; + if(mDynamicRefArray[freqIndex] < Constants.MIN_REF) + mDynamicRefArray[freqIndex] = Constants.MIN_REF; return mDynamicRefArray[freqIndex]; } diff --git a/euphony/src/main/java/co/euphony/rx/EuPI.java b/euphony/src/main/java/co/euphony/rx/EuPI.java new file mode 100644 index 0000000..343ad13 --- /dev/null +++ b/euphony/src/main/java/co/euphony/rx/EuPI.java @@ -0,0 +1,64 @@ +package co.euphony.rx; + +public class EuPI { + public enum EuPITrigger { + KEY_DOWN, KEY_UP, KEY_PRESSED + } + + public enum EuPIStatus { + KEY_DOWN, KEY_UP, KEY_PRESSED + } + + private int mKey; + private int mFreqIndex; + EuPITrigger mTrigger; + EuPIStatus mStatus; + EuPICallDetector mAPICallback; + + public EuPI(int key, EuPICallDetector callback) { + mKey = key; + mAPICallback = callback; + mTrigger = EuPITrigger.KEY_PRESSED; + mStatus = EuPIStatus.KEY_UP; + } + + public EuPI(int key, EuPITrigger trigger, EuPICallDetector callback) { + mKey = key; + mAPICallback = callback; + mTrigger = trigger; + mStatus = EuPIStatus.KEY_UP; + } + + public int getKey() { + return mKey; + } + + public void setFreqIndex(int idx) { + mFreqIndex = idx; + } + + public void setTrigger(EuPITrigger trigger) { + mTrigger = trigger; + } + + public EuPITrigger getTrigger() { + return mTrigger; + } + + public void setStatus(EuPIStatus status) { + mStatus = status; + } + + public EuPIStatus getStatus() { + return mStatus; + } + + public int getFreqIndex() { + return mFreqIndex; + } + + public EuPICallDetector getCallback() { + return mAPICallback; + } + +} diff --git a/euphony/src/main/java/co/euphony/rx/EuPICallDetector.java b/euphony/src/main/java/co/euphony/rx/EuPICallDetector.java new file mode 100644 index 0000000..6e68152 --- /dev/null +++ b/euphony/src/main/java/co/euphony/rx/EuPICallDetector.java @@ -0,0 +1,5 @@ +package co.euphony.rx; + +public interface EuPICallDetector { + void call(); +} diff --git a/euphony/src/main/java/co/euphony/rx/EuRxManager.java b/euphony/src/main/java/co/euphony/rx/EuRxManager.java new file mode 100644 index 0000000..ef65a8f --- /dev/null +++ b/euphony/src/main/java/co/euphony/rx/EuRxManager.java @@ -0,0 +1,398 @@ +package co.euphony.rx; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import java.util.ArrayList; + +import co.euphony.common.Constants; +import co.euphony.util.EuOption; + +import static co.euphony.rx.EuPI.EuPITrigger.KEY_DOWN; +import static co.euphony.rx.EuPI.EuPITrigger.KEY_PRESSED; +import static co.euphony.rx.EuPI.EuPITrigger.KEY_UP; + +public class EuRxManager { + + private final String LOG = "EuRxManager"; + + private Thread mListenThread = null; + private DetectRunner mDetectRunner = null; + private EuPICallRunner mEuPICallRunner = null; + + public enum RxManagerStatus { + RUNNING, STOP + } + + private static final int RX_MODE = 1; + private static final int DETECT_MODE = 2; + private static final int EUPI_CALL_MODE = 3; + + private EuOption mOption; + + public EuRxManager() { + mOption = EuOption.builder() + .modeWith(EuOption.ModeType.DEFAULT) + .encodingWith(EuOption.CodingType.BASE16) + .modulationWith(EuOption.ModulationType.FSK) + .build(); + } + + public EuRxManager(EuOption.ModeType mode) { + mOption = EuOption.builder() + .modeWith(mode) + .build(); + } + + public boolean listen() { + if(getStatus() != RxManagerStatus.RUNNING) { + switch (mOption.getMode()) { + case DEFAULT: + mListenThread = new Thread(new RxRunner(), "RX"); + break; + case EUPI: { + if(mEuPICallRunner != null) { + mListenThread = new Thread(mEuPICallRunner, "EUPI"); + Log.d(LOG, "Euphony : EuPICallRunner's EuPI Count : " + mEuPICallRunner.getEuPICount()); + break; + } + else { + Log.d(LOG, "Euphony : EuPICallRunner is null"); + return false; + } + } + default: + Log.d(LOG, "Detect must have specific frequency value"); + return false; + } + mListenThread.start(); + return true; + } else { + return false; + } + } + + public boolean listen(int freq) { + if(getStatus() != RxManagerStatus.RUNNING) { + if(mOption.getMode() == EuOption.ModeType.DETECT) { + mDetectRunner = new DetectRunner(freq); + mListenThread = new Thread(mDetectRunner, "DETECT"); + mListenThread.start(); + return true; + } else { + Log.d(LOG, "Please use other listen function."); + return false; + } + } else { + return false; + } + } + + public void finish() + { + if(mListenThread != null) { + mListenThread.interrupt(); + } + + mListenThread = null; + } + + public void setOnWaveKeyPressed(int freq, EuPICallDetector iEuPICallDetector) { + EuPI eupi = new EuPI(freq, KEY_PRESSED, iEuPICallDetector); + + if(mEuPICallRunner == null) { + mEuPICallRunner = new EuPICallRunner(eupi); + } else { + mEuPICallRunner.addEuPI(eupi); + } + } + + public void setOnWaveKeyDown(int key, EuPICallDetector iEuPICallDetector) { + EuPI eupi = new EuPI(key, KEY_DOWN, iEuPICallDetector); + + if(mEuPICallRunner == null) { + mEuPICallRunner = new EuPICallRunner(eupi); + } else { + mEuPICallRunner.addEuPI(eupi); + } + } + + public void setOnWaveKeyUp(int key, EuPICallDetector iEuPICallDetector) { + EuPI eupi = new EuPI(key, KEY_UP, iEuPICallDetector); + + if(mEuPICallRunner == null) { + mEuPICallRunner = new EuPICallRunner(eupi); + } else { + mEuPICallRunner.addEuPI(eupi); + } + } + + public void setOnWaveKeyPressed(int freq, double threshold, EuPICallDetector iEuPICallDetector) { + EuPI eupi = new EuPI(freq, KEY_PRESSED, iEuPICallDetector); + + if(mEuPICallRunner == null) { + mEuPICallRunner = new EuPICallRunner(threshold, eupi); + } else { + mEuPICallRunner.addEuPI(eupi); + } + } + + public void setOnWaveKeyDown(int key, double threshold, EuPICallDetector iEuPICallDetector) { + EuPI eupi = new EuPI(key, KEY_DOWN, iEuPICallDetector); + + if(mEuPICallRunner == null) { + mEuPICallRunner = new EuPICallRunner(threshold, eupi); + } else { + mEuPICallRunner.addEuPI(eupi); + } + } + + public void setOnWaveKeyUp(int key, double threshold, EuPICallDetector iEuPICallDetector) { + EuPI eupi = new EuPI(key, KEY_UP, iEuPICallDetector); + + if(mEuPICallRunner == null) { + mEuPICallRunner = new EuPICallRunner(threshold, eupi); + } else { + mEuPICallRunner.addEuPI(eupi); + } + } + + public RxManagerStatus getStatus() { + if(mListenThread != null) { + switch (mListenThread.getState()) { + case RUNNABLE: + return RxManagerStatus.RUNNING; + case NEW: + case WAITING: + case TIMED_WAITING: + case BLOCKED: + case TERMINATED: + default: + return RxManagerStatus.STOP; + } + } else + return RxManagerStatus.STOP; + } + + private AcousticSensor mAcousticSensor; + + public AcousticSensor getAcousticSensor() { + return mAcousticSensor; + } + + public void setAcousticSensor(AcousticSensor iAcousticSensor) { + this.mAcousticSensor = iAcousticSensor; + } + + private final Handler mHandler = new Handler(Looper.getMainLooper()){ + public void handleMessage(Message msg){ + switch(msg.what){ + case RX_MODE: + mAcousticSensor.notify(msg.obj + ""); + break; + case DETECT_MODE: + mFrequencyDetector.detect((float)msg.obj); + break; + case EUPI_CALL_MODE: + EuPI eupi = (EuPI)msg.obj; + eupi.getCallback().call(); + break; + + default: + break; + } + } + }; + + public EuOption getOption() { + return mOption; + } + + public void setOption(EuOption mOption) { + this.mOption = mOption; + } + + private class RxRunner extends EuFreqObject implements Runnable{ + @Override + public void run() + { + while (!Thread.currentThread().isInterrupted()) { + processFFT(); + if (this.getStarted()) + catchSingleData(); + else + this.setStarted(checkStartPoint()); + + if (this.getCompleted()) { + Message msg = mHandler.obtainMessage(); + msg.what = RX_MODE; + msg.obj = null; + if(mOption.getCodingType() == EuOption.CodingType.BASE16) { + msg.obj = EuDataDecoder.decodeStaticHexCharSource(getReceivedData()); + } + this.setCompleted(false); + mHandler.sendMessage(msg); + destroyFFT(); + return; + } + } + + destroyFFT(); + } + } + + private FrequencyDetector mFrequencyDetector; + + public FrequencyDetector getFrequencyDetector() { + return mFrequencyDetector; + } + + public void setFrequencyDetector(FrequencyDetector mFrequencyDetector) { + this.mFrequencyDetector = mFrequencyDetector; + } + + public void setFrequencyForDetect(int freq) { + if(mOption.getMode() == EuOption.ModeType.DETECT) { + if(mDetectRunner != null) + mDetectRunner.setFrequency(freq); + } + } + + private class EuPICallRunner extends EuFreqObject implements Runnable { + + private double mThreshold = 0.0009; + private final ArrayList EuPICallList = new ArrayList<>(); + + EuPICallRunner(EuPI eupi) { + addEuPI(eupi); + Log.d(LOG, "Added " + eupi.getKey() + "(" + eupi.getFreqIndex() + ")"); + } + + EuPICallRunner(double threshold, EuPI eupi) { + mThreshold = threshold; + addEuPI(eupi); + Log.d(LOG, "Added " + eupi.getKey() + "(" + eupi.getFreqIndex() + ")"); + } + + private int calculateFreqIndex(int freq) { + double freqRatio = ((float)freq) / (float)Constants.HALF_SAMPLERATE; + return (int) Math.round((freqRatio * (float) (Constants.FFT_SIZE >> 1))); + } + + private boolean compareThreshold(float amp) { + return amp > mThreshold; + } + + public void addEuPI(EuPI eupi) { + eupi.setFreqIndex(calculateFreqIndex(eupi.getKey())); + EuPICallList.add(eupi); + } + + public int getEuPICount() { + return EuPICallList.size(); + } + + @Override + public void run() { + while(!Thread.currentThread().isInterrupted()) { + processFFT(); + + float[] amp = {0, 0, 0}; + for(EuPI eupi : EuPICallList) { + boolean isActable = false; + switch(eupi.getTrigger()) { + case KEY_DOWN: { + if(eupi.getStatus() == EuPI.EuPIStatus.KEY_UP){ + isActable = true; + } + } + break; + case KEY_UP: { + if(eupi.getStatus() != EuPI.EuPIStatus.KEY_UP) { + isActable = true; + } + } + break; + case KEY_PRESSED: { + isActable = true; + } + break; + } + + int freqIndex = eupi.getFreqIndex(); + amp[0] = getSpectrumValue(freqIndex - 2); + amp[1] = getSpectrumValue(freqIndex); + amp[2] = getSpectrumValue(freqIndex + 2); + + if(isActable) { + if(compareThreshold((amp[1] - (amp[0] + amp[2])/2))) { + if(eupi.getTrigger() == KEY_DOWN || eupi.getTrigger() == KEY_PRESSED) { + Message msg = mHandler.obtainMessage(); + msg.what = EUPI_CALL_MODE; + msg.obj = eupi; + mHandler.sendMessage(msg); + } + + eupi.setStatus(EuPI.EuPIStatus.KEY_DOWN); + } else { + if(eupi.getTrigger() == KEY_UP) { + Message msg = mHandler.obtainMessage(); + msg.what = EUPI_CALL_MODE; + msg.obj = eupi; + mHandler.sendMessage(msg); + } + + eupi.setStatus(EuPI.EuPIStatus.KEY_UP); + } + } else { + if(compareThreshold((amp[1] - (amp[0] + amp[2])/2))) { + eupi.setStatus(EuPI.EuPIStatus.KEY_DOWN); + } else { + eupi.setStatus(EuPI.EuPIStatus.KEY_UP); + } + } + + Log.d(LOG, eupi.getKey() + "(" + eupi.getFreqIndex() + ")" + "'s Amplitude : " + amp[2]); + } + } + + destroyFFT(); + } + } + + private class DetectRunner extends EuFreqObject implements Runnable { + + int mFrequency = 0; + private int mFreqIndex = 0; + DetectRunner(int freq) { + setFrequency(freq); + } + + public void setFrequency(int frequency) { + mFrequency = frequency; + mFreqIndex = ((int)((frequency / 22050.0) * Constants.FFT_SIZE) / 2) + 1; + Log.d(LOG, "Frequency = " + mFrequency + ", mFreqIndex = " + mFreqIndex); + } + + @Override + public void run() { + float previousAmp = 0; + + while (!Thread.currentThread().isInterrupted()) { + processFFT(); + float amp = getSpectrumValue(mFreqIndex); + + if (previousAmp != amp) { + Message msg = mHandler.obtainMessage(); + msg.what = DETECT_MODE; + msg.obj = amp; + mHandler.sendMessage(msg); + previousAmp = amp; + } + } + destroyFFT(); + } + } +} diff --git a/euphony/src/main/java/euphony/lib/receiver/EuWindows.java b/euphony/src/main/java/co/euphony/rx/EuWindows.java similarity index 99% rename from euphony/src/main/java/euphony/lib/receiver/EuWindows.java rename to euphony/src/main/java/co/euphony/rx/EuWindows.java index f9c56c3..8f50648 100644 --- a/euphony/src/main/java/euphony/lib/receiver/EuWindows.java +++ b/euphony/src/main/java/co/euphony/rx/EuWindows.java @@ -1,4 +1,4 @@ -package euphony.lib.receiver; +package co.euphony.rx; import java.nio.ByteBuffer; import java.util.*; diff --git a/euphony/src/main/java/co/euphony/rx/FrequencyDetector.java b/euphony/src/main/java/co/euphony/rx/FrequencyDetector.java new file mode 100644 index 0000000..cece285 --- /dev/null +++ b/euphony/src/main/java/co/euphony/rx/FrequencyDetector.java @@ -0,0 +1,5 @@ +package co.euphony.rx; + +public interface FrequencyDetector { + void detect(float amplitude); +} diff --git a/euphony/src/main/java/euphony/lib/receiver/KissFFT.java b/euphony/src/main/java/co/euphony/rx/KissFFT.java similarity index 68% rename from euphony/src/main/java/euphony/lib/receiver/KissFFT.java rename to euphony/src/main/java/co/euphony/rx/KissFFT.java index e7ae292..b9bd225 100644 --- a/euphony/src/main/java/euphony/lib/receiver/KissFFT.java +++ b/euphony/src/main/java/co/euphony/rx/KissFFT.java @@ -1,4 +1,4 @@ -package euphony.lib.receiver; +package co.euphony.rx; import java.nio.ByteBuffer; @@ -9,90 +9,59 @@ public class KissFFT { - static{ - System.loadLibrary("kissff"); // kiss_fft.c - System.loadLibrary("kissfftr"); // kiss_fftr.c - System.loadLibrary("kissfft"); // KissFFT.cpp - } + static{ + System.loadLibrary("native-legacy"); + } /** the pointer to the kiss fft object **/ private final long handle; - + public KissFFT(int numSamples) { handle = create(numSamples); Log.i("var", " "+handle); } - /** - * Creates a new kiss fft object - * - * @param timeSize - * the number of samples - * @return the handle to the kiss fft object - */ - private native long create(int timeSize); - - /** - * Destroys a kiss fft object - * - * @param handle - * the handle to the kiss fft object - */ - private native void destroy(long handle); - - /** - * Calculates the frequency spectrum of the given samples. There must be as - * many samples as specified in the constructor of this class. Spectrum must - * hold timeSize / 2 + 1 elements - * - * @param handle - * the handle to the kiss fft object - * @param samples - * the samples in 16-bit signed PCM encoding - * @param spectrum - * the spectrum - */ - private native void spectrum(long handle, ShortBuffer samples, - FloatBuffer spectrum); - /** * Calculates the frequency spectrum of the given samples. There must be as * many samples as specified in the constructor of this class. Spectrum must * hold timeSize / 2 + 1 elements - * + * * @param samples * the samples * @param spectrum * the spectrum */ - public void spectrum(ShortBuffer samples, FloatBuffer spectrum) { - spectrum(handle, samples, spectrum); + public void doSpectrums(ShortBuffer samples, FloatBuffer spectrum) { + doSpectrums(handle, samples, spectrum); } /** * Calculates the frequency spectrum of the given samples. There must be as * many samples as specified in the constructor of this class. Spectrum must * hold timeSize / 2 + 1 elements - * + * * @param samples * the samples * @param spectrum * the spectrum */ - public void spectrum(ByteBuffer samples, FloatBuffer spectrum) { - spectrum(samples.asShortBuffer(), spectrum); + public void doSpectrums(ByteBuffer samples, FloatBuffer spectrum) { + doSpectrums(samples.asShortBuffer(), spectrum); + } + + public void doSpectrum(ShortBuffer samples, int sample_idx, long mag_result_address, long dbfs_result_addr) + { + doSpectrum(handle, samples, sample_idx, mag_result_address, dbfs_result_addr); } - private native void spectrum_for_phase(long handle, ShortBuffer samples, FloatBuffer specturm); - public void spectrum_for_phase(ShortBuffer samples, FloatBuffer spectrum) { - spectrum_for_phase(handle, samples, spectrum); + spectrum_for_phase(handle, samples, spectrum); } - + public void spectrum_for_phase(ByteBuffer samples, FloatBuffer spectrum) { - spectrum_for_phase(samples.asShortBuffer(), spectrum); + spectrum_for_phase(samples.asShortBuffer(), spectrum); } /** * Releases all resources of this object @@ -105,19 +74,48 @@ public void getRealPart(ShortBuffer real) { getRealPart(handle, real); } - public void getImagPart(ShortBuffer imag) { - getImagPart(handle, imag); + public void getImagePart(ShortBuffer imag) { + getImagePart(handle, imag); } + /** + * Creates a new kiss fft object + * + * @param timeSize + * the number of samples + * @return the handle to the kiss fft object + */ + private native long create(int timeSize); + + /** + * Destroys a kiss fft object + * + * @param handle + * the handle to the kiss fft object + */ + private native void destroy(long handle); + + private native void doSpectrum(long handle, ShortBuffer samples, int sample_idx, long mag_result, long dbfs_result); + + /** + * Calculates the frequency spectrum of the given samples. There must be as + * many samples as specified in the constructor of this class. Spectrum must + * hold timeSize / 2 + 1 elements + * + * @param handle + * the handle to the kiss fft object + * @param samples + * the samples in 16-bit signed PCM encoding + * @param spectrum + * the spectrum + */ + private native void doSpectrums(long handle, ShortBuffer samples, + FloatBuffer spectrum); + + private native void spectrum_for_phase(long handle, ShortBuffer samples, FloatBuffer specturm); + private native void getRealPart(long handle, ShortBuffer real); - private native void getImagPart(long handle, ShortBuffer imag); - - - - - - - + private native void getImagePart(long handle, ShortBuffer imag); } \ No newline at end of file diff --git a/euphony/src/main/java/co/euphony/tx/EuTxManager.java b/euphony/src/main/java/co/euphony/tx/EuTxManager.java new file mode 100644 index 0000000..25f88ec --- /dev/null +++ b/euphony/src/main/java/co/euphony/tx/EuTxManager.java @@ -0,0 +1,157 @@ +package co.euphony.tx; + +import android.content.Context; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import co.euphony.util.EuOption; + +import static android.media.AudioTrack.SUCCESS; +import static android.media.AudioTrack.WRITE_BLOCKING; + +public class EuTxManager { + private EuTxNativeConnector txCore; + private AudioTrack mAudioTrack = null; + private EuOption.ModeType modeType; + private PlayerEngine playerEngineType; + + public enum EuPIDuration { + LENGTH_SHORT, + LENGTH_LONG, + LENGTH_FOREVER + } + + public enum PlayerEngine { + ANDROID_DEFAULT_ENGINE, + EUPHONY_NATIVE_ENGINE + } + + public EuTxManager(Context context) { + txCore = new EuTxNativeConnector(context); + } + + /* + * @deprecated Replaced by {@link #setCode()}, deprecated for naming & dynamic option. + */ + @Deprecated + public void euInitTransmit(String data) { + setCode(data); + } + + public void setCode(String data) + { + txCore.setCode(data); + } + + public String getCode() { + return txCore.getCode(); + } + + public void callEuPI(double freq, EuPIDuration duration) { + setMode(EuOption.ModeType.EUPI); + txCore.setToneOn(true); + txCore.setAudioFrequency(freq); + txCore.start(); + + if (duration != EuPIDuration.LENGTH_FOREVER) { + new Handler(Looper.getMainLooper()).postDelayed(this::stop, + (duration == EuPIDuration.LENGTH_SHORT) ? 200 : 500); + } + } + + public float[] getOutStream() { + return txCore.getGenWaveSource(); + } + + public String getGenCode() { + return txCore.getGenCode(); + } + + public void play() { + play(1, PlayerEngine.ANDROID_DEFAULT_ENGINE); + } + + public void play(final int count) { + play(count, PlayerEngine.ANDROID_DEFAULT_ENGINE); + } + + public void play(final int count, PlayerEngine engineType) { + playerEngineType = engineType; + setMode(EuOption.ModeType.DEFAULT); + if(engineType == PlayerEngine.EUPHONY_NATIVE_ENGINE) { + playWithNativeEngine(count); + } else { + playWithAndroidEngine(count); + } + } + + private void playWithNativeEngine(final int count) { + txCore.setCountToneOn(true, count); + txCore.start(); + } + + short[] outShortStream; + private void playWithAndroidEngine(int count) { + float[] outStream = txCore.getGenWaveSource(); + + mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, outStream.length*2, AudioTrack.MODE_STATIC); + if(count <= 0) + count = -1; + + int result = mAudioTrack.setLoopPoints(0, outStream.length, count); + if(result != SUCCESS) { + Log.i("PROCESS", "failed to loop points : " + result); + } + + outShortStream = new short[outStream.length]; + for(int i = 0; i < outStream.length; i++) { + outShortStream[i] = (short) (32767 * outStream[i]); + } + + if(mAudioTrack != null){ + try{ + mAudioTrack.write(outShortStream, 0, outShortStream.length); + mAudioTrack.play(); + } + catch(IllegalStateException e) + { + Log.i("PROCESS", e.getMessage()); + } + } + } + + public void setMode(EuOption.ModeType modeType) { + this.modeType = modeType; + txCore.setMode(modeType); + } + + /* + * @deprecated Replaced by {@link #setCode()}, deprecated for naming issue + */ + @Deprecated + public void process() { play(1, PlayerEngine.ANDROID_DEFAULT_ENGINE); } + + /* + * @deprecated Replaced by {@link #setCode()}, deprecated for naming issue + */ + @Deprecated + public void process(int count) { play(count, PlayerEngine.ANDROID_DEFAULT_ENGINE); } + + public void stop() + { + if(modeType == EuOption.ModeType.DEFAULT && playerEngineType == PlayerEngine.ANDROID_DEFAULT_ENGINE) { + if(mAudioTrack != null) + mAudioTrack.pause(); + } + else { + txCore.setToneOn(false); + new Handler(Looper.getMainLooper()).postDelayed(() -> { + txCore.stop(); + }, 300); + } + } +} diff --git a/euphony/src/main/java/co/euphony/tx/EuTxNativeConnector.java b/euphony/src/main/java/co/euphony/tx/EuTxNativeConnector.java new file mode 100644 index 0000000..5e3149d --- /dev/null +++ b/euphony/src/main/java/co/euphony/tx/EuTxNativeConnector.java @@ -0,0 +1,234 @@ +package co.euphony.tx; + +import android.content.Context; +import android.media.AudioManager; +import android.os.Build; +import android.util.Log; + +import co.euphony.util.EuOption; + +public class EuTxNativeConnector { + long mEngineHandle = 0; + + public enum EpnyStatus { + RUNNING, STOP, NO_CREATE + } + + public enum EpnyPerformanceMode { + PowerSavingMode, + NormalMode, + SuperPowerMode + } + + static { + System.loadLibrary("euphony"); + } + + public EuTxNativeConnector() { + if(!create()) { + Log.e("EUPHONY_ERROR","Euphony Engine Creation was failed."); + } else { + Log.d("EUPHONY_MSG","Euphony Engine Creation was successful"); + } + } + + public EuTxNativeConnector(Context context) { + if(!create(context)){ + Log.e("EUPHONY_ERROR","Euphony Engine Creation was failed."); + } else { + Log.d("EUPHONY_MSG","Euphony Engine Creation was successful"); + } + } + + public static EuTxNativeConnector newInstance() { + return new EuTxNativeConnector(); + } + + boolean create() { + if(mEngineHandle == 0) + mEngineHandle = native_createEngine(); + + return (mEngineHandle != 0); + } + + boolean create(Context context) { + if(mEngineHandle == 0) { + setDefaultStreamValues(context); + mEngineHandle = native_createEngine(); + } + + return (mEngineHandle != 0); + } + + void clean() { + if(mEngineHandle != 0) + native_deleteEngine(mEngineHandle); + + mEngineHandle = 0; + } + + public void start() { + if(mEngineHandle != 0) + native_start(mEngineHandle); + } + + public void stop() { + if(mEngineHandle != 0) + native_stop(mEngineHandle); + } + + public void setPerformance(EpnyPerformanceMode mode, Context context) { + if(mEngineHandle != 0) { + switch(mode) { + case PowerSavingMode: + native_setPerformance(mEngineHandle, 0); + break; + case NormalMode: + native_setPerformance(mEngineHandle, 1); + break; + case SuperPowerMode: + native_setPerformance(mEngineHandle, 2); + break; + } + } + } + + public void setCodingType(EuOption.CodingType codingType) { + if(mEngineHandle != 0) { + native_setCodingType(mEngineHandle, codingType.ordinal()); + } + } + + public void setMode(EuOption.ModeType modeType) { + if(mEngineHandle != 0) { + native_setMode(mEngineHandle, modeType.ordinal()); + } + } + + public void setModulation(EuOption.ModulationType modulationType) { + if(mEngineHandle != 0) { + native_setModulation(mEngineHandle, modulationType.ordinal()); + } + } + + private void setDefaultStreamValues(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + AudioManager myAudioMgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + String sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + Log.d("EUPHONY_MSG","This device's samplerate for output : " + sampleRateStr); + int defaultSampleRate = Integer.parseInt(sampleRateStr); + if(defaultSampleRate == 0) defaultSampleRate = 44100; + + String framesPerBurstStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); + Log.d("EUPHONY_MSG","This device's frames per buffer for output : " + framesPerBurstStr); + int defaultFramesPerBurst = Integer.parseInt(framesPerBurstStr); + if(defaultFramesPerBurst == 0) defaultFramesPerBurst = 256; // Use Default + native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst); + } + } + private void setDefaultStreamValues(int sampleRate, int framesPerBurst) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ + native_setDefaultStreamValues(sampleRate, framesPerBurst); + } + } + + public void setToneOn(boolean isToneOn) { + if(mEngineHandle != 0) native_setToneOn(mEngineHandle, isToneOn); + } + + public void setCountToneOn(boolean isToneOn, int count) { + if(mEngineHandle != 0) native_setCountToneOn(mEngineHandle, isToneOn, count); + } + + public void setCode(String data) { + if(mEngineHandle != 0) native_setCode(mEngineHandle, data); + } + + public String getCode() { + if(mEngineHandle != 0) + return native_getCode(mEngineHandle); + return null; + } + + public String getGenCode() { + if(mEngineHandle != 0) + return native_getGenCode(mEngineHandle); + return null; + } + + public float[] getGenWaveSource() { + if(mEngineHandle != 0) + return native_getGenWaveSource(mEngineHandle); + return null; + } + + public void setAudioFrequency(double freq) { + if(mEngineHandle != 0) native_setAudioFrequency(mEngineHandle, freq); + } + + public void setAudioApi(int audioApi){ + if (mEngineHandle != 0) native_setAudioApi(mEngineHandle, audioApi); + } + + public void setAudioDeviceId(int deviceId){ + if (mEngineHandle != 0) native_setAudioDeviceId(mEngineHandle, deviceId); + } + + public void setChannelCount(int channelCount) { + if (mEngineHandle != 0) native_setChannelCount(mEngineHandle, channelCount); + } + + public int getFramesPerBursts(){ + if (mEngineHandle != 0) return native_getFramesPerBursts(mEngineHandle); + else return -1; + } + + public void setBufferSizeInBursts(int bufferSizeInBursts){ + if (mEngineHandle != 0) native_setBufferSizeInBursts(mEngineHandle, bufferSizeInBursts); + } + + public double getCurrentOutputLatencyMillis(){ + if (mEngineHandle == 0) return 0; + return native_getCurrentOutputLatencyMillis(mEngineHandle); + } + + public boolean isLatencyDetectionSupported() { + return mEngineHandle != 0 && native_isLatencyDetectionSupported(mEngineHandle); + } + + public EpnyStatus getStatus() { + if(mEngineHandle == 0) return EpnyStatus.NO_CREATE; + switch(native_getStatus(mEngineHandle)) { + case 0: + return EpnyStatus.RUNNING; + case 1: + return EpnyStatus.STOP; + } + return EpnyStatus.NO_CREATE; + } + + private native long native_createEngine(); + private native void native_deleteEngine(long engineHandle); + private native void native_start(long engineHandle); + private native void native_stop(long engineHandle); + private native int native_getStatus(long engineHandle); + private native void native_setPerformance(long engineHandle, int performanceLevel); + private native void native_setToneOn(long engineHandle, boolean isToneOn); + private native void native_setCountToneOn(long engineHandle, boolean isToneOn, int count); + private native void native_setCode(long engineHandle, String data); + private native void native_setCodingType(long engineHandle, int type); + private native void native_setMode(long engineHandle, int mode); + private native void native_setModulation(long engineHandle, int modulationType); + private native String native_getCode(long engineHandle); + private native String native_getGenCode(long engineHandle); + private native float[] native_getGenWaveSource(long engineHandle); + private native void native_setAudioFrequency(long engineHandle, double frequency); + private native void native_setAudioApi(long engineHandle, int audioApi); + private native void native_setAudioDeviceId(long engineHandle, int deviceId); + private native void native_setChannelCount(long engineHandle, int channelCount); + private native int native_getFramesPerBursts(long engineHandle); + private native void native_setBufferSizeInBursts(long engineHandle, int bufferSizeInBursts); + private native double native_getCurrentOutputLatencyMillis(long engineHandle); + private native boolean native_isLatencyDetectionSupported(long engineHandle); + private native void native_setDefaultStreamValues(int sampleRate, int framesPerBurst); +} diff --git a/euphony/src/main/java/euphony/lib/util/ErrorHandler.java b/euphony/src/main/java/co/euphony/util/ErrorHandler.java similarity index 99% rename from euphony/src/main/java/euphony/lib/util/ErrorHandler.java rename to euphony/src/main/java/co/euphony/util/ErrorHandler.java index 0bcacbd..2b0b793 100644 --- a/euphony/src/main/java/euphony/lib/util/ErrorHandler.java +++ b/euphony/src/main/java/co/euphony/util/ErrorHandler.java @@ -1,4 +1,4 @@ -package euphony.lib.util; +package co.euphony.util; import android.util.Log; diff --git a/euphony/src/main/java/euphony/lib/util/EuCodec.java b/euphony/src/main/java/co/euphony/util/EuCodec.java similarity index 94% rename from euphony/src/main/java/euphony/lib/util/EuCodec.java rename to euphony/src/main/java/co/euphony/util/EuCodec.java index cfaf4ba..f7351ef 100644 --- a/euphony/src/main/java/euphony/lib/util/EuCodec.java +++ b/euphony/src/main/java/co/euphony/util/EuCodec.java @@ -1,4 +1,4 @@ -package euphony.lib.util; +package co.euphony.util; import java.util.Arrays; diff --git a/euphony/src/main/java/co/euphony/util/EuOption.java b/euphony/src/main/java/co/euphony/util/EuOption.java new file mode 100644 index 0000000..faa8e38 --- /dev/null +++ b/euphony/src/main/java/co/euphony/util/EuOption.java @@ -0,0 +1,88 @@ +package co.euphony.util; + +public class EuOption { + public enum CodingType { + BASE2, BASE16 + } + + public enum ModeType { + DEFAULT, + EUPI, + DETECT + } + + public enum ModulationType { + FSK, + /* + TODO: v0.7.1.6 had ASK feature. but v0.8 has to create it. + ASK, + */ + /* + TODO: Rearchitecturing necessary because the CPFSK modulation type has some glitch sound. + CPFSK + */ + } + + private CodingType mCodingType; + private ModeType mModeType; + private ModulationType mModulationType; + + public EuOption(CodingType codingType, ModeType modeType, ModulationType modulationType) { + mCodingType = codingType; + mModeType = modeType; + mModulationType = modulationType; + } + + public CodingType getCodingType() { + return mCodingType; + } + + public void setCodingType(CodingType mCodingType) { + this.mCodingType = mCodingType; + } + + public ModeType getMode() { + return mModeType; + } + + public void setMode(ModeType mModeType) { + this.mModeType = mModeType; + } + + public ModulationType getModulationType() { + return mModulationType; + } + + public void setModulationType(ModulationType mModulationType) { + this.mModulationType = mModulationType; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private CodingType codingType; + private ModeType commMode; + private ModulationType modulationType; + + public Builder encodingWith(CodingType type) { + codingType = type; + return this; + } + + public Builder modeWith(ModeType mode) { + commMode = mode; + return this; + } + + public Builder modulationWith(ModulationType type) { + modulationType = type; + return this; + } + + public EuOption build() { + return new EuOption(codingType, commMode, modulationType); + } + } +} diff --git a/euphony/src/main/java/euphony/lib/util/PacketErrorDetector.java b/euphony/src/main/java/co/euphony/util/PacketErrorDetector.java similarity index 97% rename from euphony/src/main/java/euphony/lib/util/PacketErrorDetector.java rename to euphony/src/main/java/co/euphony/util/PacketErrorDetector.java index 8242a5b..3d9d484 100644 --- a/euphony/src/main/java/euphony/lib/util/PacketErrorDetector.java +++ b/euphony/src/main/java/co/euphony/util/PacketErrorDetector.java @@ -1,4 +1,4 @@ -package euphony.lib.util; +package co.euphony.util; import android.util.Log; @@ -64,7 +64,7 @@ public static boolean checkEvenParity(int[] payload, int nParityBit){ * return type : int * the EvenParity data to transmit *****************************************************/ - public static int makeParellelParity(int payLoad){ + public static int makeParallelParity(int payLoad){ int evenParity1 = ((0x8 & payLoad) >> 3); int evenParity2 = ((0x4 & payLoad) >> 2); int evenParity3 = ((0x2 & payLoad) >> 1); @@ -85,7 +85,7 @@ public static int makeParellelParity(int payLoad){ * return type : int * the EvenParity data to transmit *****************************************************/ - public static int makeParellelParity(int[] payLoad){ + public static int makeParallelParity(int[] payLoad){ int evenParity1 = 0; int evenParity2 = 0; int evenParity3 = 0; diff --git a/euphony/src/main/java/euphony/lib/receiver/EuRxManager.java b/euphony/src/main/java/euphony/lib/receiver/EuRxManager.java deleted file mode 100644 index 0f0ad86..0000000 --- a/euphony/src/main/java/euphony/lib/receiver/EuRxManager.java +++ /dev/null @@ -1,222 +0,0 @@ -package euphony.lib.receiver; - -import euphony.lib.util.COMMON; -import android.os.Handler; -import android.os.Message; -import android.util.Log; - -public class EuRxManager { - private Thread mRxThread = null; - private RxRunner mRxRunner = null; - private PsRunner mPsRunner = null; - private Thread mPsThread = null; - private boolean _active; - - private static final int RX_DECODE = 1; - private static final int PS_DECODE = 2; - - private boolean mHex = false; - public EuRxManager() { } - public EuRxManager(boolean hex) { mHex = hex; } - - public void listen() - { - listen(mHex); - } - - public void listen(boolean hex) { - _active = true; - mRxRunner = new RxRunner(hex); - mRxThread = new Thread(mRxRunner, "RX"); - mRxThread.start(); - } - - public void find() - { - _active = true; - mPsRunner = new PsRunner(); - mPsThread = new Thread(mPsRunner, "PS"); - mPsThread.start(); - } - - public void finishToFind() - { - if(mPsThread != null) { - _active = false; - while (true) { - try { - mPsThread.join(); - break; - } catch (InterruptedException e) { - Log.i("FINISH", e.getMessage()); - } - } - } - - if(mPsRunner != null) - mPsRunner.destroyFFT(); - - mPsThread = null; - mPsRunner = null; - } - - public void finish() - { - if(mRxThread != null) { - _active = false; - while (true) { - try { - mRxThread.join(); - break; - } catch (InterruptedException e) { - Log.i("FINISH", e.getMessage()); - } - } - } - if(mRxRunner != null) - mRxRunner.destroyFFT(); - - mRxThread = null; - mRxRunner = null; - } - - private AcousticSensor mAcousticSensor; - - public AcousticSensor getAcousticSensor() { - return mAcousticSensor; - } - - public void setAcousticSensor(AcousticSensor iAcousticSensor) { - this.mAcousticSensor = iAcousticSensor; - } - - private Handler mHandler = new Handler(){ - public void handleMessage(Message msg){ - switch(msg.what){ - case RX_DECODE: - mAcousticSensor.notify(msg.obj + ""); - break; - default: - break; - } - } - }; - - private PositionDetector mPositionDetector; - - public PositionDetector getPositionDetector() { - return mPositionDetector; - } - - public void setPositionDetector(PositionDetector detector) { - this.mPositionDetector = detector; - } - - private Handler mPsHandler = new Handler() { - public void handleMessage(Message msg) { - switch(msg.what){ - case PS_DECODE: - mPositionDetector.detectSignal((Integer)msg.obj); - break; - } - } - }; - - private class RxRunner extends EuFreqObject implements Runnable{ - boolean mHex = false; - RxRunner() { } - RxRunner(boolean hex) { - mHex = hex; - } - @Override - public void run() - { - while (_active) - { - processFFT(); - if(this.getStarted()) - catchSingleData(); - else - this.setStarted(checkStartPoint()); - - if(this.getCompleted()){ - Message msg = mHandler.obtainMessage(); - msg.what = RX_DECODE; - msg.obj = (mHex) ? getReceivedData() : EuDataDecoder.decodeStaticHexCharSource(getReceivedData()); - this.setCompleted(false); - mHandler.sendMessage(msg); - mRxRunner.destroyFFT(); - return; - } - } - } - } - - private class PsRunner extends EuFreqObject implements Runnable { - - @Override - public void run() { - boolean startswt = false; - int startcnt = 0; - int specificFreq = 0; - Log.i("START", "START LISTEN"); - while(_active) { - //To find the frequency point - while(!startswt) { - processFFT(); - int i; - for(i = 21000; i >= 16500; i-=COMMON.CHANNEL_SPAN) - if(100 < detectFreq(i)){ - startswt = true; - break; - } - specificFreq = i; - - //there is no af area.. - if(startcnt++ > 1000){ - _active = false; - startswt = true; - Log.i("START", "FAILED to find any position"); - } - } - - int signal, max_signal = 0, avr_signal = 0; - int noSignalCnt=0, processingCnt = 0, maxCnt=0; - do{ - processFFT(); - signal = detectFreq(specificFreq); - - if(signal < 20) - noSignalCnt++; - else{ - noSignalCnt = 0; - - if(max_signal < signal){ - maxCnt++; - max_signal = signal; - avr_signal += max_signal; - } - if(++processingCnt > 50){ - avr_signal /= maxCnt; - Message msg = mPsHandler.obtainMessage(); - msg.what = PS_DECODE; - msg.obj = avr_signal; - mPsHandler.sendMessage(msg); - processingCnt = 0; - max_signal = 0; - avr_signal = 0; - maxCnt = 0; - } - } - }while(noSignalCnt < 50 && _active); - - Message msg = mPsHandler.obtainMessage(); - msg.what = PS_DECODE; - msg.obj = -1; - mPsHandler.sendMessage(msg); - break; - - } - } - } -} diff --git a/euphony/src/main/java/euphony/lib/receiver/PositionDetector.java b/euphony/src/main/java/euphony/lib/receiver/PositionDetector.java deleted file mode 100644 index 2b3eb04..0000000 --- a/euphony/src/main/java/euphony/lib/receiver/PositionDetector.java +++ /dev/null @@ -1,6 +0,0 @@ -package euphony.lib.receiver; - -public interface PositionDetector { - void detectSignal(int signal); - void detectFq(int fq); -} diff --git a/euphony/src/main/java/euphony/lib/transmitter/EuCodeMaker.java b/euphony/src/main/java/euphony/lib/transmitter/EuCodeMaker.java deleted file mode 100644 index 4c553af..0000000 --- a/euphony/src/main/java/euphony/lib/transmitter/EuCodeMaker.java +++ /dev/null @@ -1,211 +0,0 @@ -package euphony.lib.transmitter; - -import android.util.Log; -import euphony.lib.util.PacketErrorDetector; - -public class EuCodeMaker extends EuFreqGenerator { - String mMainString; - short[] mCodeSource; - public int START_BIT = getFreqBasePoint() - getFreqSpan(); - - public static enum CHANNEL { - SINGLE, MULTI, EXINGLE - } - - private CHANNEL mChannelMode = CHANNEL.EXINGLE; - - public EuCodeMaker() - { } - - public EuCodeMaker(CHANNEL channelMode) - { - mChannelMode = channelMode; - } - - - public short[] assembleData(String data) - { - short[] assembledData = applyCrossFade(makeStaticFrequency(START_BIT, 0)); - int[] payload = new int[data.length() + 1]; - int payloadSum = 0; - - switch(mChannelMode) - { - case SINGLE: - for(int i = 0; i < data.length(); i++) - { - switch(data.charAt(i)) - { - case '0': - assembledData = appendRawData(assembledData, getZeroSource()); - break; - case '1': - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint(),0))); - break; - } - } - break; - - case MULTI: - for(int i = 0; i < data.length(); i++) - { - switch(data.charAt(i)) - { - case '0': - break; - case '1': - assembledData = mixingRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan()*(i+1), 0))); - break; - } - } - break; - - case EXINGLE: - for(int i = 0; i < data.length(); i++){ - char ch = data.charAt(i); - switch(ch) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * (ch - '0'), 0))); - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * (ch - 'a' + 10), 0))); - break; - } - } - break; - } - - for(int i = 0; i < data.length(); i++){ - switch(data.charAt(i)) - { - case '0': case '1': - case '2': case '3': - case '4': case '5': - case '6': case '7': - case '8': case '9': - payload[i] = data.charAt(i) - '0'; - break; - case 'a': case 'b': - case 'c': case 'd': - case 'e': case 'f': - payload[i] = (data.charAt(i) - 'a') + 10; - break; - } - payloadSum += payload[i]; - } - int checksum = PacketErrorDetector.makeCheckSum(payloadSum); - int parity = PacketErrorDetector.makeParellelParity(payload); - - Log.i("euphony_code", "CODE" + data + "CHECKSUM : " + checksum + " PARITY : " + parity); - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * checksum, 0))); - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * parity, 0))); - - return assembledData; - } - - public short[] assembleLiveData(String data) - { - short[] liveStartData = applyCrossFade(makeStaticFrequency(START_BIT - getFreqSpan(), 0)); - short[] startData = applyCrossFade(makeStaticFrequency(START_BIT, 0)); - short[] assembledData = liveStartData.clone(); - int[] payload = new int[data.length() + 1]; - int payloadSum = 0; - - switch(mChannelMode) - { - case SINGLE: - for(int i = 0; i < data.length(); i++) - { - switch(data.charAt(i)) - { - case '0': - assembledData = appendRawData(assembledData, getZeroSource()); - break; - case '1': - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint(),0))); - break; - } - // checksum - assembledData = appendRawData(assembledData, makeFrequencyWithValue(PacketErrorDetector.makeCheckSum(data.charAt(i) - '0'))); - // parity check - assembledData = appendRawData(assembledData, makeFrequencyWithValue(PacketErrorDetector.makeParellelParity(data.charAt(i) - '0'))); - // final code - assembledData = appendRawData(assembledData, startData); - } - break; - - case MULTI: - for(int i = 0; i < data.length(); i++) - { - switch(data.charAt(i)) - { - case '0': - break; - case '1': - assembledData = mixingRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan()*(i+1), 0))); - break; - } - // checksum - assembledData = appendRawData(assembledData, makeFrequencyWithValue(PacketErrorDetector.makeCheckSum(data.charAt(i) - '0'))); - // parity check - assembledData = appendRawData(assembledData, makeFrequencyWithValue(PacketErrorDetector.makeParellelParity(data.charAt(i) - '0'))); - // final code - assembledData = appendRawData(assembledData, startData); - } - - break; - - case EXINGLE: - for(int i = 0; i < data.length(); i++){ - char ch = data.charAt(i); - switch(ch) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * (ch - '0'), 0))); - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - assembledData = appendRawData(assembledData, applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * (ch - 'a' + 10), 0))); - break; - } - // checksum - assembledData = appendRawData(assembledData, makeFrequencyWithValue(PacketErrorDetector.makeCheckSum(ch - '0'))); - // parity check - assembledData = appendRawData(assembledData, makeFrequencyWithValue(PacketErrorDetector.makeParellelParity(ch - '0'))); - // final code - assembledData = appendRawData(assembledData, startData); - } - break; - } - - return assembledData; - } -} diff --git a/euphony/src/main/java/euphony/lib/transmitter/EuDataEncoder.java b/euphony/src/main/java/euphony/lib/transmitter/EuDataEncoder.java deleted file mode 100644 index 1c4a7df..0000000 --- a/euphony/src/main/java/euphony/lib/transmitter/EuDataEncoder.java +++ /dev/null @@ -1,75 +0,0 @@ -package euphony.lib.transmitter; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Arrays; - -import euphony.lib.util.EuCodec; - -public class EuDataEncoder extends EuCodec { - private String mOriginalSource; - - EuDataEncoder() { - } - - public EuDataEncoder(String _source) { - mOriginalSource = _source; - } - - public String encodeHexCharSource() { - return encodeStaticHexCharSource(mOriginalSource); - } - - public static String encodeStaticHexCharSource(String _source) { - StringBuilder strBuilder = new StringBuilder(); - - for (int i = 0; i < _source.length(); i++) { - int data = _source.charAt(i); - strBuilder.append(Integer.toHexString(data)); - } - - return strBuilder.toString(); - } - - /* - TODO: 40 BASE should be implemented. - public static byte[] base40StaticEncode(String _source) - { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(baos); - for(int i = 0; i < _source.length(); i+=3) - { - switch(Math.min(3, _source.length() - i)) { - case 1: - byte b = base40Index[_source.charAt(i)]; - dos.writeByte(b); - break; - case 2: - char ch = (char) ((base40Index[_source.charAt(i+1)]) * 40 + base40Index[_source.charAt(i)]); - dos.writeChar(ch); - break; - case 3: - char ch2 = (char) ((char) ((base40Index[_source.charAt(i+2)]) * 40 + base40Index[_source.charAt(i+1)]) * 40 + base40Index[_source.charAt(i)]); - dos.writeChar(ch2); - - break; - } - } - return baos.toByteArray(); - } - catch(IOException e) - { - throw new AssertionError(e); - } - } - */ - - public String getOriginalSource() { - return mOriginalSource; - } - public void setOriginalSource(String mOriginalSource) { - this.mOriginalSource = mOriginalSource; - } -} diff --git a/euphony/src/main/java/euphony/lib/transmitter/EuFreqGenerator.java b/euphony/src/main/java/euphony/lib/transmitter/EuFreqGenerator.java deleted file mode 100644 index a051eb5..0000000 --- a/euphony/src/main/java/euphony/lib/transmitter/EuFreqGenerator.java +++ /dev/null @@ -1,167 +0,0 @@ -package euphony.lib.transmitter; - -import euphony.lib.util.COMMON; - -public class EuFreqGenerator { - - // FIXED ACOUSTIC DATA - public final int SAMPLERATE = COMMON.SAMPLERATE;//44100; - public final int DATA_LENGTH = COMMON.DATA_LENGTH;//2048; - public final double PI = Math.PI; - public final double PI2 = PI * 2; - - // Member for Frequency point - // DEFAULT DEFINITION - private int mFreqBasePoint = COMMON.START_FREQ; - private int mFreqSpan = COMMON.CHANNEL_SPAN; //86 - private short[] mZeroSource = new short[DATA_LENGTH]; - - public EuFreqGenerator() { } - - public EuFreqGenerator(int freqStartPoint, int freqSpan) - { - mFreqSpan = freqSpan; - mFreqBasePoint = freqStartPoint; - } - - public short[] makeStaticFrequency(int freq, int degree) - { - double[] double_source = new double[DATA_LENGTH]; - short[] source = new short[DATA_LENGTH]; - double time, phase; - - for(int i = 0; i < DATA_LENGTH; i++) - { - time = (double)i / (double)SAMPLERATE; - double_source[i] = Math.sin(PI2 * (double)freq * time); - source[i] = (short)(32767 * double_source[i]); - } - - return source; - } - - public void euMakeFrequency(short[] source, int freq) - { - source = makeStaticFrequency(freq, 0); - } - - public short[] makeFrequencyWithCrossFade(int freq) - { - return applyCrossFade(makeStaticFrequency(freq, 0)); - } - - public short[] makeFrequencyWithValue(int value) { - return applyCrossFade(makeStaticFrequency(getFreqBasePoint() + getFreqSpan() * value, 0)); - } - - public short[] applyCrossFade(short[] source) - { - double mini_window; - int fade_section = COMMON.FADE_RANGE; - for(int i = 0; i < fade_section; i++) - { - mini_window = (double)i / (double)fade_section; - source[i] *= mini_window; - source[DATA_LENGTH-1-i] *= mini_window; - } - - return source; - } - - public short[] appendRawData(short[] src, short[] objective) - { - int SRC_LENGTH, TOTAL_LENGTH; - if(src == null) - SRC_LENGTH = 0; - else - SRC_LENGTH = src.length; - TOTAL_LENGTH = SRC_LENGTH + objective.length; - - short[] dest = new short[TOTAL_LENGTH]; - - for(int i = 0; i < SRC_LENGTH; i++) - dest[i] = src[i]; - for(int i = SRC_LENGTH; i < TOTAL_LENGTH; i++) - dest[i] = objective[i - SRC_LENGTH]; - - return dest; - } - - public short[] euLinkRawData(short[]... sources) - { - short[] dest = new short[sources.length * DATA_LENGTH]; - - for(int i = 0; i < sources.length; i++) - for(int j = 0; j < sources[i].length; j++) - dest[j + i * DATA_LENGTH] = sources[i][j]; - - return dest; - } - - public short[] euLinkRawData(boolean isCrossfaded, short[]... sources) - { - short[] dest = new short[sources.length * DATA_LENGTH]; - for(int i = 0; i < sources.length; i++) - { - if(isCrossfaded) - sources[i] = applyCrossFade(sources[i]); - - for(int j = 0; j < sources[i].length; j++) - dest[j + i * DATA_LENGTH] = sources[i][j]; - } - - return dest; - } - - public short[] mixingRawData(short[]... sources) - { - short[] dest = sources[0].clone(); - - for(int i = 1; i < sources.length; i++) - { - for(int j = 0; j < sources[i].length; j++){ - dest[j] = (short) (((int)dest[j] + (int)sources[i][j])/2); - } - } - return dest; - } - - public short[] euMakeMaximumVolume(short[] source) - { - int max = 0; - //SCAN FOR VOLUME UP - for (short i1 : source) - if (max < Math.abs(i1)) - max = i1; - if(32767 == max) - return source; - - for(int i = 0; i < source.length; i++) - source[i] *= 32767/max; - - return source; - } - - public short[] getZeroSource() { - return mZeroSource; - } - - public int getFreqBasePoint() { - return mFreqBasePoint; - } - - public void setFreqBasePoint(int mFreqBasePoint) { - this.mFreqBasePoint = mFreqBasePoint; - } - - public int getFreqSpan() { - return mFreqSpan; - } - - public void setFreqSpan(int mFreqSpan) { - this.mFreqSpan = mFreqSpan; - } - - -} - diff --git a/euphony/src/main/java/euphony/lib/transmitter/EuPlayer.java b/euphony/src/main/java/euphony/lib/transmitter/EuPlayer.java deleted file mode 100644 index da741e8..0000000 --- a/euphony/src/main/java/euphony/lib/transmitter/EuPlayer.java +++ /dev/null @@ -1,41 +0,0 @@ -package euphony.lib.transmitter; - -import euphony.lib.util.COMMON; -import android.media.AudioFormat; -import android.media.AudioManager; -import android.media.AudioTrack; - -public class EuPlayer { - - private short[] mSource; - private AudioTrack mAudioTrack = null; - private final int DATA_LENGTH = COMMON.FFT_SIZE * 4;//2048; - private short[] mZeroSource = new short[DATA_LENGTH]; - - public EuPlayer() { } - - public EuPlayer(short[] src) - { - this.setSource(src); - } - - public void setSource(short[] src) - { - mSource = src; - mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, src.length*2, AudioTrack.MODE_STATIC); - } - - public void Play() - { - mAudioTrack.write(mSource, 0, mSource.length); - mAudioTrack.setLoopPoints(0, mSource.length, -1); - mAudioTrack.play(); - } - - public void Stop() - { - if(mAudioTrack != null) - if(mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) - mAudioTrack.pause(); - } -} diff --git a/euphony/src/main/java/euphony/lib/transmitter/EuTxManager.java b/euphony/src/main/java/euphony/lib/transmitter/EuTxManager.java deleted file mode 100644 index dc5529c..0000000 --- a/euphony/src/main/java/euphony/lib/transmitter/EuTxManager.java +++ /dev/null @@ -1,111 +0,0 @@ -package euphony.lib.transmitter; - -import android.content.Context; -import android.media.AudioFormat; -import android.media.AudioManager; -import android.media.AudioTrack; -import android.util.Log; - -import euphony.lib.util.EuOption; - -public class EuTxManager { - private AudioTrack mAudioTrack = null; - private EuOption mTxOption = null; - private EuCodeMaker mCodeMaker = new EuCodeMaker(); - private EuDataEncoder mDataEncoder = new EuDataEncoder(); - - public short[] getOutStream() { - return mOutStream; - } - - private short[] mOutStream; - - public EuTxManager() { - mTxOption = new EuOption(EuOption.EncodingType.ASCII, EuOption.CommunicationMode.GENERAL); - } - - public EuTxManager(EuOption option) { - mTxOption = option; - } - - /* - * @deprecated Replaced by {@link #setCode()}, deprecated for naming & dynamic option. - */ - @Deprecated - public void euInitTransmit(String data) { - setCode(data); - } - - public void setCode(String data) - { - String code = data; - - // set encoding code. - switch(mTxOption.getEncodingType()) { - case ASCII: - code = mDataEncoder.encodeStaticHexCharSource(data); - break; - case HEX: - break; - } - - // set communication mode. - switch(mTxOption.getCommunicationMode()) { - case GENERAL: - mOutStream = mCodeMaker.assembleData(code); - break; - case LIVE: - mOutStream = mCodeMaker.assembleLiveData(code); - break; - } - } - - public void process() { process(1); } - - public void process(int count) - { - if(count > 0) - mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mOutStream.length*2, AudioTrack.MODE_STREAM); - else { - mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mOutStream.length*2, AudioTrack.MODE_STATIC); - count = -1; - } - - mAudioTrack.setLoopPoints(0, mOutStream.length, count); - - if(mAudioTrack != null){ - try{ - mAudioTrack.write(mOutStream, 0, mOutStream.length); - mAudioTrack.play(); - } - catch(IllegalStateException e) - { - Log.i("PROCESS", e.getMessage()); - } - } - } - - public void stop() - { - if(mAudioTrack != null) - mAudioTrack.pause(); - } - - public void setSoftVolume(float ratio) - { - for(int i = 0; i < mOutStream.length; i++) - mOutStream[i] *= ratio; - } - - public void setSystemVolumeMax(Context _context) - { - AudioManager am = (AudioManager) _context.getSystemService(Context.AUDIO_SERVICE); - - if (am != null) { - am.setStreamVolume( - AudioManager.STREAM_MUSIC, - am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), - 0); - } - } -} diff --git a/euphony/src/main/java/euphony/lib/util/COMMON.java b/euphony/src/main/java/euphony/lib/util/COMMON.java deleted file mode 100644 index 2da1657..0000000 --- a/euphony/src/main/java/euphony/lib/util/COMMON.java +++ /dev/null @@ -1,21 +0,0 @@ -package euphony.lib.util; - -public interface COMMON { - // RX & TX COMMON VARIABLES - int SAMPLERATE = 44100; - int FFT_SIZE = 512; - int DATA_LENGTH = FFT_SIZE * 4; - int FADE_RANGE = DATA_LENGTH / 16; - - double MAX_FREQ = 22050.0; - int START_FREQ = 18000; - int CHANNEL = 16; - int CHANNEL_SPAN = SAMPLERATE / FFT_SIZE; // Frequency Interval - int BUNDLE_INTERVAL = CHANNEL_SPAN * CHANNEL; - - // RX - int MAX_REF = 4000; - int MIN_REF = 50; - - int DEFAULT_REF = 500; // BASE Reference value -} diff --git a/euphony/src/main/java/euphony/lib/util/EuAfRangeFinder.java b/euphony/src/main/java/euphony/lib/util/EuAfRangeFinder.java deleted file mode 100644 index 3554633..0000000 --- a/euphony/src/main/java/euphony/lib/util/EuAfRangeFinder.java +++ /dev/null @@ -1,127 +0,0 @@ -package euphony.lib.util; - -import android.os.Handler; -import android.os.Message; -import android.util.Log; - -import euphony.lib.receiver.EuFreqObject; -import euphony.lib.receiver.PositionDetector; -import euphony.lib.transmitter.EuFreqGenerator; -import euphony.lib.transmitter.EuPlayer; - -public class EuAfRangeFinder { - - EuFreqGenerator mEuFreqGenerator; - EuPlayer mEuPlayer; - EuFreqObject mEuObject; - GettingFQRunner mFQRunner; - - private static final int RX_FREQ = 2; - private static final int RX_REF = 3; - - public EuAfRangeFinder() { - ClassInitializer(); - } - - private void ClassInitializer(){ - mEuFreqGenerator = new EuFreqGenerator(); - mEuPlayer = new EuPlayer(); - mEuObject = new EuFreqObject(); - } - - - PositionDetector mPositionDetector; - public void setPositionDetector(PositionDetector detector) { - this.mPositionDetector = detector; - } - - Handler mHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - // TODO Auto-generated method stub - super.handleMessage(msg); - switch(msg.what) - { - case RX_FREQ: - mSuitableFreq = (Integer)msg.obj; - mPositionDetector.detectFq(mSuitableFreq); - - mFQRunner = null; - break; - } - } - - }; - - int mSuitableFreq; - - public void findSuitableChannel() - { - ClassInitializer(); - mFQRunner = new GettingFQRunner(); - mFQRunner.start(); - } - public void stopFindingChannel() - { - while(mFQRunner.isAlive()) - { - try { - mFQRunner.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - mFQRunner = null; - } - - public - - class GettingFQRunner extends Thread { - - int ref = 0; - int current_freq = 21000;//(int)COMMON.MAX_FREQ - 1000; - - @Override - public void run() { - - do - { - mEuPlayer.setSource(mEuFreqGenerator.applyCrossFade(mEuFreqGenerator.makeStaticFrequency(current_freq, 0))); - try{ mEuPlayer.Play(); } - catch(IllegalStateException e) - { - mEuPlayer = new EuPlayer(); - Log.e("PLAY", e.getMessage().toString()); - continue; - } - int cnt = 0; - do { - mEuObject.processFFT(); - ref = mEuObject.detectFreq(current_freq); - }while(ref <= 250 && cnt++ < 50); - - Log.i("RANGE", ref + " : " + current_freq); - current_freq -= COMMON.CHANNEL_SPAN; - try { mEuPlayer.Stop(); } - catch(IllegalStateException e) - { - mEuPlayer = new EuPlayer(); - Log.e("PLAY", e.getMessage().toString()); - continue; - } - }while(ref <= 250 && current_freq > 16500); - - current_freq += COMMON.CHANNEL_SPAN; - - Message msg = mHandler.obtainMessage(); - msg.what = RX_FREQ; - msg.obj = current_freq; - mHandler.sendMessage(msg); - - mEuObject.destroyFFT(); - } - }; - -} diff --git a/euphony/src/main/java/euphony/lib/util/EuOption.java b/euphony/src/main/java/euphony/lib/util/EuOption.java deleted file mode 100644 index 8f49755..0000000 --- a/euphony/src/main/java/euphony/lib/util/EuOption.java +++ /dev/null @@ -1,37 +0,0 @@ -package euphony.lib.util; - -public class EuOption { - public enum EncodingType { - ASCII, HEX - } - - public enum CommunicationMode { - GENERAL, - LIVE - } - - private EncodingType mEncodingType; - private CommunicationMode mCommunicationMode; - - public EuOption() {} - public EuOption(EncodingType _encodingType, CommunicationMode _commMode) { - mEncodingType = _encodingType; - mCommunicationMode = _commMode; - } - - public EncodingType getEncodingType() { - return mEncodingType; - } - - public void setEncodingType(EncodingType mEncodingType) { - this.mEncodingType = mEncodingType; - } - - public CommunicationMode getCommunicationMode() { - return mCommunicationMode; - } - - public void setCommunicationMode(CommunicationMode mCommunicationMode) { - this.mCommunicationMode = mCommunicationMode; - } -} diff --git a/euphony/src/main/jni/Android.mk b/euphony/src/main/jni/Android.mk deleted file mode 100644 index 839d5ad..0000000 --- a/euphony/src/main/jni/Android.mk +++ /dev/null @@ -1,74 +0,0 @@ -LOCAL_PATH := $(call my-dir) -LOCAL_C_INCLUDES += $(LOCAL_PATH)/jni -LOCAL_ALLOW_UNDEFINED_SYMBOLS := true - - -include $(CLEAR_VARS) - - -LOCAL_MODULE := kissff -LOCAL_SRC_FILES := kiss_fft.c -LOCAL_LDLIBS := -llog -LOCAL_ARM_MODE := arm -LOCAL_CFLAGS := -O2 -Wall -D__ANDROID__ -LOCAL_CFLAGS += -DFIXED_POINT - - -include $(BUILD_SHARED_LIBRARY) - - - - - -include $(CLEAR_VARS) - - - -LOCAL_MODULE := kissfftr -LOCAL_SRC_FILES := kiss_fftr.c -LOCAL_LDLIBS := -llog -LOCAL_STATIC_LIBRARIES := kissff -LOCAL_ARM_MODE := arm -LOCAL_CFLAGS := -O2 -Wall -D__ANDROID__ - -LOCAL_CFLAGS += -DFIXED_POINT -include $(BUILD_SHARED_LIBRARY) - - - - - -include $(CLEAR_VARS) - -#APP_STL := gnustl_static -#APP_CPPFLAGS += -frtti -#APP_CPPFLAGS += -fexceptions -#LOCAL_ALLOW_UNDEFINED_SYMBOLS := true -LOCAL_ARM_MODE := arm - -LOCAL_CFLAGS := -O2 -Wall -D__ANDROID__ -LOCAL_CFLAGS += -DFIXED_POINT - - - -LOCAL_MODULE := kissfft -#LOCAL_SRC_FILES := $(wildcard jni/*.c) -LOCAL_SRC_FILES := euphony_lib_receiver_KissFFT.cpp -#LOCAL_SRC_FILES := ca_uol_aig_fftpack_KissFFT.cpp \ kiss_fftr.c \ kiss_fft.c -LOCAL_LDLIBS := -llog - -LOCAL_STATIC_LIBRARIES := kissfftr - - - - - -include $(BUILD_SHARED_LIBRARY) - - - - - - - - diff --git a/euphony/src/main/jni/Application.mk b/euphony/src/main/jni/Application.mk deleted file mode 100644 index 3862d6a..0000000 --- a/euphony/src/main/jni/Application.mk +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := armeabi-v7a, arm64-v8a \ No newline at end of file diff --git a/euphony/src/main/jni/com_euphony_fft_KissFFT.h b/euphony/src/main/jni/com_euphony_fft_KissFFT.h deleted file mode 100644 index 4816245..0000000 --- a/euphony/src/main/jni/com_euphony_fft_KissFFT.h +++ /dev/null @@ -1,53 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_euphony_fft_KissFFT */ - -#ifndef _Included_com_euphony_fft_KissFFT -#define _Included_com_euphony_fft_KissFFT -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_euphony_fft_KissFFT - * Method: create - * Signature: (I)J - */ -JNIEXPORT jlong JNICALL Java_com_euphony_fft_KissFFT_create - (JNIEnv *, jobject, jint); - -/* - * Class: com_euphony_fft_KissFFT - * Method: destroy - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_com_euphony_fft_KissFFT_destroy - (JNIEnv *, jobject, jlong); - -/* - * Class: com_euphony_fft_KissFFT - * Method: spectrum - * Signature: (JLjava/nio/ShortBuffer;Ljava/nio/FloatBuffer;)V - */ -JNIEXPORT void JNICALL Java_com_euphony_fft_KissFFT_spectrum - (JNIEnv *, jobject, jlong, jobject, jobject); - -/* - * Class: com_euphony_fft_KissFFT - * Method: getRealPart - * Signature: (JLjava/nio/ShortBuffer;)V - */ -JNIEXPORT void JNICALL Java_com_euphony_fft_KissFFT_getRealPart - (JNIEnv *, jobject, jlong, jobject); - -/* - * Class: com_euphony_fft_KissFFT - * Method: getImagPart - * Signature: (JLjava/nio/ShortBuffer;)V - */ -JNIEXPORT void JNICALL Java_com_euphony_fft_KissFFT_getImagPart - (JNIEnv *, jobject, jlong, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/euphony/src/main/jni/euphony_lib_receiver_KissFFT.cpp b/euphony/src/main/jni/euphony_lib_receiver_KissFFT.cpp deleted file mode 100644 index 6b9d2f3..0000000 --- a/euphony/src/main/jni/euphony_lib_receiver_KissFFT.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include "kiss_fftr.h" -#include "euphony_lib_receiver_KissFFT.h" -#include -#include -#include - -#define MAX_SHORT 32767.0f - -static inline float scale( kiss_fft_scalar val ) -{ - if( val < 0 ) - return val * ( 1 / 32768.0f ); - else - return val * ( 1 / 32767.0f ); -} - -struct KissFFT -{ - kiss_fftr_cfg config; - kiss_fft_cpx* spectrum; - int numSamples; -}; - - -JNIEXPORT jlong JNICALL Java_euphony_lib_receiver_KissFFT_create (JNIEnv *, jobject, jint numSamples) -{ - KissFFT* fft = new KissFFT(); - - fft->config = kiss_fftr_alloc(numSamples,0,NULL,NULL); - fft->spectrum = (kiss_fft_cpx*)malloc(sizeof(kiss_fft_cpx) * (int)numSamples); - - //__android_log_print(ANDROID_LOG_INFO,"----","r: %f i : %f",fft->spectrum->r, fft->spectrum->i); - fft->numSamples = numSamples; - return (jlong)fft; - return 0; -} - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: destroy - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_destroy(JNIEnv *, jobject, jlong handle) -{ - KissFFT* fft = (KissFFT*)handle; - free(fft->config); - free(fft->spectrum); - free(fft); -} - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: spectrum_for_phase - * Signature: (JLjava/nio/ShortBuffer;Ljava/nio/FloatBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_spectrum_1for_1phase - (JNIEnv *env, jobject, jlong handle, jobject source, jobject target) -{ - KissFFT* fft = (KissFFT*)handle; - kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetDirectBufferAddress( source ); - float* spectrum = (float*)env->GetDirectBufferAddress( target ); - - kiss_fftr( fft->config, samples, fft->spectrum ); - - int len = fft->numSamples / 2 + 1; - int start = len * (16500.0 / 22050.0); - - for( int i = start; i < len; i++ ) - { - float re = scale(fft->spectrum[i].r) * fft->numSamples; - float im = scale(fft->spectrum[i].i) * fft->numSamples; - - spectrum[i] = atan2(im,re) * 180 / 3.141592; - } -} - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: spectrum - * Signature: (JLjava/nio/ShortBuffer;Ljava/nio/FloatBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_spectrum(JNIEnv *env, jobject, jlong handle, jobject source, jobject target) -{ - - KissFFT* fft = (KissFFT*)handle; - kiss_fft_scalar* samples = (kiss_fft_scalar*)env->GetDirectBufferAddress( source ); - float* spectrum = (float*)env->GetDirectBufferAddress( target ); - - - kiss_fftr( fft->config, samples, fft->spectrum ); //<--- fatal signal 11 (SIGSEV) at 0x00000400 - - int len = fft->numSamples / 2 + 1; // <=--- <--- fatal signal 11 (SIGSEV) at 0x00000408 - // int len = 6; // <-- for debugging - int start = len * (16500.0 / 22050.0); - for( int i = start; i < len; i++ ) - { - float re = scale(fft->spectrum[i].r) * fft->numSamples; - float im = scale(fft->spectrum[i].i) * fft->numSamples; - - if( i > 0 ) - spectrum[i] = sqrtf(re*re + im*im) / (fft->numSamples / 2); - else - spectrum[i] = sqrtf(re*re + im*im) / (fft->numSamples); - } -} - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: getRealPart - * Signature: (JLjava/nio/ShortBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_getRealPart(JNIEnv *env, jobject, jlong handle, jobject real) -{ - KissFFT* fft = (KissFFT*)handle; - short* target = (short*)env->GetDirectBufferAddress(real); - for( int i = 0; i < fft->numSamples / 2; i++ ) - target[i] = fft->spectrum[i].r; -} - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: getImagPart - * Signature: (JLjava/nio/ShortBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_getImagPart(JNIEnv *env, jobject, jlong handle, jobject real) -{ - KissFFT* fft = (KissFFT*)handle; - short* target = (short*)env->GetDirectBufferAddress(real); - for( int i = 0; i < fft->numSamples / 2; i++ ) - target[i] = fft->spectrum[i].i; -} diff --git a/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h b/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h deleted file mode 100644 index 694c2ad..0000000 --- a/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h +++ /dev/null @@ -1,61 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class euphony_lib_receiver_KissFFT */ - -#ifndef _Included_euphony_lib_receiver_KissFFT -#define _Included_euphony_lib_receiver_KissFFT -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: euphony_lib_receiver_KissFFT - * Method: create - * Signature: (I)J - */ -JNIEXPORT jlong JNICALL Java_euphony_lib_receiver_KissFFT_create - (JNIEnv *, jobject, jint); - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: destroy - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_destroy - (JNIEnv *, jobject, jlong); - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: spectrum - * Signature: (JLjava/nio/ShortBuffer;Ljava/nio/FloatBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_spectrum - (JNIEnv *, jobject, jlong, jobject, jobject); - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: spectrum_for_phase - * Signature: (JLjava/nio/ShortBuffer;Ljava/nio/FloatBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_spectrum_1for_1phase - (JNIEnv *, jobject, jlong, jobject, jobject); - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: getRealPart - * Signature: (JLjava/nio/ShortBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_getRealPart - (JNIEnv *, jobject, jlong, jobject); - -/* - * Class: euphony_lib_receiver_KissFFT - * Method: getImagPart - * Signature: (JLjava/nio/ShortBuffer;)V - */ -JNIEXPORT void JNICALL Java_euphony_lib_receiver_KissFFT_getImagPart - (JNIEnv *, jobject, jlong, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/AcousticSensor.kt b/euphony/src/main/kotlin/euphony/lib/receiver/AcousticSensor.kt deleted file mode 100644 index 066d650..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/AcousticSensor.kt +++ /dev/null @@ -1,5 +0,0 @@ -package euphony.lib.receiver - -interface AcousticSensor { - fun notify(letters: String) -} diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/AudioRecorder.kt b/euphony/src/main/kotlin/euphony/lib/receiver/AudioRecorder.kt deleted file mode 100644 index 5f4bb3d..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/AudioRecorder.kt +++ /dev/null @@ -1,87 +0,0 @@ -package euphony.lib.receiver - -import android.media.AudioFormat -import android.media.AudioRecord -import android.media.MediaRecorder -import java.nio.ByteBuffer - -class AudioRecorder -/** - * Constructor. - * - * @param sampleRate - * The sample rate (e.g. 44100 Hz). - * @param bufferSize - * The size of the recording buffer in bytes. - */ -(sampleRate: Int) { - - private val audioRecord: AudioRecord - private var running: Boolean = false - private var swtWindowing: Boolean = false //TEST WINDOWING - - init { - var bufferSize = AudioRecord.getMinBufferSize(sampleRate, - AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT) - - audioRecord = AudioRecord(MediaRecorder.AudioSource.MIC, - sampleRate, AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT, bufferSize) - swtWindowing = false - } - - /** - * Reads the mic input and writes to a buffer. - * - * @param buffer - * The buffer that will store the samples. - * @param bufferSize - * The max number of bytes to be read. - * @return The number of bytes that were read. - */ - fun read(buffer: ByteBuffer, bufferSize: Int): Int { - val samplesRead: Int - samplesRead = audioRecord.read(buffer, bufferSize) - return samplesRead - } - - fun read(buffer: ByteBuffer, bufferSize: Int, windowNum: Short): Int { - val samplesRead: Int - samplesRead = audioRecord.read(buffer, bufferSize) - swtWindowing = swtWindowing xor true - if (swtWindowing) { - val euWindow = EuWindows(windowNum, buffer, bufferSize) - euWindow.Processor() - } - return samplesRead - } - - /** - * Starts recording audio. Must be called before the first call to 'read'. - */ - fun start() { - if (!running) { - audioRecord.startRecording() - running = true - } - } - - /** - * Stops recording audio. - */ - fun stop() { - if (running) { - audioRecord.stop() - running = false - } - } - - /** - * Releases the allocated memory. - */ - fun destroy() { - stop() - //audioRecord.release(); - } - -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/EuDataDecoder.kt b/euphony/src/main/kotlin/euphony/lib/receiver/EuDataDecoder.kt deleted file mode 100644 index 78462ef..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/EuDataDecoder.kt +++ /dev/null @@ -1,42 +0,0 @@ -package euphony.lib.receiver - -import android.util.Log -import euphony.lib.util.EuCodec - -class EuDataDecoder(var originalSource: String?) : EuCodec() { - - fun decodeHexCharSource(): String? { - return decodeStaticHexCharSource(originalSource!!) - } - - companion object { - - fun decodeStaticHexCharSource(_source: String?): String? { - var retValue = "" - var i = 0 - - if(_source == null) - return null - - while (i < _source.length - 1) { - val data = Integer.parseInt("" + _source[i] + _source[i + 1], 16) - retValue += data.toChar() - Log.d("DECODED", _source + " : " + _source[i] + " " + _source[i + 1] + " " + retValue) - i += 2 - } - - return retValue - } - - fun decodeStaticHexCharSource(_intArray: IntArray): String { - var retValue = "" - var i = 0 - while (i < _intArray.size - 1) { - retValue += (_intArray[i] * 16 + _intArray[i + 1]).toChar() - i += 2 - } - - return retValue - } - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/EuFreqObject.kt b/euphony/src/main/kotlin/euphony/lib/receiver/EuFreqObject.kt deleted file mode 100644 index f684a1f..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/EuFreqObject.kt +++ /dev/null @@ -1,393 +0,0 @@ -package euphony.lib.receiver - -import java.nio.ByteBuffer -import java.nio.ByteOrder -import java.nio.FloatBuffer -import java.nio.ShortBuffer -import java.util.ArrayList - -import android.util.Log -import euphony.lib.util.COMMON -import euphony.lib.util.PacketErrorDetector - -open class EuFreqObject { - - val SAMPLERATE = COMMON.SAMPLERATE//44100; - val fftsize = COMMON.FFT_SIZE//512; - val MAXREFERENCE = COMMON.MAX_REF//4000; - val MINREFERENCE = COMMON.MIN_REF//50; - val MAXFREQUENCY = COMMON.MAX_FREQ//22050.0; - val DEFAULT_REF = COMMON.DEFAULT_REF//500 - val START_FREQ = COMMON.START_FREQ //18000 - val RXCHANNEL = COMMON.CHANNEL// 16 - private val STARTCHANNEL = 1 - private val mFreqSpan = COMMON.CHANNEL_SPAN // 86 - var START_BIT = START_FREQ - mFreqSpan - - var mStartSwt: Boolean? = false - var isCompleted: Boolean? = false - private var isRecording: Boolean? = false - - private val samples = allocateByteBuffer(fftsize) - private val spectrum = allocateFloatBuffer(fftsize / 2 + 1) - private val spectrum_p = allocateFloatBuffer(fftsize / 2 + 1) - var receivedData: String? = null - - private val mFreqArray = IntArray(RXCHANNEL + STARTCHANNEL) - private val mTempRef = IntArray(RXCHANNEL + STARTCHANNEL) - private val mRefCntIndexArray = IntArray(RXCHANNEL + STARTCHANNEL) - private val mDynamicRefArray = IntArray(RXCHANNEL + STARTCHANNEL) - - private val mChannelArrayList = ArrayList() - - private val recorder: AudioRecorder - private val FFT = KissFFT(fftsize) - - private var mMaxIndex = -1 - private var mSampleIndex = 0 - private var mSampleTemp = 0 - private var mChannelTemp = 0 - var cntCheck = 0 - private var mArrMaxIndex = IntArray(RXCHANNEL + STARTCHANNEL) - private val mArrSampleIndex = IntArray(RXCHANNEL + STARTCHANNEL) - private val mArrSampleTemp = IntArray(RXCHANNEL + STARTCHANNEL) - private val mArrChannelTemp = IntArray(RXCHANNEL + STARTCHANNEL) - var mArrcntCheck = IntArray(RXCHANNEL + STARTCHANNEL) - - var mStartSampleCnt = 0 - - private val SENSOR_LIMIT_COUNT = 2000 - - init { - recorder = AudioRecorder(SAMPLERATE) - //INIT DYNAMIC REFERENCE ARRAY.. - for (i in 0 until RXCHANNEL + STARTCHANNEL) - mDynamicRefArray[i] = DEFAULT_REF - - isRecording = false - } - - - fun StartFFT() { - if (isRecording != true) { - recorder.start() - isRecording = true - } - recorder.read(samples, fftsize) - FFT.spectrum(samples, spectrum) - //FFT.spectrum_for_phase(samples, spectrum_p); - //FFT.getRealPart(real); - //FFT.getImagPart(image); - } - - fun StartFFT(windowsNum: Short) { - if (isRecording != true) { - recorder.start() - isRecording = true - } - recorder.read(samples, fftsize, windowsNum) - FFT.spectrum(samples, spectrum) - } - - fun DestroyFFT() { - FFT.dispose() - recorder.stop() - isRecording = false - } - - fun euDetectFreq(fFrequency: Int): Int { - - val fFreqRatio: Double - val freqIndex: Int - val fmax: Float - - fFreqRatio = fFrequency / MAXFREQUENCY - freqIndex = (fFreqRatio * fftsize / 2).toInt() + 1 - - //f1 = spectrum.get(freqIndex-1); - fmax = spectrum.get(freqIndex) - //f3 = spectrum_p.get(freqIndex); - //r1 = real.get(freqIndex); - //i1 = image.get(freqIndex); - /* - String s = ""; - for(int i = freqIndex - 1; i <= freqIndex + 1; i++) - s += " " + spectrum.get(i); - Log.i("HELLO FREQ", freqIndex + "::" + s); - */ - //f3 = spectrum.get(freqIndex+1); - - //if( fmax < f2 ) fmax = f2; - //if( fmax < f3 ) fmax = f3; - - return (fmax * 100000).toInt() - } - - fun euCatchSingleData() { - // UPDATED ON 1/2/2014 - // START BIT's Frequency Detection - mSampleTemp = this.euDetectFreq(START_BIT) - mMaxIndex = RXCHANNEL - // START BIT's Dynamic Reference Catch - mDynamicRefArray[RXCHANNEL] = euGetDynamicReference(mSampleTemp, RXCHANNEL) - - // Rest of frequency processing - for (i in 0 until RXCHANNEL) { - var currentFreq = this.euDetectFreq(START_FREQ + mFreqSpan * i) - mDynamicRefArray[i] = euGetDynamicReference(currentFreq, i) - - if (currentFreq >= mSampleTemp && currentFreq >= mDynamicRefArray[i]) { - mSampleTemp = currentFreq - mMaxIndex = i - } - } - - // BEFORE VERSION - /*for(int i = 0; i < RXCHANNEL + STARTCHANNEL ; i++) - { - if(i != RXCHANNEL) - currentFreq = (int) this.detectFreq(START_FREQ + mFreqSpan*i); - else - currentFreq = (int) this.detectFreq(START_BIT); - mDynamicRefArray[i] = getDynamicReference(currentFreq, i); - - if(currentFreq>=mSampleTemp && currentFreq >=mDynamicRefArray[i]){ - mSampleTemp = currentFreq; - mMaxIndex = i; - } - }*/ - - if (mMaxIndex != -1) { - mFreqArray[mMaxIndex]++ - } - if (mSampleIndex < 7) { - mSampleIndex++ - } else { - for (i in 0 until RXCHANNEL + STARTCHANNEL) { - if (mFreqArray[i] > mChannelTemp) { - mChannelTemp = mFreqArray[i] - mMaxIndex = i - } - //mbFreqArray[i] = 0; - } - - if (mChannelTemp > 2 && mMaxIndex != -1) { - if (mMaxIndex == 16) { - if (mChannelArrayList.size > 1) { - cntCheck++ - Log.v("mChanelArrayList.size()", "mChanelArrayList.size():" + mChannelArrayList.size) - - receivedData = "" - val a = IntArray(mChannelArrayList.size - 2) - for (i in 0 until mChannelArrayList.size - 2) { - a[i] = mChannelArrayList[i] - if (a[i] > 9) - receivedData += "" + ('a'.toInt() + (a[i] - 10)).toChar() - else - receivedData += "" + a[i] - } - - if (PacketErrorDetector.makeCheckSum(a) == mChannelArrayList[mChannelArrayList.size - 2] && PacketErrorDetector.makeParellelParity(a) == mChannelArrayList[mChannelArrayList.size - 1]) { - mStartSwt = false - isCompleted = true - receiveStr = EuDataDecoder.decodeStaticHexCharSource(a) - } - mChannelArrayList.clear() - } - } else { - mChannelArrayList.add(mMaxIndex) - } - Log.v("DATA", "DATAIndex : " + mMaxIndex + " mCheckedByte :" + mSampleIndex + " tempxcnt :" + mChannelTemp + " Data :" + this.euDetectFreq(START_FREQ + mFreqSpan * mMaxIndex)) - Log.v("DaTA", "0:" + mFreqArray[0] + " 1:" + mFreqArray[1] + " 2:" + mFreqArray[2] + " 3:" + mFreqArray[3] + " 4:" + mFreqArray[4] + " 5:" + mFreqArray[5] + " 6:" + mFreqArray[6] + " 7:" + mFreqArray[7] + " 8:" + mFreqArray[8] - + " 9:" + mFreqArray[9] + " 10:" + mFreqArray[10] + " 11:" + mFreqArray[11] + " 12:" + mFreqArray[12] + " 13:" + mFreqArray[13] + " 14:" + mFreqArray[14] + " 15:" + mFreqArray[15] + " 16:" + mFreqArray[16]) - } else { - mChannelArrayList.add(-1) - Log.v("DATAX", "DATAIndex : " + mMaxIndex + " mCheckedByte :" + mSampleIndex + " Data :" + this.euDetectFreq(START_FREQ + mFreqSpan * mMaxIndex)) - Log.v("DaTA", "0:" + mFreqArray[0] + " 1:" + mFreqArray[1] + " 2:" + mFreqArray[2] + " 3:" + mFreqArray[3] + " 4:" + mFreqArray[4] + " 5:" + mFreqArray[5] + " 6:" + mFreqArray[6] + " 7:" + mFreqArray[7] + " 8:" + mFreqArray[8] - + " 9:" + mFreqArray[9] + " 10:" + mFreqArray[10] + " 11:" + mFreqArray[11] + " 12:" + mFreqArray[12] + " 13:" + mFreqArray[13] + " 14:" + mFreqArray[14] + " 15:" + mFreqArray[15] + " 16:" + mFreqArray[16]) - - } - mMaxIndex = -1 - mSampleIndex = 0 - mSampleTemp = 0 - mChannelTemp = 0 - for (i in 0 until RXCHANNEL + STARTCHANNEL) {//// - mFreqArray[i] = 0//// - }///// - } - - } - - fun euCatchMultiData() { - for (j in 0 until RXCHANNEL + STARTCHANNEL) { - mArrMaxIndex[j] = -1 - mArrSampleIndex[j] = 0 - mArrSampleTemp[j] = 0 - mArrChannelTemp[j] = 0 - mArrcntCheck[j] = 0 - mFreqArray[j] = 0 - } - val arrCurrentFreq = IntArray(RXCHANNEL + STARTCHANNEL) - for (i in 0 until RXCHANNEL + STARTCHANNEL) { - arrCurrentFreq[i] = this.euDetectFreq(START_FREQ + mFreqSpan * i) - if (arrCurrentFreq[i] >= 200) { - //mArrSampleTemp[i] = arrCurrentFreq[i]; - mArrMaxIndex[i] = i - } - } - } - - fun getmMaxIndex(): Int { - return mMaxIndex - } - - fun setmMaxIndex(mMaxIndex: Int) { - this.mMaxIndex = mMaxIndex - } - - fun getmArrMaxIndex(): IntArray { - return mArrMaxIndex - } - - fun setmArrMaxIndex(mArrMaxIndex: IntArray) { - this.mArrMaxIndex = mArrMaxIndex - } - - fun euCheckStartPoint(): Boolean? { - var tempFreq = 50 - var tempIndex = -1 - - for (i in -1..1) { - var currentFreq = this.euDetectFreq(START_BIT + mFreqSpan * i) - if (currentFreq > tempFreq) { - tempFreq = currentFreq - tempIndex = 0 - } - } - if (tempIndex == 0) { - if (mStartSampleCnt == 8) - return true - else - mStartSampleCnt++ - } else - mStartSampleCnt = 0 - - return false - } - - private fun euSpecificFreqSensor(_freq: Int): Boolean { - var dynRef = 500 - val dynRefCnt = 0 - var criticalCnt = 0 - var limitCnt = 0 - var temp = 0 - val preservedRef = 0 - while (SENSOR_LIMIT_COUNT > limitCnt++) { - this.StartFFT() - - val curFreq = this.euDetectFreq(_freq) - dynRef = euGetDynamicRef(curFreq, dynRef, preservedRef, dynRefCnt) - - if (curFreq >= dynRef) { - val prevFreq = this.euDetectFreq(_freq - mFreqSpan) - val nextFreq = this.euDetectFreq(_freq + mFreqSpan) - - if (prevFreq > curFreq || nextFreq > curFreq) - continue - else { - criticalCnt++ - temp = limitCnt - } - } - - if (criticalCnt > 4) { - if (limitCnt - temp > 12) { - criticalCnt = 0 - continue - } else - return true - } - } - return false - } - - fun euGetDynamicRef(curFreq: Int, dynRef: Int, preservedRef: Int, dynRefCnt: Int): Int { - var dynRef = dynRef - - if (curFreq > dynRef) - // DATA TRUE - { - when (dynRefCnt) { - 0 -> dynRef = curFreq - 1 -> dynRef = (curFreq + dynRef) / 3 - 2 -> dynRef = preservedRef - } - } else - //DATA FALSE - { - dynRef -= ((dynRef - curFreq) * 0.9).toInt() - } - - // MAXIMUM and MIMINUM DATA CATCHING - if (dynRef > MAXREFERENCE) - dynRef = MAXREFERENCE - if (dynRef < MINREFERENCE) - dynRef = MINREFERENCE - - return dynRef - } - - fun euGetDynamicReference(nfreq: Int, freqIndex: Int): Int { - if (nfreq > mDynamicRefArray[freqIndex]) - // DATA TRUE - { - when (mRefCntIndexArray[freqIndex]) { - 0 -> { - mDynamicRefArray[freqIndex] = nfreq - mRefCntIndexArray[freqIndex]++ - } - 1 -> { - mDynamicRefArray[freqIndex] = (nfreq + mDynamicRefArray[freqIndex]) / 2 - mTempRef[freqIndex] = mDynamicRefArray[freqIndex] - mRefCntIndexArray[freqIndex]++ - } - 2 -> mDynamicRefArray[freqIndex] = mTempRef[freqIndex] - } - } else - //DATA FALSE - { - mDynamicRefArray[freqIndex] -= ((mDynamicRefArray[freqIndex] - nfreq) * 0.9).toInt() - mRefCntIndexArray[freqIndex] = 0 - } - - // MAXIMUM and MIMINUM DATA CATCHING - if (mDynamicRefArray[freqIndex] > MAXREFERENCE) - mDynamicRefArray[freqIndex] = MAXREFERENCE - if (mDynamicRefArray[freqIndex] < MINREFERENCE) - mDynamicRefArray[freqIndex] = MINREFERENCE - - return mDynamicRefArray[freqIndex] - } - - - private fun allocateByteBuffer(numSamples: Int): ByteBuffer { - val buffer = ByteBuffer.allocateDirect(numSamples * 2) - buffer.order(ByteOrder.nativeOrder()) - return buffer - } - - private fun allocateFloatBuffer(numSamples: Int): FloatBuffer { - val buffer = allocateByteBuffer(numSamples * 2) - return buffer.asFloatBuffer() - } - - private fun allocateShortBuffer(numSamples: Int): ShortBuffer { - val buffer = allocateByteBuffer(numSamples * 2) - return buffer.asShortBuffer() - } - - companion object { - var receiveStr = "" - } - -} diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/EuRxManager.kt b/euphony/src/main/kotlin/euphony/lib/receiver/EuRxManager.kt deleted file mode 100644 index 46d6b73..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/EuRxManager.kt +++ /dev/null @@ -1,208 +0,0 @@ -package euphony.lib.receiver - -import android.os.Handler -import android.os.Message -import android.util.Log -import euphony.lib.util.COMMON - -class EuRxManager { - private var mRxThread: Thread? = null - private var mRxRunner: RxRunner? = null - private var mPsRunner: PsRunner? = null - private var mPsThread: Thread? = null - private var _active: Boolean = false - - private var mHex = false - - var acousticSensor: AcousticSensor? = null - - private val mHandler = object : Handler() { - override fun handleMessage(msg: Message) { - when (msg.what) { - RX_DECODE -> acousticSensor!!.notify(msg.obj.toString() + "") - else -> { - } - } - } - } - - var positionDetector: PositionDetector? = null - - private val mPsHandler = object : Handler() { - override fun handleMessage(msg: Message) { - when (msg.what) { - PS_DECODE -> positionDetector!!.detectSignal(msg.obj as Int) - } - } - } - - constructor() {} - constructor(hex: Boolean) { - mHex = hex - } - - @JvmOverloads - fun listen(hex: Boolean = mHex) { - _active = true - mRxRunner = RxRunner(hex) - mRxThread = Thread(mRxRunner, "RX") - mRxThread!!.start() - } - - fun find() { - _active = true - mPsRunner = PsRunner() - mPsThread = Thread(mPsRunner, "PS") - mPsThread!!.start() - } - - fun finishToFind() { - if (mPsThread != null) { - _active = false - while (true) { - try { - mPsThread!!.join() - break - } catch (e: InterruptedException) { - Log.i("FINISH", e.message) - } - - } - } - - if (mPsRunner != null) - mPsRunner!!.DestroyFFT() - - mPsThread = null - mPsRunner = null - } - - fun finish() { - if (mRxThread != null) { - _active = false - while (true) { - try { - mRxThread!!.join() - break - } catch (e: InterruptedException) { - Log.i("FINISH", e.message) - } - - } - } - if (mRxRunner != null) - mRxRunner!!.DestroyFFT() - - mRxThread = null - mRxRunner = null - } - - private inner class RxRunner : EuFreqObject, Runnable { - internal var mHex = false - - internal constructor() {} - internal constructor(hex: Boolean) { - mHex = hex - } - - override fun run() { - while (_active) { - StartFFT() - if (mStartSwt!!) - euCatchSingleData() - else - mStartSwt = euCheckStartPoint() - - if (isCompleted!!) { - val msg = mHandler.obtainMessage() - msg.what = RX_DECODE - msg.obj = if (mHex) receivedData else EuDataDecoder.decodeStaticHexCharSource(receivedData) - isCompleted = false - mHandler.sendMessage(msg) - mRxRunner!!.DestroyFFT() - return - } - } - } - } - - private inner class PsRunner : EuFreqObject(), Runnable { - - override fun run() { - var startswt = false - var startcnt = 0 - var specificFreq = 0 - Log.i("START", "START LISTEN") - while (_active) { - //To find the frequency point - while (!startswt) { - StartFFT() - var i: Int - i = 21000 - while (i >= 16500) { - if (100 < euDetectFreq(i)) { - startswt = true - break - } - i -= COMMON.CHANNEL_SPAN - } - specificFreq = i - - //there is no af area.. - if (startcnt++ > 1000) { - _active = false - startswt = true - Log.i("START", "FAILED to find any position") - } - } - - var signal: Int - var max_signal = 0 - var avr_signal = 0 - var noSignalCnt = 0 - var processingCnt = 0 - var maxCnt = 0 - do { - StartFFT() - signal = euDetectFreq(specificFreq) - - if (signal < 20) - noSignalCnt++ - else { - noSignalCnt = 0 - - if (max_signal < signal) { - maxCnt++ - max_signal = signal - avr_signal += max_signal - } - if (++processingCnt > 50) { - avr_signal /= maxCnt - val msg = mPsHandler.obtainMessage() - msg.what = PS_DECODE - msg.obj = avr_signal - mPsHandler.sendMessage(msg) - processingCnt = 0 - max_signal = 0 - avr_signal = 0 - maxCnt = 0 - } - } - } while (noSignalCnt < 50 && _active) - - val msg = mPsHandler.obtainMessage() - msg.what = PS_DECODE - msg.obj = -1 - mPsHandler.sendMessage(msg) - break - - } - } - } - - companion object { - - private val RX_DECODE = 1 - private val PS_DECODE = 2 - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/EuWindows.kt b/euphony/src/main/kotlin/euphony/lib/receiver/EuWindows.kt deleted file mode 100644 index b06fd31..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/EuWindows.kt +++ /dev/null @@ -1,103 +0,0 @@ -package euphony.lib.receiver - -import java.nio.ByteBuffer - -class EuWindows(mWindowNumber: Short, buffer: ByteBuffer, bufferSize: Int) { - var windowNumber: Short = 0 - - var buffer: ByteBuffer? = null - var bufferSize = 0 - private val mRawData: ByteArray - var kaiserAlph = 32.0 - var kaiserWindowSize = 45.0 - var hammingAlph = 54.0 - var blackmanAlph = 0.16 - - init { - this.buffer = buffer - this.bufferSize = bufferSize - mRawData = buffer.array() - windowNumber = mWindowNumber - } - - internal fun Processor() { - if (buffer != null && bufferSize != 0) - // check buffer buffersize - { - when (windowNumber as Int) { - RECTANGULAR -> RectangularWindow() - TRIANGLAR -> TrianglarWindow() - HANNING -> HanningWindow() - HAMMING -> HammingWindow() - BLACKMAN -> BlackmanWindow() - KAISER -> KaiserWindow() - } - } - } - - internal fun RectangularWindow() { - for (i in mRawData.indices) - mRawData[i] = (mRawData[i] * 1.0).toByte() - buffer = ByteBuffer.wrap(mRawData) - - } - - internal fun TrianglarWindow() { - for (i in mRawData.indices) - mRawData[i] = (mRawData[i] * ((mRawData.size / 2.0 - Math.abs(i - (mRawData.size - 1.0) / 2.0)) / (mRawData.size / 2.0))).toByte() - buffer = ByteBuffer.wrap(mRawData) - } - - internal fun HanningWindow() { - for (i in mRawData.indices) - mRawData[i] = (mRawData[i] * (0.5 * (1 - Math.cos(2.0 * Math.PI * i.toDouble() / (512 - 1))))).toByte() - buffer = ByteBuffer.wrap(mRawData) - } - - internal fun HammingWindow() { - for (i in mRawData.indices) - mRawData[i] = (mRawData[i] * (hammingAlph + (1.0 - hammingAlph) * Math.cos(2.0 * Math.PI * i.toDouble() / mRawData.size + Math.PI))).toByte() - buffer = ByteBuffer.wrap(mRawData) - } - - internal fun BlackmanWindow() { - for (i in mRawData.indices) - mRawData[i] = (mRawData[i] * ((1.0 - blackmanAlph) / 2.0 - 0.5 * Math.cos(2.0 * Math.PI * i.toDouble() / (mRawData.size - 1.0)) + blackmanAlph / 2.0 * Math.cos(4.0 * Math.PI * i.toDouble() / (mRawData.size - 1.0)))).toByte() - buffer = ByteBuffer.wrap(mRawData) - } - - internal fun KaiserWindow() { - val n = kaiserWindowSize / 2.0 - for (i in mRawData.indices) { - mRawData[i] = (mRawData[i] * (Util.I0(kaiserAlph * Math.sqrt(1.0 - Math.pow(2.0 * (i.toDouble() - n) / kaiserWindowSize, 2.0))) / Util.I0(kaiserAlph))).toByte() - } - buffer = ByteBuffer.wrap(mRawData) - } - - internal object Util { - fun I0(x: Double): Double { - val eps = 10E-9 - var n = 1 - var S = 1.0 - var D = 1.0 - while (D > eps * S) { - val T = x / (2.0 * n) - n++ - D *= T * T - S += D - } - return S - } - } - - companion object { - - //windows - val RECTANGULAR = 0 - val TRIANGLAR = 1 - val HANNING = 2 - val HAMMING = 3 - val BLACKMAN = 4 - val KAISER = 5 - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/KissFFT.kt b/euphony/src/main/kotlin/euphony/lib/receiver/KissFFT.kt deleted file mode 100644 index 047b1e0..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/KissFFT.kt +++ /dev/null @@ -1,117 +0,0 @@ -package euphony.lib.receiver - -import android.util.Log -import java.nio.ByteBuffer -import java.nio.FloatBuffer -import java.nio.ShortBuffer - -class KissFFT(numSamples: Int) { - - /** the pointer to the kiss fft object */ - private val handle: Long - - init { - handle = create(numSamples) - Log.i("var", " $handle") - } - - /** - * Creates a new kiss fft object - * - * @param timeSize - * the number of samples - * @return the handle to the kiss fft object - */ - private external fun create(timeSize: Int): Long - - /** - * Destroys a kiss fft object - * - * @param handle - * the handle to the kiss fft object - */ - private external fun destroy(handle: Long) - - /** - * Calculates the frequency spectrum of the given samples. There must be as - * many samples as specified in the constructor of this class. Spectrum must - * hold timeSize / 2 + 1 elements - * - * @param handle - * the handle to the kiss fft object - * @param samples - * the samples in 16-bit signed PCM encoding - * @param spectrum - * the spectrum - */ - private external fun spectrum(handle: Long, samples: ShortBuffer, - spectrum: FloatBuffer) - - /** - * Calculates the frequency spectrum of the given samples. There must be as - * many samples as specified in the constructor of this class. Spectrum must - * hold timeSize / 2 + 1 elements - * - * @param samples - * the samples - * @param spectrum - * the spectrum - */ - fun spectrum(samples: ShortBuffer, spectrum: FloatBuffer) { - spectrum(handle, samples, spectrum) - } - - /** - * Calculates the frequency spectrum of the given samples. There must be as - * many samples as specified in the constructor of this class. Spectrum must - * hold timeSize / 2 + 1 elements - * - * @param samples - * the samples - * @param spectrum - * the spectrum - */ - fun spectrum(samples: ByteBuffer, spectrum: FloatBuffer) { - spectrum(samples.asShortBuffer(), spectrum) - } - - private external fun spectrum_for_phase(handle: Long, samples: ShortBuffer, specturm: FloatBuffer) - - fun spectrum_for_phase(samples: ShortBuffer, spectrum: FloatBuffer) { - spectrum_for_phase(handle, samples, spectrum) - } - - fun spectrum_for_phase(samples: ByteBuffer, spectrum: FloatBuffer) { - spectrum_for_phase(samples.asShortBuffer(), spectrum) - } - - /** - * Releases all resources of this object - */ - fun dispose() { - destroy(handle) - } - - fun getRealPart(real: ShortBuffer) { - getRealPart(handle, real) - } - - fun getImagPart(imag: ShortBuffer) { - getImagPart(handle, imag) - } - - private external fun getRealPart(handle: Long, real: ShortBuffer) - - private external fun getImagPart(handle: Long, imag: ShortBuffer) - - companion object { - - init { - System.loadLibrary("kissff") // kiss_fft.c - System.loadLibrary("kissfftr") // kiss_fftr.c - System.loadLibrary("kissfft") // KissFFT.cpp - } - } - - -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/receiver/PositionDetector.kt b/euphony/src/main/kotlin/euphony/lib/receiver/PositionDetector.kt deleted file mode 100644 index 5c2ccbd..0000000 --- a/euphony/src/main/kotlin/euphony/lib/receiver/PositionDetector.kt +++ /dev/null @@ -1,6 +0,0 @@ -package euphony.lib.receiver - -interface PositionDetector { - fun detectSignal(signal: Int) - fun detectFq(fq: Int) -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/transmitter/EuCodeMaker.kt b/euphony/src/main/kotlin/euphony/lib/transmitter/EuCodeMaker.kt deleted file mode 100644 index 2522898..0000000 --- a/euphony/src/main/kotlin/euphony/lib/transmitter/EuCodeMaker.kt +++ /dev/null @@ -1,71 +0,0 @@ -package euphony.lib.transmitter - -import android.util.Log -import euphony.lib.util.PacketErrorDetector - -class EuCodeMaker : EuFreqGenerator { - internal var mMainString: String? = null - internal var mCodeSource: ShortArray? = null - var START_BIT = freqBasePoint - freqSpan - - private var mChannelMode = CHANNEL.EXINGLE - - enum class CHANNEL { - SINGLE, MULTI, EXINGLE - } - - constructor() {} - - constructor(channelMode: CHANNEL) { - mChannelMode = channelMode - } - - - fun euAssembleData(data: String): ShortArray { - var assembledData = euApplyCrossFade(euMakeStaticFrequency(START_BIT, 0)) - val payload = IntArray(data.length + 1) - - when (mChannelMode) { - EuCodeMaker.CHANNEL.SINGLE -> for (i in 0 until data.length) { - when (data[i]) { - '0' -> assembledData = euAppendRawData(assembledData, zeroSource) - '1' -> assembledData = euAppendRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(freqBasePoint, 0))) - } - } - - EuCodeMaker.CHANNEL.MULTI -> for (i in 0 until data.length) { - when (data[i]) { - '0' -> { - } - '1' -> assembledData = euMixingRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(freqBasePoint + freqSpan * (i + 1), 0))) - } - } - - EuCodeMaker.CHANNEL.EXINGLE -> for (i in 0 until data.length) { - val ch = data[i] - when (ch) { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> assembledData = euAppendRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(freqBasePoint + freqSpan * (ch - '0'), 0))) - 'a', 'b', 'c', 'd', 'e', 'f' -> assembledData = euAppendRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(freqBasePoint + freqSpan * (ch - 'a' + 10), 0))) - } - } - } - - for (i in 0 until data.length) { - when (data[i]) { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> payload[i] = data[i] - '0' - 'a', 'b', 'c', 'd', 'e', 'f' -> payload[i] = data[i] - 'a' + 10 - } - } - val checksum = PacketErrorDetector.makeCheckSum(payload) - val parity = PacketErrorDetector.makeParellelParity(payload) - - Log.i("UHEHE", "CHECKSUM : $checksum PARITY : $parity") - assembledData = euAppendRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(freqBasePoint + freqSpan * checksum, 0))) - assembledData = euAppendRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(freqBasePoint + freqSpan * parity, 0))) - - assembledData = euAppendRawData(assembledData, euApplyCrossFade(euMakeStaticFrequency(START_BIT, 0))) - - return assembledData - } - -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/transmitter/EuDataEncoder.kt b/euphony/src/main/kotlin/euphony/lib/transmitter/EuDataEncoder.kt deleted file mode 100644 index 9f9a5f0..0000000 --- a/euphony/src/main/kotlin/euphony/lib/transmitter/EuDataEncoder.kt +++ /dev/null @@ -1,63 +0,0 @@ -package euphony.lib.transmitter - -import android.util.Log -import euphony.lib.util.EuCodec -import java.io.ByteArrayOutputStream -import java.io.DataOutputStream -import java.io.IOException - -class EuDataEncoder : EuCodec { - var originalSource: String? = null - - internal constructor() {} - constructor(_source: String) { - originalSource = _source - } - - fun encodeHexCharSource(): String { - return encodeStaticHexCharSource(originalSource) - } - - fun encodeStaticHexCharSource(_source: String?): String { - val strBuilder = StringBuilder() - - for (i in 0 until _source!!.length) { - val data = _source[i].toInt() - strBuilder.append(Integer.toHexString(data)) - } - - return strBuilder.toString() - } - - companion object { - - fun base40StaticEncode(_source: String): ByteArray { - try { - val baos = ByteArrayOutputStream() - val dos = DataOutputStream(baos) - var i = 0 - while (i < _source.length) { - when (Math.min(3, _source.length - i)) { - 1 -> { - val b = EuCodec.base40Index[_source[i] as Int] - dos.writeByte(b.toInt()) - } - 2 -> { - val ch = (EuCodec.base40Index[_source[i + 1] as Int] * 40 + EuCodec.base40Index[_source[i] as Int]).toChar() - dos.writeChar(ch.toInt()) - } - 3 -> { - val ch2 = ((EuCodec.base40Index[_source[i + 2] as Int] * 40 + EuCodec.base40Index[_source[i + 1] as Int]).toChar().toInt() * 40 + EuCodec.base40Index[_source[i] as Int]).toChar() - dos.writeChar(ch2.toInt()) - } - } - i += 3 - } - return baos.toByteArray() - } catch (e: IOException) { - throw AssertionError(e) - } - - } - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/transmitter/EuFreqGenerator.kt b/euphony/src/main/kotlin/euphony/lib/transmitter/EuFreqGenerator.kt deleted file mode 100644 index bb3ec02..0000000 --- a/euphony/src/main/kotlin/euphony/lib/transmitter/EuFreqGenerator.kt +++ /dev/null @@ -1,134 +0,0 @@ -package euphony.lib.transmitter - -import euphony.lib.util.COMMON - -open class EuFreqGenerator { - - // FIXED ACOUSTIC DATA - val SAMPLERATE = COMMON.SAMPLERATE//44100; - val DATA_LENGTH = COMMON.DATA_LENGTH//2048; - val PI = Math.PI - val PI2 = PI * 2 - - // Member for Frequency point - // DEFAULT DEFINITION - var freqBasePoint = COMMON.START_FREQ - var freqSpan = COMMON.CHANNEL_SPAN //86 - val zeroSource = ShortArray(DATA_LENGTH) - - constructor() {} - - constructor(freqStartPoint: Int, freqSpan: Int) { - this.freqSpan = freqSpan - freqBasePoint = freqStartPoint - } - - fun euMakeStaticFrequency(freq: Int, degree: Int): ShortArray { - val double_source = DoubleArray(DATA_LENGTH) - val source = ShortArray(DATA_LENGTH) - var time: Double - val phase: Double - - for (i in 0 until DATA_LENGTH) { - time = i.toDouble() / SAMPLERATE.toDouble() - double_source[i] = Math.sin(PI2 * freq.toDouble() * time) - source[i] = (32767 * double_source[i]).toShort() - } - - return source - } - - fun euMakeFrequency(source: ShortArray, freq: Int) { - var source = source - source = euMakeStaticFrequency(freq, 0) - } - - //updated - fun euMakeFrequencyWithCrossFade(freq: Int): ShortArray { - return euApplyCrossFade(euMakeStaticFrequency(freq, 0)) - } - - fun euApplyCrossFade(source: ShortArray): ShortArray { - var mini_window: Double - val fade_section = COMMON.FADE_RANGE - for (i in 0 until fade_section) { - mini_window = i.toDouble() / fade_section.toDouble() - source[i] = (source[i].toDouble() * mini_window).toShort() - source[DATA_LENGTH - 1 - i] = (source[DATA_LENGTH - 1 - i].toDouble() * mini_window).toShort() - } - - return source - } - - fun euAppendRawData(src: ShortArray?, objective: ShortArray): ShortArray { - val SRC_LENGTH: Int - val TOTAL_LENGTH: Int - if (src == null) - SRC_LENGTH = 0 - else - SRC_LENGTH = src.size - TOTAL_LENGTH = SRC_LENGTH + objective.size - - val dest = ShortArray(TOTAL_LENGTH) - - for (i in 0 until SRC_LENGTH) - dest[i] = src!![i] - for (i in SRC_LENGTH until TOTAL_LENGTH) - dest[i] = objective[i - SRC_LENGTH] - - return dest - } - - fun euLinkRawData(vararg sources: ShortArray): ShortArray { - val dest = ShortArray(sources.size * DATA_LENGTH) - - for (i in sources.indices) - for (j in 0 until sources[i].size) - dest[j + i * DATA_LENGTH] = sources[i][j] - - return dest - } - - fun euLinkRawData(isCrossfaded: Boolean, vararg sources: ShortArray): ShortArray { - val dest = ShortArray(sources.size * DATA_LENGTH) - for (i in sources.indices) { - var src = sources[i] - if (isCrossfaded) - src = euApplyCrossFade(sources[i]) - - for (j in 0 until src.size) - dest[j + i * DATA_LENGTH] = src[j] - } - - return dest - } - - fun euMixingRawData(vararg sources: ShortArray): ShortArray { - val dest = sources[0].clone() - - for (i in 1 until sources.size) { - for (j in 0 until sources[i].size) { - dest[j] = ((dest[j].toInt() + sources[i][j].toInt()) / 2).toShort() - } - } - return dest - } - - fun euMakeMaximumVolume(source: ShortArray): ShortArray { - var max = 0 - //SCAN FOR VOLUME UP - for (i1 in source) - if (max < Math.abs(i1.toInt())) - max = i1.toInt() - if (32767 == max) - return source - - - for (i in source.indices) - source[i] = ( source[i] * (32767.0 / max.toDouble())).toShort() - - return source - } - - -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/transmitter/EuPlayer.kt b/euphony/src/main/kotlin/euphony/lib/transmitter/EuPlayer.kt deleted file mode 100644 index cb3bc5a..0000000 --- a/euphony/src/main/kotlin/euphony/lib/transmitter/EuPlayer.kt +++ /dev/null @@ -1,38 +0,0 @@ -package euphony.lib.transmitter - -import android.media.AudioAttributes -import android.media.AudioFormat -import android.media.AudioManager -import android.media.AudioTrack -import euphony.lib.util.COMMON - -class EuPlayer { - - private var mSource: ShortArray? = null - private var mAudioTrack: AudioTrack? = null - private val DATA_LENGTH = COMMON.FFT_SIZE * 4//2048; - private val mZeroSource = ShortArray(DATA_LENGTH) - - constructor() {} - - constructor(src: ShortArray) { - this.setSource(src) - } - - fun setSource(src: ShortArray) { - mSource = src - mAudioTrack = AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, src.size * 2, AudioTrack.MODE_STATIC) - } - - fun play() { - mAudioTrack!!.write(mSource!!, 0, mSource!!.size) - mAudioTrack!!.setLoopPoints(0, mSource!!.size, -1) - mAudioTrack!!.play() - } - - fun stop() { - if (mAudioTrack != null) - if (mAudioTrack!!.playState == AudioTrack.PLAYSTATE_PLAYING) - mAudioTrack!!.pause() - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/transmitter/EuTxManager.kt b/euphony/src/main/kotlin/euphony/lib/transmitter/EuTxManager.kt deleted file mode 100644 index 43b8184..0000000 --- a/euphony/src/main/kotlin/euphony/lib/transmitter/EuTxManager.kt +++ /dev/null @@ -1,63 +0,0 @@ -package euphony.lib.transmitter - -import android.content.Context -import android.media.AudioFormat -import android.media.AudioManager -import android.media.AudioTrack -import android.util.Log - -class EuTxManager { - private var mAudioTrack: AudioTrack? = null - private val mCodeMaker = EuCodeMaker() - private val mDataEncoder = EuDataEncoder() - - private var mHex = false - private var mOutStream: ShortArray? = null - - constructor() {} - - constructor(hex: Boolean) { - mHex = hex - } - - fun euInitTransmit(data: String) { - mOutStream = mCodeMaker.euAssembleData(if (mHex) data else mDataEncoder.encodeStaticHexCharSource(data)) - } - - @JvmOverloads - fun process(count: Int = 1) { - var count = count - if (count > 0) - mAudioTrack = AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mOutStream!!.size * 2, AudioTrack.MODE_STREAM) - else { - mAudioTrack = AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mOutStream!!.size * 2, AudioTrack.MODE_STATIC) - count = -1 - } - - mAudioTrack!!.setLoopPoints(0, mOutStream!!.size, count) - - if (mAudioTrack != null) { - try { - mAudioTrack!!.write(mOutStream!!, 0, mOutStream!!.size) - mAudioTrack!!.play() - } catch (e: IllegalStateException) { - Log.i("PROCESS", e.message) - } - - } - } - - fun stop() { - if (mAudioTrack != null) - mAudioTrack!!.pause() - } - - fun setSystemVolumeMax(_context: Context) { - val am = _context.getSystemService(Context.AUDIO_SERVICE) as AudioManager - - am.setStreamVolume( - AudioManager.STREAM_MUSIC, - am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), - 0) - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/util/COMMON.kt b/euphony/src/main/kotlin/euphony/lib/util/COMMON.kt deleted file mode 100644 index 4fa95cc..0000000 --- a/euphony/src/main/kotlin/euphony/lib/util/COMMON.kt +++ /dev/null @@ -1,23 +0,0 @@ -package euphony.lib.util - -interface COMMON { - companion object { - // RX & TX COMMON VARIABLES - val SAMPLERATE = 44100 - val FFT_SIZE = 512 - val DATA_LENGTH = FFT_SIZE * 4 - val FADE_RANGE = DATA_LENGTH / 16 - - val MAX_FREQ = 22050.0 - val START_FREQ = 18000 - val CHANNEL = 16 - val CHANNEL_SPAN = SAMPLERATE / FFT_SIZE // Frequency Interval - val BUNDLE_INTERVAL = CHANNEL_SPAN * CHANNEL - - // RX - val MAX_REF = 4000 - val MIN_REF = 50 - - val DEFAULT_REF = 500 // BASE Reference value - } -} diff --git a/euphony/src/main/kotlin/euphony/lib/util/EuCodec.kt b/euphony/src/main/kotlin/euphony/lib/util/EuCodec.kt deleted file mode 100644 index dc49b90..0000000 --- a/euphony/src/main/kotlin/euphony/lib/util/EuCodec.kt +++ /dev/null @@ -1,32 +0,0 @@ -package euphony.lib.util; - -import java.util.Arrays; - -open class EuCodec { - private val chars = StringBuilder(BASE40) - - init { - chars.append('\u0000') - run { - var ch = 'a' - while (ch <= 'z') { - chars.append(ch) - ch++ - } - } - var ch = '0' - while (ch <= '9') { - chars.append(ch) - ch++ - } - chars.append("-:.") - Arrays.fill(base40Index, (-1).toByte()) - for (i in 0 until chars.length) - base40Index[chars[i] as Int] = i as Byte - } - - companion object { - private val BASE40 = 40 - var base40Index = ByteArray(256) - } -} \ No newline at end of file diff --git a/euphony/src/main/kotlin/euphony/lib/util/PacketErrorDetector.kt b/euphony/src/main/kotlin/euphony/lib/util/PacketErrorDetector.kt deleted file mode 100644 index b3c37d5..0000000 --- a/euphony/src/main/kotlin/euphony/lib/util/PacketErrorDetector.kt +++ /dev/null @@ -1,136 +0,0 @@ -package euphony.lib.util - -import android.util.Log - -class PacketErrorDetector { - - private var mEvenParity = false - - /***************************************************** - * This function sets EvenParity Bit's Value with parameter (force to set) - * - * parameter : - * int nParityValue - 0 : Data Bit Value 1's number is EVEN - * 1 : Data Bit Value 1's number is ODD - * - * - * return : none - */ - fun euSetEvenParityState(nParityState: Boolean) { - mEvenParity = nParityState - } - - /***************************************************** - * This function returns EvenParity Bit's Value. - * parameter : none - * return type : int - * 0 : Data Bit Value 1's number is EVEN - * 1 : Data Bit Value 1's number is ODD - */ - fun euGetEvenParityState(): Boolean { - return mEvenParity - } - - companion object { - - /***************************************************** - * This function checks ParityBit(Even) and judges payload data is reliable - * - * parameter : - * int[] Payload - Payload Data - * int nParity - Payrity bit's value - * return type : int - * TRUE - Parity Check Result means data is reliable - * FALSE - Parity Check Result means data is unreliable - */ - fun checkEvenParity(payload: IntArray, nParityBit: Int): Boolean { - var ntemp = 0 - for (i in payload.indices) { - ntemp = ntemp xor payload[i] - } - ntemp = ntemp xor nParityBit - return if (ntemp == 0) - // result of Parity Calculation is 0 --> Even Parity Correct! - true - else { // result of Parity Calculation is 1 --> Even Parity incorrect! - false - } - } - - /***************************************************** - * This function makes ParellelParityBit(int[] payLoad) (word : 4bit) - * - * parameter : - * int[] payLoad - Payload Data - * return type : int - * the EvenParity data to transmit - */ - fun makeParellelParity(payLoad: IntArray): Int { - var evenParity1 = 0 - var evenParity2 = 0 - var evenParity3 = 0 - var evenParity4 = 0 - val evenParity: Int - - for (i in payLoad.indices) { - evenParity1 += 0x8 and payLoad[i] shr 3 - evenParity2 += 0x4 and payLoad[i] shr 2 - evenParity3 += 0x2 and payLoad[i] shr 1 - evenParity4 += 0x1 and payLoad[i] - } - - Log.i("UHEHE", "$evenParity1 $evenParity2 $evenParity3 $evenParity4") - evenParity = (evenParity1 and 0x1) * 8 + (evenParity2 and 0x1) * 4 + (evenParity3 and 0x1) * 2 + (evenParity4 and 0x1) - - return evenParity - } - - /***************************************************** - * This function verify Checksum bit (word : 4bit) - * parameter : - * int[] Payload - Payload Data - * int nSizeOfPayload, - Payload Data's quantity - * int nCheckSum - Checksum bit's value - * return type : boolean - * true - Checksum is correct - * WAIT - Checksum is incorrect - */ - fun verifyCheckSum(payLoad: IntArray, checkSum: Int): Boolean { - var sumTemp = 0 - var checkResult = 0 - for (i in payLoad.indices) { // add all of payload data - sumTemp += payLoad[i] - } - // add checksum data - sumTemp += checkSum - // get 2's Complement and remove carry - checkResult = sumTemp.inv() + 1 and 0xF - return if (checkResult == 0x0) { - true - } else - false - } - - /***************************************************** - * This function makes Checksum bit(word : 4bit) - * parameter : int[] Payload - Payload Data - * int nSizeOfPayload, - Payload Data's quantity - * int nCheckSum - Checksum bit's value - * return type : int - * the Checksum data to transmit - */ - fun makeCheckSum(payLoad: IntArray): Int { - var nSumTemp = 0 - var nCheckSum = 0 // CheckSum's Initial value is 0 - for (i in payLoad.indices) { - nSumTemp += payLoad[i] - } - // remove carry - nSumTemp = nSumTemp and 0xF - // get 2's Complement and make checksum 4bit word - nCheckSum = nSumTemp.inv() + 1 and 0xF - Log.v("TCheckSum", "TCheckSum $nCheckSum") - return nCheckSum - } - } -} \ No newline at end of file diff --git a/euphony/src/main/libs/arm64-v8a/libkissff.so b/euphony/src/main/libs/arm64-v8a/libkissff.so deleted file mode 100755 index b6f6ac4..0000000 Binary files a/euphony/src/main/libs/arm64-v8a/libkissff.so and /dev/null differ diff --git a/euphony/src/main/libs/arm64-v8a/libkissfft.so b/euphony/src/main/libs/arm64-v8a/libkissfft.so deleted file mode 100755 index 0040163..0000000 Binary files a/euphony/src/main/libs/arm64-v8a/libkissfft.so and /dev/null differ diff --git a/euphony/src/main/libs/arm64-v8a/libkissfftr.so b/euphony/src/main/libs/arm64-v8a/libkissfftr.so deleted file mode 100755 index 3fc8633..0000000 Binary files a/euphony/src/main/libs/arm64-v8a/libkissfftr.so and /dev/null differ diff --git a/euphony/src/main/libs/armeabi-v7a/libkissff.so b/euphony/src/main/libs/armeabi-v7a/libkissff.so deleted file mode 100755 index 1a37070..0000000 Binary files a/euphony/src/main/libs/armeabi-v7a/libkissff.so and /dev/null differ diff --git a/euphony/src/main/libs/armeabi-v7a/libkissfft.so b/euphony/src/main/libs/armeabi-v7a/libkissfft.so deleted file mode 100755 index 5bea1fe..0000000 Binary files a/euphony/src/main/libs/armeabi-v7a/libkissfft.so and /dev/null differ diff --git a/euphony/src/main/libs/armeabi-v7a/libkissfftr.so b/euphony/src/main/libs/armeabi-v7a/libkissfftr.so deleted file mode 100755 index 86f9bff..0000000 Binary files a/euphony/src/main/libs/armeabi-v7a/libkissfftr.so and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/libkissff.so b/euphony/src/main/obj/local/arm64-v8a/libkissff.so deleted file mode 100755 index 62a97f3..0000000 Binary files a/euphony/src/main/obj/local/arm64-v8a/libkissff.so and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/libkissfft.so b/euphony/src/main/obj/local/arm64-v8a/libkissfft.so deleted file mode 100755 index 6e22269..0000000 Binary files a/euphony/src/main/obj/local/arm64-v8a/libkissfft.so and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/libkissfftr.so b/euphony/src/main/obj/local/arm64-v8a/libkissfftr.so deleted file mode 100755 index 04da502..0000000 Binary files a/euphony/src/main/obj/local/arm64-v8a/libkissfftr.so and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/libstdc++.a b/euphony/src/main/obj/local/arm64-v8a/libstdc++.a deleted file mode 100644 index 8b277f0..0000000 --- a/euphony/src/main/obj/local/arm64-v8a/libstdc++.a +++ /dev/null @@ -1 +0,0 @@ -! diff --git a/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o b/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o deleted file mode 100644 index a0a291e..0000000 Binary files a/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o.d b/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o.d deleted file mode 100644 index 595dd38..0000000 --- a/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o.d +++ /dev/null @@ -1,8 +0,0 @@ -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/obj/local/arm64-v8a/objs/kissff/kiss_fft.o: \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.c \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h: diff --git a/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o b/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o deleted file mode 100644 index f4ee0ee..0000000 Binary files a/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o.d b/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o.d deleted file mode 100644 index 1f834f2..0000000 --- a/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o.d +++ /dev/null @@ -1,11 +0,0 @@ -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/obj/local/arm64-v8a/objs/kissfft/euphony_lib_receiver_KissFFT.o: \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/euphony_lib_receiver_KissFFT.cpp \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h: diff --git a/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o b/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o deleted file mode 100644 index 4f856d7..0000000 Binary files a/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o and /dev/null differ diff --git a/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o.d b/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o.d deleted file mode 100644 index 4f770e0..0000000 --- a/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o.d +++ /dev/null @@ -1,11 +0,0 @@ -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/obj/local/arm64-v8a/objs/kissfftr/kiss_fftr.o: \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.c \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h: diff --git a/euphony/src/main/obj/local/armeabi-v7a/libkissff.so b/euphony/src/main/obj/local/armeabi-v7a/libkissff.so deleted file mode 100755 index 971aa47..0000000 Binary files a/euphony/src/main/obj/local/armeabi-v7a/libkissff.so and /dev/null differ diff --git a/euphony/src/main/obj/local/armeabi-v7a/libkissfft.so b/euphony/src/main/obj/local/armeabi-v7a/libkissfft.so deleted file mode 100755 index 7c74491..0000000 Binary files a/euphony/src/main/obj/local/armeabi-v7a/libkissfft.so and /dev/null differ diff --git a/euphony/src/main/obj/local/armeabi-v7a/libkissfftr.so b/euphony/src/main/obj/local/armeabi-v7a/libkissfftr.so deleted file mode 100755 index de2b9b5..0000000 Binary files a/euphony/src/main/obj/local/armeabi-v7a/libkissfftr.so and /dev/null differ diff --git a/euphony/src/main/obj/local/armeabi-v7a/libstdc++.a b/euphony/src/main/obj/local/armeabi-v7a/libstdc++.a deleted file mode 100644 index 8b277f0..0000000 --- a/euphony/src/main/obj/local/armeabi-v7a/libstdc++.a +++ /dev/null @@ -1 +0,0 @@ -! diff --git a/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o b/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o deleted file mode 100644 index 8ea78c1..0000000 Binary files a/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o and /dev/null differ diff --git a/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o.d b/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o.d deleted file mode 100644 index bf6d14d..0000000 --- a/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o.d +++ /dev/null @@ -1,8 +0,0 @@ -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/obj/local/armeabi-v7a/objs/kissff/kiss_fft.o: \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.c \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h: diff --git a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o b/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o deleted file mode 100644 index 27573f7..0000000 Binary files a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o and /dev/null differ diff --git a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o.d b/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o.d deleted file mode 100644 index 5de166f..0000000 --- a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o.d +++ /dev/null @@ -1,11 +0,0 @@ -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/obj/local/armeabi-v7a/objs/kissfft/euphony_lib_receiver_KissFFT.o: \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/euphony_lib_receiver_KissFFT.cpp \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/euphony_lib_receiver_KissFFT.h: diff --git a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o b/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o deleted file mode 100644 index c766abf..0000000 Binary files a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o and /dev/null differ diff --git a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o.d b/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o.d deleted file mode 100644 index 69b18b3..0000000 --- a/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o.d +++ /dev/null @@ -1,11 +0,0 @@ -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/obj/local/armeabi-v7a/objs/kissfftr/kiss_fftr.o: \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.c \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h \ - /Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fftr.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/kiss_fft.h: - -/Users/jbear/AndroidStudioProjects/Euphony/euphony/src/main/jni/_kiss_fft_guts.h: diff --git a/euphony/src/main/res/drawable-hdpi/ic_launcher.png b/euphony/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 288b665..0000000 Binary files a/euphony/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/euphony/src/main/res/drawable-mdpi/ic_launcher.png b/euphony/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 6ae570b..0000000 Binary files a/euphony/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/euphony/src/main/res/drawable-xhdpi/ic_launcher.png b/euphony/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index d4fb7cd..0000000 Binary files a/euphony/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/euphony/src/main/res/drawable-xxhdpi/ic_launcher.png b/euphony/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 85a6081..0000000 Binary files a/euphony/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/euphony/src/main/res/values-sw600dp/dimens.xml b/euphony/src/main/res/values-sw600dp/dimens.xml deleted file mode 100644 index 44f01db..0000000 --- a/euphony/src/main/res/values-sw600dp/dimens.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/euphony/src/main/res/values-sw720dp-land/dimens.xml b/euphony/src/main/res/values-sw720dp-land/dimens.xml deleted file mode 100644 index ee04b4b..0000000 --- a/euphony/src/main/res/values-sw720dp-land/dimens.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/euphony/src/main/res/values/dimens.xml b/euphony/src/main/res/values/dimens.xml deleted file mode 100644 index 0e9ce62..0000000 --- a/euphony/src/main/res/values/dimens.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/euphony/src/main/res/values/strings.xml b/euphony/src/main/res/values/strings.xml deleted file mode 100644 index 1805e66..0000000 --- a/euphony/src/main/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - Euphony - - diff --git a/euphony/src/main/res/values/styles.xml b/euphony/src/main/res/values/styles.xml deleted file mode 100644 index 6ce89c7..0000000 --- a/euphony/src/main/res/values/styles.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - diff --git a/euphony/src/test/java/euphony/lib/receiver/ReceiverUnitTest.java b/euphony/src/test/java/euphony/lib/receiver/ReceiverUnitTest.java index 1b6268f..8851e31 100644 --- a/euphony/src/test/java/euphony/lib/receiver/ReceiverUnitTest.java +++ b/euphony/src/test/java/euphony/lib/receiver/ReceiverUnitTest.java @@ -2,7 +2,7 @@ import org.junit.Test; -import euphony.lib.transmitter.EuDataEncoder; +import co.euphony.rx.EuDataDecoder; import static org.junit.Assert.assertEquals; diff --git a/euphony/src/test/java/euphony/lib/transmitter/TransmitterUnitTest.java b/euphony/src/test/java/euphony/lib/transmitter/TransmitterUnitTest.java index eddaca6..97387f5 100644 --- a/euphony/src/test/java/euphony/lib/transmitter/TransmitterUnitTest.java +++ b/euphony/src/test/java/euphony/lib/transmitter/TransmitterUnitTest.java @@ -1,35 +1,50 @@ package euphony.lib.transmitter; +import org.junit.Ignore; import org.junit.Test; -import euphony.lib.transmitter.EuDataEncoder; -import euphony.lib.util.EuOption; import static org.junit.Assert.assertEquals; public class TransmitterUnitTest { @Test + @Ignore("This unit-test was substituted by Base16EncoderTest.cpp on gtest") public void encode_hex_isCorrect() { + /* + * This unit-test was substituted by Base16EncoderTest.cpp on gtest + * EuDataEncoder mEuDataEncoder = new EuDataEncoder("hell"); assertEquals(mEuDataEncoder.getOriginalSource(), "hell"); assertEquals(mEuDataEncoder.encodeHexCharSource(), "68656c6c"); assertEquals(EuDataEncoder.encodeStaticHexCharSource("hello, euphony"), "68656c6c6f2c20657570686f6e79"); + */ } @Test - public void EuTxManager_iscorrect() { - EuTxManager mEuTxManager = new EuTxManager(); - mEuTxManager.setCode("Hello, Euphony"); - int length = 63488; - int outStreamLength = mEuTxManager.getOutStream().length; - assertEquals(outStreamLength, length); - mEuTxManager.process(); - mEuTxManager.process(3); + @Ignore("This unit-test was substituted by FSKTest.cpp on gtest") + public void EuCodeMaker_iscorrect() { + /* + * This unit-test was substituted by FSKTest.cpp on gtest + * + EuOption txOption = new EuOption(); + txOption.setModulationType(EuOption.ModulationType.CPFSK); - EuTxManager mEuTxManager2 = new EuTxManager(new EuOption(EuOption.EncodingType.ASCII, EuOption.CommunicationMode.LIVE)); - mEuTxManager2.setCode("Hello, Euphony"); - length = 231424; - outStreamLength = mEuTxManager2.getOutStream().length; - assertEquals(outStreamLength, length); + String code = EuDataEncoder.encodeStaticHexCharSource("hello"); + EuCodeMaker mCodeMaker = new EuCodeMaker(txOption); + short[] musicSource = mCodeMaker.assembleData(code); + assertEquals(musicSource.length, 5 * 2 * 2048); + + txOption.setModulationType(EuOption.ModulationType.FSK); + mCodeMaker.setOption(txOption); + musicSource = mCodeMaker.assembleData(code); + assertEquals(musicSource.length, 5 * 2 * 2048); + + txOption.setModulationType(EuOption.ModulationType.ASK); + mCodeMaker.setOption(txOption); + code = EuDataEncoder.encodeStaticBinaryCharSource("hello"); + musicSource = mCodeMaker.assembleData(code); + assertEquals(musicSource.length, 5*2*4*2048); + + */ } } diff --git a/euphony/src/test/java/euphony/lib/util/UtilUnitTest.java b/euphony/src/test/java/euphony/lib/util/UtilUnitTest.java index a0de913..16dc80c 100644 --- a/euphony/src/test/java/euphony/lib/util/UtilUnitTest.java +++ b/euphony/src/test/java/euphony/lib/util/UtilUnitTest.java @@ -1,9 +1,15 @@ package euphony.lib.util; import org.junit.Test; -import euphony.lib.transmitter.EuDataEncoder; + +import co.euphony.util.ErrorHandler; +import co.euphony.util.EuOption; +import co.euphony.util.PacketErrorDetector; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + public class UtilUnitTest { @Test public void packet_err_detect_isCorrect() @@ -11,21 +17,21 @@ public void packet_err_detect_isCorrect() int[] source = {0x6, 0x8, 0x6, 0x5, 0x6, 0xc, 0x6, 0xc, 0x6, 0xf}; assertEquals(PacketErrorDetector.makeCheckSum(source), 14); assertEquals(PacketErrorDetector.makeCheckSum( 234), 6); - assertEquals(PacketErrorDetector.makeParellelParity(source), 4); - assertEquals(PacketErrorDetector.makeParellelParity(234), 10); - assertEquals(PacketErrorDetector.checkEvenParity(source, 4), true); - assertEquals(PacketErrorDetector.checkEvenParity(source, 5), false); - assertEquals(PacketErrorDetector.verifyCheckSum(source, 14), true); - assertEquals(PacketErrorDetector.verifyCheckSum(source, 13), false); + assertEquals(PacketErrorDetector.makeParallelParity(source), 4); + assertEquals(PacketErrorDetector.makeParallelParity(234), 10); + assertTrue(PacketErrorDetector.checkEvenParity(source, 4)); + assertFalse(PacketErrorDetector.checkEvenParity(source, 5)); + assertTrue(PacketErrorDetector.verifyCheckSum(source, 14)); + assertFalse(PacketErrorDetector.verifyCheckSum(source, 13)); PacketErrorDetector errorDetector = new PacketErrorDetector(); - assertEquals(errorDetector.euGetEvenParityState(), false); + assertFalse(errorDetector.euGetEvenParityState()); errorDetector.euSetEvenParityState(true); - assertEquals(errorDetector.euGetEvenParityState(), true); + assertTrue(errorDetector.euGetEvenParityState()); } @Test - public void error_handler_isCorret() + public void error_handler_isCorrect() { ErrorHandler mErrorHandler = new ErrorHandler(20); mErrorHandler.euSetChannelState(ErrorHandler.BUSY); @@ -40,19 +46,14 @@ public void error_handler_isCorret() @Test public void option_isCorrect() { - EuOption option = new EuOption(); - option.setEncodingType(EuOption.EncodingType.ASCII); - assertEquals(option.getEncodingType(), EuOption.EncodingType.ASCII); - option.setEncodingType(EuOption.EncodingType.HEX); - assertEquals(option.getEncodingType(), EuOption.EncodingType.HEX); - option.setCommunicationMode(EuOption.CommunicationMode.GENERAL); - assertEquals(option.getCommunicationMode(), EuOption.CommunicationMode.GENERAL); - option.setCommunicationMode(EuOption.CommunicationMode.LIVE); - assertEquals(option.getCommunicationMode(), EuOption.CommunicationMode.LIVE); - - EuOption option2 = new EuOption(EuOption.EncodingType.HEX, EuOption.CommunicationMode.LIVE); - assertEquals(option2.getEncodingType(), EuOption.EncodingType.HEX); - assertEquals(option2.getCommunicationMode(), EuOption.CommunicationMode.LIVE); + EuOption option = EuOption.builder() + .modeWith(EuOption.ModeType.DEFAULT) + .encodingWith(EuOption.CodingType.BASE16) + .modulationWith(EuOption.ModulationType.FSK) + .build(); + + assertEquals(option.getCodingType(), EuOption.CodingType.BASE16); + assertEquals(option.getMode(), EuOption.ModeType.DEFAULT); } } diff --git a/settings.gradle b/settings.gradle index 83ff1a7..08159e5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1 @@ -include ':euphony' - -// select main language : java, kotlin -gradle.ext.language = "java" // or kotlin \ No newline at end of file +include ':euphony' \ No newline at end of file