2012-06-19 9 views
17

Pracuję nad odtwarzaczem muzyki, w którym potrzebuję zmienić tempo (szybkość odtwarzania muzyki) bez zmiany wysokości.Android: Jak zmienić szybkość odtwarzania muzyki za pomocą OpenSL ES

Nie jestem w stanie znaleźć natywnej klasy na Androida. Próbowałem SoundPool, ale nie działa z dużymi plikami muzycznymi, a także nie działa na wielu urządzeniach. Próbowałem też AudioTrack, ale znowu nie miałem szczęścia.

Teraz próbuję dźwięku Android NDK przykład, który używa OpenSL ES do obsługi muzyki. Teraz po prostu chcę dodać funkcję ustawiania szybkości odtwarzania w tym przykładzie.

Czy ktoś może pokazać mi, w jaki sposób mogę dodać funkcję zmiany tempa odtwarzania?

Odpowiedz

30

Rozwiązałem mój problem. Oto mój pełny kod natywny dla OpenSL ES w przypadku innych konieczne to:

#include <jni.h> 

#include<android/log.h> 
// LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog 넣어주세요 
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "OSLESMediaPlayer", __VA_ARGS__) 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "OSLESMediaPlayer", __VA_ARGS__) 
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "OSLESMediaPlayer", __VA_ARGS__) 
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "OSLESMediaPlayer", __VA_ARGS__) 
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "OSLESMediaPlayer", __VA_ARGS__) 

// for native audio 
#include <SLES/OpenSLES.h> 
#include <SLES/OpenSLES_Android.h> 

#include <assert.h> 
#include <sys/types.h> 

// engine interfaces 
static SLObjectItf engineObject = NULL; 
static SLEngineItf engineEngine; 

// URI player interfaces 
static SLObjectItf uriPlayerObject = NULL; 
static SLPlayItf uriPlayerPlay; 
static SLSeekItf uriPlayerSeek; 
static SLPlaybackRateItf uriPlaybackRate; 

// output mix interfaces 
static SLObjectItf outputMixObject = NULL; 

// playback rate (default 1x:1000) 
static SLpermille playbackMinRate = 500; 
static SLpermille playbackMaxRate = 2000; 
static SLpermille playbackRateStepSize; 

//Pitch 
static SLPitchItf uriPlaybackPitch; 
static SLpermille playbackMinPitch = 500; 
static SLpermille playbackMaxPitch = 2000; 

// create the engine and output mix objects 
JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_createEngine(
     JNIEnv* env, jclass clazz) { 
    SLresult result; 

    // create engine 
    LOGD("create engine"); 
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); 
    assert(SL_RESULT_SUCCESS == result); 

    // realize the engine 
    LOGD("realize the engine"); 
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); 
    assert(SL_RESULT_SUCCESS == result); 

    // get the engine interface, which is needed in order to create other objects 
    LOGD("get the engine interface"); 
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, 
      &engineEngine); 
    assert(SL_RESULT_SUCCESS == result); 

    // create output mix, with environmental reverb specified as a non-required interface 
    LOGD("create output mix"); 
    const SLInterfaceID ids[1] = {SL_IID_PLAYBACKRATE}; 
    const SLboolean req[1] = {SL_BOOLEAN_FALSE}; 
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, 
      ids, req); 
    assert(SL_RESULT_SUCCESS == result); 

    // realize the output mix 
    LOGD("realize the output mix"); 
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); 
    assert(SL_RESULT_SUCCESS == result); 

} 

JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_releaseEngine(
     JNIEnv* env, jclass clazz) { 
    // destroy URI audio player object, and invalidate all associated interfaces 
    if (uriPlayerObject != NULL) { 
     (*uriPlayerObject)->Destroy(uriPlayerObject); 
     uriPlayerObject = NULL; 
     uriPlayerPlay = NULL; 
     uriPlayerSeek = NULL; 
    } 

    // destroy output mix object, and invalidate all associated interfaces 
    if (outputMixObject != NULL) { 
     (*outputMixObject)->Destroy(outputMixObject); 
     outputMixObject = NULL; 
    } 

    // destroy engine object, and invalidate all associated interfaces 
    if (engineObject != NULL) { 
     (*engineObject)->Destroy(engineObject); 
     engineObject = NULL; 
     engineEngine = NULL; 
    } 

} 

/* 
void OnCompletion(JNIEnv* env, jclass clazz) 
{ 
jclass cls = env->GetObjectClass(thiz); 
if (cls != NULL) 
{ 
jmethodID mid = env->GetMethodID(cls, "OnCompletion", "()V"); 
if (mid != NULL) 
{ 
env->CallVoidMethod(thiz, mid, 1234); 
} 
} 
}*/ 

