mirror of
https://github.com/azahar-emu/soundtouch
synced 2025-11-06 23:20:03 +01:00
198 lines
5.6 KiB
C++
198 lines
5.6 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
///
|
|
/// Example Interface class for SoundTouch native compilation
|
|
///
|
|
/// Author : Copyright (c) Olli Parviainen
|
|
/// Author e-mail : oparviai 'at' iki.fi
|
|
/// WWW : http://www.surina.net
|
|
///
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// $Id$
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <jni.h>
|
|
#include <android/log.h>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
using namespace std;
|
|
|
|
#include "../../../include/SoundTouch.h"
|
|
#include "../source/SoundStretch/WavFile.h"
|
|
|
|
#define LOGV(...) __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
|
|
//#define LOGV(...)
|
|
|
|
|
|
// String for keeping possible c++ exception error messages. Notice that this isn't
|
|
// thread-safe but it's expected that exceptions are special situations that won't
|
|
// occur in several threads in parallel.
|
|
static string _errMsg = "";
|
|
|
|
|
|
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
|
|
#define BUFF_SIZE 4096
|
|
|
|
|
|
using namespace soundtouch;
|
|
|
|
|
|
// Set error message to return
|
|
static void _setErrmsg(const char *msg)
|
|
{
|
|
_errMsg = msg;
|
|
}
|
|
|
|
|
|
|
|
// Processes the sound file
|
|
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
|
|
{
|
|
int nSamples;
|
|
int nChannels;
|
|
int buffSizeSamples;
|
|
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
|
|
|
// open input file
|
|
WavInFile inFile(inFileName);
|
|
int sampleRate = inFile.getSampleRate();
|
|
int bits = inFile.getNumBits();
|
|
nChannels = inFile.getNumChannels();
|
|
|
|
// create output file
|
|
WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
|
|
|
|
pSoundTouch->setSampleRate(sampleRate);
|
|
pSoundTouch->setChannels(nChannels);
|
|
|
|
assert(nChannels > 0);
|
|
buffSizeSamples = BUFF_SIZE / nChannels;
|
|
|
|
// Process samples read from the input file
|
|
while (inFile.eof() == 0)
|
|
{
|
|
int num;
|
|
|
|
// Read a chunk of samples from the input file
|
|
num = inFile.read(sampleBuffer, BUFF_SIZE);
|
|
nSamples = num / nChannels;
|
|
|
|
// Feed the samples into SoundTouch processor
|
|
pSoundTouch->putSamples(sampleBuffer, nSamples);
|
|
|
|
// Read ready samples from SoundTouch processor & write them output file.
|
|
// NOTES:
|
|
// - 'receiveSamples' doesn't necessarily return any samples at all
|
|
// during some rounds!
|
|
// - On the other hand, during some round 'receiveSamples' may have more
|
|
// ready samples than would fit into 'sampleBuffer', and for this reason
|
|
// the 'receiveSamples' call is iterated for as many times as it
|
|
// outputs samples.
|
|
do
|
|
{
|
|
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
|
outFile.write(sampleBuffer, nSamples * nChannels);
|
|
} while (nSamples != 0);
|
|
}
|
|
|
|
// Now the input file is processed, yet 'flush' few last samples that are
|
|
// hiding in the SoundTouch's internal processing pipeline.
|
|
pSoundTouch->flush();
|
|
do
|
|
{
|
|
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
|
outFile.write(sampleBuffer, nSamples * nChannels);
|
|
} while (nSamples != 0);
|
|
}
|
|
|
|
|
|
|
|
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
|
|
{
|
|
const char *verStr;
|
|
|
|
LOGV("JNI call SoundTouch.getVersionString");
|
|
|
|
// Call example SoundTouch routine
|
|
verStr = SoundTouch::getVersionString();
|
|
|
|
// return version as string
|
|
return env->NewStringUTF(verStr);
|
|
}
|
|
|
|
|
|
|
|
extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
|
|
{
|
|
return (jlong)(new SoundTouch());
|
|
}
|
|
|
|
|
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
|
|
{
|
|
SoundTouch *ptr = (SoundTouch*)handle;
|
|
delete ptr;
|
|
}
|
|
|
|
|
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
|
|
{
|
|
SoundTouch *ptr = (SoundTouch*)handle;
|
|
ptr->setTempo(tempo);
|
|
}
|
|
|
|
|
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
|
|
{
|
|
SoundTouch *ptr = (SoundTouch*)handle;
|
|
ptr->setPitchSemiTones(pitch);
|
|
}
|
|
|
|
|
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
|
|
{
|
|
SoundTouch *ptr = (SoundTouch*)handle;
|
|
ptr->setRate(speed);
|
|
}
|
|
|
|
|
|
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
|
|
{
|
|
jstring result = env->NewStringUTF(_errMsg.c_str());
|
|
_errMsg.clear();
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
|
|
{
|
|
SoundTouch *ptr = (SoundTouch*)handle;
|
|
|
|
const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
|
|
const char *outputFile = env->GetStringUTFChars(joutputFile, 0);
|
|
|
|
LOGV("JNI process file %s", inputFile);
|
|
|
|
try
|
|
{
|
|
_processFile(ptr, inputFile, outputFile);
|
|
}
|
|
catch (const runtime_error &e)
|
|
{
|
|
const char *err = e.what();
|
|
// An exception occurred during processing, return the error message
|
|
LOGV("JNI exception in SoundTouch::processFile: %s", err);
|
|
_setErrmsg(err);
|
|
return -1;
|
|
}
|
|
|
|
|
|
env->ReleaseStringUTFChars(jinputFile, inputFile);
|
|
env->ReleaseStringUTFChars(joutputFile, outputFile);
|
|
|
|
return 0;
|
|
}
|