Альтернатива для ifstream (c ++) при попытке прочитать файл .wav в android

Я пытаюсь вычислить коэффициенты MFCC из файлов WAV, хранящихся на SD-карте. Я использую библиотеку: https://github.com/dspavankumar/compute-mfcc

Входными данными является путь к файлу wav с использованием ifstream. Мне нужно иметь доступ к различным файлам pcm, разделенным из одного файла wav в соответствии с временными сегментами, и вычислять MFCC для каждого сегмента. У меня возникли проблемы с поиском способа получить эти данные (необработанные данные pcm) в буфер, показанный в методе ниже, из класса java. (Используя JNI)

int process (std::ifstream &wavFp, std::ofstream &mfcFp) {
    // Read the wav header    
    wavHeader hdr;
    int headerSize = sizeof(wavHeader);

    wavFp.read((char *) &hdr, headerSize);

    // Check audio format
    if (hdr.AudioFormat != 1 || hdr.bitsPerSample != 16) {
        std::cerr << "Unsupported audio format, use 16 bit PCM Wave" << 
    std::endl;
        return 1;
    }
    // Check sampling rate
    if (hdr.SamplesPerSec != fs) {
        std::cerr << "Sampling rate mismatch: Found " << hdr.SamplesPerSec << " instead of " << fs <<std::endl;
        return 1;
    }

    // Initialise buffer
    uint16_t bufferLength = winLengthSamples-frameShiftSamples;
    int16_t* buffer = new int16_t[bufferLength];
    int bufferBPS = (sizeof buffer[0]);

    // Read and set the initial samples        
    wavFp.read((char *) buffer, bufferLength*bufferBPS);
    for (int i=0; i<bufferLength; i++)
        prevsamples[i] = buffer[i];        
    delete [] buffer;

    // Recalculate buffer size
    bufferLength = frameShiftSamples;
    buffer = new int16_t[bufferLength];

    // Read data and process each frame
    wavFp.read((char *) buffer, bufferLength*bufferBPS);
    while (wavFp.gcount() == bufferLength*bufferBPS && !wavFp.eof()) {
        mfcFp << processFrame(buffer, bufferLength);
        wavFp.read((char *) buffer, bufferLength*bufferBPS);
    }
    delete [] buffer;
    buffer = nullptr;
    return 0;
}

`

Похоже, я не могу получить доступ к файлу wav на SD-карте непосредственно из библиотеки С ++. Итак, я попытался передать jbytearray и преобразовать его в char *, используя:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_nikhar_mst04v10_RecordActivity_doMFCC(JNIEnv *env, jobject 
instance,
                                                   jbyteArray wavBytes_) {
int len = env ->GetArrayLength(wavBytes_);
char* buf = new char[len];
env->GetByteArrayRegion(wavBytes_,0,len, reinterpret_cast<jbyte *>(buf));

// TODO

 /* env->ReleaseStringUTFChars(wavPath_, wavPath);
env->ReleaseStringUTFChars(mfccPath_, mfccPath);*/
// Assign variables
int numCepstra =  12;
int numFilters =  40;
int samplingRate = 16000;
int winLength = 25;
int frameShift = 10;
int lowFreq = 50;
int highFreq = samplingRate/2;

// Initialise MFCC class instance
MFCC mfccComputer (samplingRate, numCepstra, winLength, frameShift, 
numFilters, lowFreq, highFreq);
mfccComputer.process(buf);
}

но это было безуспешно. Есть предложения, как я могу это сделать?


person user2654207    schedule 17.10.2017    source источник
comment
Примечание: я изменил параметры для mfccComputer на (const * char wavBytes)   -  person user2654207    schedule 17.10.2017
comment
Похоже, я не могу получить доступ к wav-файлу на SD-карте. Примечание: у нас 2017 год, а Android 6 был представлен в 2015 году, так что у вас было 2 года, чтобы узнать, что было изменено. Очевидно, проблема с разрешениями не с ifstreams   -  person Selvin    schedule 17.10.2017
comment
Я впервые использую android. Это просто для конкретной цели, так что я учусь, как и собираюсь   -  person user2654207    schedule 17.10.2017
comment
Я впервые использую Android Это не меняет того факта, что вам следует провести небольшое исследование, прежде чем спрашивать   -  person Selvin    schedule 17.10.2017
comment
Я очень старался, но, возможно, из-за моей неопытности я пропустил ответ, который искал   -  person user2654207    schedule 17.10.2017
comment
В опубликованном вами коде вы определяете int process (std::ifstream &wavFp, std::ofstream &mfcFp), но вызываете другой process() метод: mfccComputer.process(buf); Пожалуйста, опубликуйте фактический код, который вы используете.   -  person Andrew Henle    schedule 19.10.2017


Ответы (1)


Взгляните сюда:

http://jnicookbook.owsiak.org/recipe-No-012/

чтобы познакомиться с передачей массивов между Java и C.

Что касается jbyte - этот тип зависит от машины. Обычно это «знаковый символ». Я предлагаю передать ваши данные в C, а затем преобразовать массив в char *. Он должен работать.

Но! Не забудьте дважды проверить, как объявляется jbyte в вашей целевой системе. Вы можете найти его здесь: $ YOUR_PLATFORM_NAME / jni_md.h

person Oo.oO    schedule 18.10.2017
comment
Что касается jbyte - этот тип зависит от машины. Не должно быть. Oracle определяет его как подписанные 8 бит: docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ - person Michael; 18.10.2017
comment
Из jni.h - / * jni_md.h содержит машинно-зависимые определения типов для jbyte, jint и jlong ​​* / - person Oo.oO; 18.10.2017