void playStatusCallback(SLPlayItf play, void* context, SLuint32 event) { 
    //LOGD("playStatusCallback"); 
} 

// create URI audio player 
JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_createAudioPlayer(
     JNIEnv* env, jclass clazz, jstring uri) { 
    SLresult result; 

    // convert Java string to UTF-8 
    const jbyte *utf8 = (*env)->GetStringUTFChars(env, uri, NULL); 
    assert(NULL != utf8); 

    // configure audio source 
    // (requires the INTERNET permission depending on the uri parameter) 
    SLDataLocator_URI loc_uri = { SL_DATALOCATOR_URI, (SLchar *) utf8 }; 
    SLDataFormat_MIME format_mime = { SL_DATAFORMAT_MIME, NULL, 
      SL_CONTAINERTYPE_UNSPECIFIED }; 
    SLDataSource audioSrc = { &loc_uri, &format_mime }; 

    // configure audio sink 
    SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, 
      outputMixObject }; 
    SLDataSink audioSnk = { &loc_outmix, NULL }; 

    // create audio player 
    const SLInterfaceID ids[2] = { SL_IID_SEEK, SL_IID_PLAYBACKRATE }; 
    const SLboolean req[2] = { SL_BOOLEAN_FALSE, SL_BOOLEAN_TRUE }; 
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &uriPlayerObject, 
      &audioSrc, &audioSnk, 2, ids, req); 
    // note that an invalid URI is not detected here, but during prepare/prefetch on Android, 
    // or possibly during Realize on other platforms 
    assert(SL_RESULT_SUCCESS == result); 

    // release the Java string and UTF-8 
    (*env)->ReleaseStringUTFChars(env, uri, utf8); 

    // realize the player 
    result = (*uriPlayerObject)->Realize(uriPlayerObject, SL_BOOLEAN_FALSE); 
    // this will always succeed on Android, but we check result for portability to other platforms 
    if (SL_RESULT_SUCCESS != result) { 
     (*uriPlayerObject)->Destroy(uriPlayerObject); 
     uriPlayerObject = NULL; 
     return JNI_FALSE; 
    } 

    // get the play interface 
    result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PLAY, 
      &uriPlayerPlay); 
    assert(SL_RESULT_SUCCESS == result); 

    // get the seek interface 
    result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_SEEK, 
      &uriPlayerSeek); 
    assert(SL_RESULT_SUCCESS == result); 

    // get playback rate interface 
    result = (*uriPlayerObject)->GetInterface(uriPlayerObject, 
      SL_IID_PLAYBACKRATE, &uriPlaybackRate); 
    assert(SL_RESULT_SUCCESS == result); 

    /* // get playback pitch interface 
    result = (*uriPlayerObject)->GetInterface(uriPlayerObject, SL_IID_PITCH, &uriPlaybackPitch); 
    assert(SL_RESULT_SUCCESS == result);*/ 

    // register callback function 
    result = (*uriPlayerPlay)->RegisterCallback(uriPlayerPlay, 
      playStatusCallback, 0); 
    assert(SL_RESULT_SUCCESS == result); 
    result = (*uriPlayerPlay)->SetCallbackEventsMask(uriPlayerPlay, 
      SL_PLAYEVENT_HEADATEND); // head at end 
    assert(SL_RESULT_SUCCESS == result); 

    SLmillisecond msec; 
    result = (*uriPlayerPlay)->GetDuration(uriPlayerPlay, &msec); 
    assert(SL_RESULT_SUCCESS == result); 

    // no loop 
    result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, SL_BOOLEAN_TRUE, 0, msec); 
    assert(SL_RESULT_SUCCESS == result); 


    SLuint32 capa; 
     result = (*uriPlaybackRate)->GetRateRange(uriPlaybackRate, 0, 
       &playbackMinRate, &playbackMaxRate, &playbackRateStepSize, &capa); 
     assert(SL_RESULT_SUCCESS == result); 

     result = (*uriPlaybackRate)->SetPropertyConstraints(uriPlaybackRate, 
         SL_RATEPROP_PITCHCORAUDIO); 

        if (SL_RESULT_PARAMETER_INVALID == result) { 
         LOGD("Parameter Invalid"); 
        } 
        if (SL_RESULT_FEATURE_UNSUPPORTED == result) { 
          LOGD("Feature Unsupported"); 
         } 
        if (SL_RESULT_SUCCESS == result) { 
         assert(SL_RESULT_SUCCESS == result); 
          LOGD("Success"); 
         } 
    /* 
    result = (*uriPlaybackPitch)->GetPitchCapabilities(uriPlaybackPitch, &playbackMinPitch, &playbackMaxPitch); 
    assert(SL_RESULT_SUCCESS == result);*/ 

    /* 
    SLpermille minRate, maxRate, stepSize, rate = 1000; 
    SLuint32 capa; 
    (*uriPlaybackRate)->GetRateRange(uriPlaybackRate, 0, &minRate, &maxRate, &stepSize, &capa); 

    (*uriPlaybackRate)->SetRate(uriPlaybackRate, minRate); 
    */ 
    return JNI_TRUE; 
} 

JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_releaseAudioPlayer(
     JNIEnv* env, jclass clazz) { 
    // destroy URI audio player object, and invalidate all associated interfaces 
    if (uriPlayerObject != NULL) { 
     (*uriPlayerObject)->Destroy(uriPlayerObject); 
     uriPlayerObject = NULL; 
     uriPlayerPlay = NULL; 
     uriPlayerSeek = NULL; 
     uriPlaybackRate = NULL; 
    } 

} 

void setPlayState(SLuint32 state) { 
    SLresult result; 

    // make sure the URI audio player was created 
    if (NULL != uriPlayerPlay) { 

     // set the player's state 
     result = (*uriPlayerPlay)->SetPlayState(uriPlayerPlay, state); 
     assert(SL_RESULT_SUCCESS == result); 
    } 

} 

SLuint32 getPlayState() { 
    SLresult result; 

    // make sure the URI audio player was created 
    if (NULL != uriPlayerPlay) { 

     SLuint32 state; 
     result = (*uriPlayerPlay)->GetPlayState(uriPlayerPlay, &state); 
     assert(SL_RESULT_SUCCESS == result); 

     return state; 
    } 

    return 0; 

} 

// play 
JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_play(JNIEnv* env, 
     jclass clazz) { 
    setPlayState(SL_PLAYSTATE_PLAYING); 
} 

// stop 
JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_stop(JNIEnv* env, 
     jclass clazz) { 
    setPlayState(SL_PLAYSTATE_STOPPED); 
} 

// pause 
JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_pause(JNIEnv* env, 
     jclass clazz) { 
    setPlayState(SL_PLAYSTATE_PAUSED); 
} 

// pause 
JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_isPlaying(
     JNIEnv* env, jclass clazz) { 
    return (getPlayState() == SL_PLAYSTATE_PLAYING); 
} 

// set position 
JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_seekTo(
     JNIEnv* env, jclass clazz, jint position) { 
    if (NULL != uriPlayerPlay) { 

     //SLuint32 state = getPlayState(); 
     //setPlayState(SL_PLAYSTATE_PAUSED); 

     SLresult result; 

     result = (*uriPlayerSeek)->SetPosition(uriPlayerSeek, position, 
       SL_SEEKMODE_FAST); 
     assert(SL_RESULT_SUCCESS == result); 

     //setPlayState(state); 
    } 

} 

// get duration 
JNIEXPORT jint Java_com_swssm_waveloop_audio_OSLESMediaPlayer_getDuration(
     JNIEnv* env, jclass clazz) { 
    if (NULL != uriPlayerPlay) { 

     SLresult result; 

     SLmillisecond msec; 
     result = (*uriPlayerPlay)->GetDuration(uriPlayerPlay, &msec); 
     assert(SL_RESULT_SUCCESS == result); 

     return msec; 
    } 

    return 0.0f; 
} 

// get current position 
JNIEXPORT jint Java_com_swssm_waveloop_audio_OSLESMediaPlayer_getPosition(
     JNIEnv* env, jclass clazz) { 
    if (NULL != uriPlayerPlay) { 

     SLresult result; 

     SLmillisecond msec; 
     result = (*uriPlayerPlay)->GetPosition(uriPlayerPlay, &msec); 
     assert(SL_RESULT_SUCCESS == result); 

     return msec; 
    } 

    return 0.0f; 
} 

//llllllllllllllllllll 

JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setPitch(
     JNIEnv* env, jclass clazz, jint rate) { 
    if (NULL != uriPlaybackPitch) { 
     SLresult result; 

     result = (*uriPlaybackPitch)->SetPitch(uriPlaybackPitch, rate); 
     assert(SL_RESULT_SUCCESS == result); 
    } 
} 

JNIEXPORT void Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setRate(
     JNIEnv* env, jclass clazz, jint rate) { 
    if (NULL != uriPlaybackRate) { 
     SLresult result; 

     result = (*uriPlaybackRate)->SetRate(uriPlaybackRate, rate); 
      assert(SL_RESULT_SUCCESS == result); 


    } 
} 

JNIEXPORT jint Java_com_swssm_waveloop_audio_OSLESMediaPlayer_getRate(
     JNIEnv* env, jclass clazz) { 
    if (NULL != uriPlaybackRate) { 
     SLresult result; 

     SLpermille rate; 
     result = (*uriPlaybackRate)->GetRate(uriPlaybackRate, &rate); 
     assert(SL_RESULT_SUCCESS == result); 

     return rate; 
    } 

    return 0; 
} 

