swapnilgt

Untitled

Apr 8th, 2018
65
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ////////////////////////////////////////////////////////////////////////////////
  2. ///
  3. /// Example Interface class for SoundTouch native compilation
  4. ///
  5. /// Author        : Copyright (c) Olli Parviainen
  6. /// Author e-mail : oparviai 'at' iki.fi
  7. /// WWW           : http://www.surina.net
  8. ///
  9. ////////////////////////////////////////////////////////////////////////////////
  10. //
  11. // $Id: soundtouch-jni.cpp 212 2015-05-15 10:22:36Z oparviai $
  12. //
  13. ////////////////////////////////////////////////////////////////////////////////
  14.  
  15. #include <jni.h>
  16. #include <android/log.h>
  17. #include <stdexcept>
  18. #include <string>
  19.  
  20. using namespace std;
  21.  
  22. #include "../../../include/SoundTouch.h"
  23. #include "../source/SoundStretch/WavFile.h"
  24.  
  25. #define LOGV(...)   __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
  26. //#define LOGV(...)
  27.  
  28.  
  29. // String for keeping possible c++ exception error messages. Notice that this isn't
  30. // thread-safe but it's expected that exceptions are special situations that won't
  31. // occur in several threads in parallel.
  32. static string _errMsg = "";
  33.  
  34.  
  35. #define DLL_PUBLIC __attribute__ ((visibility ("default")))
  36. #define BUFF_SIZE 4096
  37.  
  38.  
  39. using namespace soundtouch;
  40.  
  41.  
  42. // Set error message to return
  43. static void _setErrmsg(const char *msg)
  44. {
  45.     _errMsg = msg;
  46. }
  47.  
  48.  
  49. #ifdef _OPENMP
  50.  
  51. #include <pthread.h>
  52. extern pthread_key_t gomp_tls_key;
  53. static void * _p_gomp_tls = NULL;
  54.  
  55. /// Function to initialize threading for OpenMP.
  56. ///
  57. /// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if
  58. /// called from the Android App main thread because in the main thread the gomp_tls storage is
  59. /// properly set, however, Android does not properly initialize gomp_tls storage for other threads.
  60. /// Thus if OpenMP routines are invoked from some other thread than the main thread,
  61. /// the OpenMP routine will crash the application due to NULL pointer access on uninitialized storage.
  62. ///
  63. /// This workaround stores the gomp_tls storage from main thread, and copies to other threads.
  64. /// In order this to work, the Application main thread needws to call at least "getVersionString"
  65. /// routine.
  66. static int _init_threading(bool warn)
  67. {
  68.     void *ptr = pthread_getspecific(gomp_tls_key);
  69.     LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
  70.     if (ptr == NULL)
  71.     {
  72.         LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
  73.         pthread_setspecific(gomp_tls_key, _p_gomp_tls);
  74.     }
  75.     else
  76.     {
  77.         LOGV("JNI store this TLS storage");
  78.         _p_gomp_tls = ptr;
  79.     }
  80.     // Where critical, show warning if storage still not properly initialized
  81.     if ((warn) && (_p_gomp_tls == NULL))
  82.     {
  83.         _setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
  84.         return -1;
  85.     }
  86.     return 0;
  87. }
  88.  
  89. #else
  90. static int _init_threading(bool warn)
  91. {
  92.     // do nothing if not OpenMP build
  93.     return 0;
  94. }
  95. #endif
  96.  
  97.  
  98. // Processes the sound file
  99. static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
  100. {
  101.     int nSamples;
  102.     int nChannels;
  103.     int buffSizeSamples;
  104.     SAMPLETYPE sampleBuffer[BUFF_SIZE];
  105.  
  106.     // open input file
  107.     WavInFile inFile(inFileName);
  108.     int sampleRate = inFile.getSampleRate();
  109.     int bits = inFile.getNumBits();
  110.     nChannels = inFile.getNumChannels();
  111.  
  112.     // create output file
  113.     WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
  114.  
  115.     pSoundTouch->setSampleRate(sampleRate);
  116.     pSoundTouch->setChannels(nChannels);
  117.  
  118.     assert(nChannels > 0);
  119.     buffSizeSamples = BUFF_SIZE / nChannels;
  120.  
  121.     // Process samples read from the input file
  122.     while (inFile.eof() == 0)
  123.     {
  124.         int num;
  125.  
  126.         // Read a chunk of samples from the input file
  127.         num = inFile.read(sampleBuffer, BUFF_SIZE);
  128.         nSamples = num / nChannels;
  129.  
  130.         // Feed the samples into SoundTouch processor
  131.         pSoundTouch->putSamples(sampleBuffer, nSamples);
  132.  
  133.         // Read ready samples from SoundTouch processor & write them output file.
  134.         // NOTES:
  135.         // - 'receiveSamples' doesn't necessarily return any samples at all
  136.         //   during some rounds!
  137.         // - On the other hand, during some round 'receiveSamples' may have more
  138.         //   ready samples than would fit into 'sampleBuffer', and for this reason
  139.         //   the 'receiveSamples' call is iterated for as many times as it
  140.         //   outputs samples.
  141.         do
  142.         {
  143.             nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
  144.             outFile.write(sampleBuffer, nSamples * nChannels);
  145.         } while (nSamples != 0);
  146.     }
  147.  
  148.     // Now the input file is processed, yet 'flush' few last samples that are
  149.     // hiding in the SoundTouch's internal processing pipeline.
  150.     pSoundTouch->flush();
  151.     do
  152.     {
  153.         nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
  154.         outFile.write(sampleBuffer, nSamples * nChannels);
  155.     } while (nSamples != 0);
  156. }
  157.  
  158.  
  159.  
  160. extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
  161. {
  162.     const char *verStr;
  163.  
  164.     LOGV("JNI call SoundTouch.getVersionString");
  165.  
  166.     // Call example SoundTouch routine
  167.     verStr = SoundTouch::getVersionString();
  168.  
  169.     /// gomp_tls storage bug workaround - see comments in _init_threading() function!
  170.     _init_threading(false);
  171.  
  172.     int threads = 0;
  173.     #pragma omp parallel
  174.     {
  175.         #pragma omp atomic
  176.         threads ++;
  177.     }
  178.     LOGV("JNI thread count %d", threads);
  179.  
  180.     // return version as string
  181.     return env->NewStringUTF(verStr);
  182. }
  183.  
  184.  
  185.  
  186. extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
  187. {
  188.     return (jlong)(new SoundTouch());
  189. }
  190.  
  191.  
  192. extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
  193. {
  194.     SoundTouch *ptr = (SoundTouch*)handle;
  195.     delete ptr;
  196. }
  197.  
  198.  
  199. extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
  200. {
  201.     SoundTouch *ptr = (SoundTouch*)handle;
  202.     ptr->setTempo(tempo);
  203. }
  204.  
  205.  
  206. extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
  207. {
  208.     SoundTouch *ptr = (SoundTouch*)handle;
  209.     ptr->setPitchSemiTones(pitch);
  210. }
  211.  
  212.  
  213. extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
  214. {
  215.     SoundTouch *ptr = (SoundTouch*)handle;
  216.     ptr->setRate(speed);
  217. }
  218.  
  219.  
  220. extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
  221. {
  222.     jstring result = env->NewStringUTF(_errMsg.c_str());
  223.     _errMsg.clear();
  224.  
  225.     return result;
  226. }
  227.  
  228.  
  229. extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
  230. {
  231.     SoundTouch *ptr = (SoundTouch*)handle;
  232.  
  233.     const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
  234.     const char *outputFile = env->GetStringUTFChars(joutputFile, 0);
  235.  
  236.     LOGV("JNI process file %s", inputFile);
  237.  
  238.     /// gomp_tls storage bug workaround - see comments in _init_threading() function!
  239.     if (_init_threading(true)) return -1;
  240.  
  241.     try
  242.     {
  243.         _processFile(ptr, inputFile, outputFile);
  244.     }
  245.     catch (const runtime_error &e)
  246.     {
  247.         const char *err = e.what();
  248.         // An exception occurred during processing, return the error message
  249.         LOGV("JNI exception in SoundTouch::processFile: %s", err);
  250.         _setErrmsg(err);
  251.         return -1;
  252.     }
  253.  
  254.  
  255.     env->ReleaseStringUTFChars(jinputFile, inputFile);
  256.     env->ReleaseStringUTFChars(joutputFile, outputFile);
  257.  
  258.     return 0;
  259. }
RAW Paste Data Copied