// create URI audio player 
JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setLoop(
     JNIEnv* env, jclass clazz, jint startPos, jint endPos) { 
    SLresult result; 

    result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, SL_BOOLEAN_TRUE, startPos, 
      endPos); 
    assert(SL_RESULT_SUCCESS == result); 

    return JNI_TRUE; 
} 

// create URI audio player 
JNIEXPORT jboolean Java_com_swssm_waveloop_audio_OSLESMediaPlayer_setNoLoop(
     JNIEnv* env, jclass clazz) { 
    SLresult result; 
    if (NULL != uriPlayerSeek) { 
     // enable whole file looping 
     result = (*uriPlayerSeek)->SetLoop(uriPlayerSeek, SL_BOOLEAN_TRUE, 0, 
       SL_TIME_UNKNOWN); 
     assert(SL_RESULT_SUCCESS == result); 

    } 
    return JNI_TRUE; 
} 

Wystarczy skompilować go za pomocą polecenia ndk-build i używać go. Jeśli ktokolwiek odniesie sukces w zmianie boiska, proszę, powiedz mi rozwiązanie.

Oto android.mk plikowi

LOCAL_PATH := $(call my-dir) 

include $(CLEAR_VARS) 

LOCAL_MODULE := audio-tools 

LOCAL_SRC_FILES := OSLESMediaPlayer.c 


LOCAL_CFLAGS := -DHAVE_CONFIG_H -DFPM_ARM -ffast-math -O3 

LOCAL_LDLIBS += -lOpenSLES -llog 

include $(BUILD_SHARED_LIBRARY) 

i Application.mk plik

APP_STL := gnustl_static 
APP_CPPFLAGS += -fexceptions -frtti 
APP_ABI := armeabi armeabi-v7a 

I klasy otoki, można użyć jego funkcji bezpośrednio w projekcie

package com.swssm.waveloop.audio; 
public class OSLESMediaPlayer { 
    public native void createEngine(); 
    public native void releaseEngine(); 
    public native boolean createAudioPlayer(String uri); 
    public native void releaseAudioPlayer(); 
    public native void play(); 
    public native void stop(); 
    public native void pause(); 
    public native boolean isPlaying(); 

    public native void seekTo(int position); 
    public native int getDuration(); 
    public native int getPosition(); 

    public native void setPitch(int rate); 

    public native void setRate(int rate); 
    public native int getRate(); 

    public native void setLoop(int startPos, int endPos); 
    public native void setNoLoop(); 


    public interface OnCompletionListener { 
     public void OnCompletion(); 
    } 

    private OnCompletionListener mCompletionListener; 
    public void SetOnCompletionListener(OnCompletionListener listener) 
    { 
     mCompletionListener = listener; 
    } 


    private void OnCompletion() 
    { 
     mCompletionListener.OnCompletion(); 

     int position = getPosition(); 
     int duration = getDuration(); 
     if(position != duration) 
     { 
      int a = 0; 

     } 
     else 
     { 
      int c = 0; 

     } 
    } 
} 
+0

Dzięki za podzielenie się swoją wiedzą. Czy możesz mi powiedzieć, że to będzie działać z plikami .Mp3. Czy mogę użyć tej biblioteki i kodu do zmiany tempa plików .mp3. Thanx w zaawansowanym vipul – Harsh

+1

Tak. Będzie działać z wszystkimi formatami plików MP3, WAV itp. Niestety funkcje zmiany tempa nie będą działać na ICS. Nie wiem dlaczego, ale ta funkcja została usunięta z OpenSL ES w Android ICS. –

+0

Thanx. W fragmencie kodu dołączasz 4 pliki (#include #include #include #include ) Gdzie mogę znaleźć te pliki. – Harsh

5

To może być pomocne (wzięte z dokumentacji OpenSL NDK):

szybkość odtwarzania

Zakres obsługiwana szybkość odtwarzania (s) i zdolności mogą się różnić zależności od wersji platformy i implementacji, i tak powinno być określona w czasie wykonywania przez kwerendy z PlaybackRate :: GetRateRange lub PlaybackRate :: GetCapabilitiesOfRate.

Powiedział, że niektóre wytyczne dotyczące typowych zakresów stóp może być użyteczne: W Androidzie 2.3 pojedynczy wskaźnik odtwarzania zakres od 500 do 2000 promila promila integracyjnego jest zazwyczaj obsługiwane, z własności SL_RATEPROP_NOPITCHCORAUDIO. W systemie Android 4.0 ten sam zakres stawek jest zwykle obsługiwany w przypadku źródła danych w formacie PCM , a także w zakresie współczynnika jedności dla innych formatów.

Powiązane problemy