2016-03-24 8 views
16

Ich habe eine Funktion, die ich über Android AudioTrack statt MediaPlayer anstelle von MediaPlayer, wegen ein paar gut bekannten Bugs mit MediaPlayer, wie die kleine Lücke, die zwischen Looping-Tracks erscheint.Play looping audio mit AudioTrack

Ich wurde empfohlen, AudioTrack zu verwenden, aber habe nicht zu viele Beispiele dafür gefunden. Ich habe eine Frage finden auf SO AudioTrack Bezug und einen Teil dieses Code verwendet zu hacken zusammen etwas:

public class TestActivity extends Activity implements Runnable { 

    Button playButton; 
    byte[] byteData = null; 
    int bufSize; 
    AudioTrack myAT = null; 
    Thread playThread = null; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_test); 

     playButton = (Button) findViewById(R.id.testButton); 

     InputStream inputStream = getResources().openRawResource(R.raw.whitenoise_wav); 
     try { 
      byteData = new byte[ inputStream.available()]; 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     try { 
      inputStream.read(byteData); 
      inputStream.close(); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     initialize(); 

     playButton.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View v) { 

       playThread.start(); 
      } 
     }); 
    } 

    void initialize() { 

     bufSize = android.media.AudioTrack.getMinBufferSize(44100, 
       AudioFormat.CHANNEL_CONFIGURATION_STEREO, 
       AudioFormat.ENCODING_PCM_16BIT); 

     myAT = new AudioTrack(AudioManager.STREAM_MUSIC, 
       44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO, 
       AudioFormat.ENCODING_PCM_16BIT, bufSize, 
       AudioTrack.MODE_STREAM); 
     myAT.setVolume(.2f); 

     playThread = new Thread(this); 
    } 

    public void run() { 
     if (myAT != null) { 
      myAT.play(); 
      myAT.setLoopPoints(0, byteData.length, 6); 
      myAT.write(byteData, 0, byteData.length); 
     } 
    } 
} 

dies nicht so scheint die gesamte Audiospur (~ 1: 00 min) zu spielen und hält dann an. Jetzt ist das Endziel hier zwei haben zwei separate Audio-Tracks spielen und Looping zur gleichen Zeit. Ich habe derzeit die Audiospuren im Verzeichnis /res/raw/, aber ich kann sie in einen einfachen Ordner assets verschieben, wenn das besser wäre. Ist meine aktuelle Implementierung von AudioTrack korrekt? Wenn ja, wie würde ich es in die Schleife bekommen?

Zusammenfassend: Wie können Sie looping Audio ohne eine Lücke mit AudioTrack?

Vorschläge für alternative Möglichkeiten zum Erhalten von Audio-Schleifen, wie zum Beispiel Bibliotheken von Drittanbietern, sind willkommen.

+0

Willst du die beiden Tracks gleichzeitig abspielen und auch das Audio einmal richtig beenden? –

+0

Das ist richtig. – Orbit

+0

Überprüfen Sie dies: http://developer.android.com/reference/android/media/SoundPool.html –

Antwort

5

Sie können keine Schleife mit einem AudioTrack durchführen, das mit AudioTrack.MODE_STREAM konfiguriert wurde. Wenn Sie MODE_STREAM verwenden, muss AudioTrack kontinuierlich mit neuen Samples gefüllt werden.

Aber Sie können es mit AudioTrack.MODE_STATIC konfigurieren und den gesamten Puffer übergeben, um gespielt zu werden (ich meine: wenn Sie zwei Proben mischen müssen, müssen Sie die gemischten Proben übergeben).

setLoopPoints: Legt die Loop-Punkte und die Loop-Anzahl fest. Die Schleife kann unendlich sein. Ähnlich wie setPlaybackHeadPosition muss die Spur für die zu ändernden Loop-Punkte angehalten oder angehalten werden und muss den Modus MODE_STATIC verwenden.

Bitte beachten Sie, dass AudioTrack rohe PCM-Samples spielt, es gibt keine Unterstützung für WAV, MP3 oder andere Container.

+0

Wenn die Datei in Ihren rohen Ressourcen gespeichert wird, können Sie einen 'InputStream' zurückgeben, wenn Sie die Ressource abrufen und in den' AudioTrack' einspeisen. Mit "looping" meine ich jede Art und Weise, wie man es richtig ablaufen lässt, ob es Daten kontinuierlich oder einmal zuführt und automatisch schleift, es kann einfach keine Lücke haben. – Orbit

+0

Ich verstehe, was Sie sagen, ich weiß, dass automatische Schleife mit '.setLoopingPoints()' kann nur im statischen Modus durchgeführt werden. Ich war auf der Suche nach einem Beispiel für eine lückenlose Schleife mit 'MODE_STATIC' und/oder' MODE_STREAM', da die meisten Beispiele, die ich gefunden habe, nicht wirklich funktionierten. Ich habe ein bisschen herumgespielt und eine funktionierende Implementierung mit dem statischen Modus und '.setLoopingPoints' bekommen, obwohl es manchmal während der Wiedergabe stottert. Ich habe auch bemerkt, dass wenn es nicht in einem neuen Thread gespielt wird, es beim Starten einen lauten Startton erzeugt und dann verstummt. Spielt der Hauptthread ein Problem? – Orbit

1

Betrachten Sie this Beispiel, es scheint ein ähnliches Problem, gelöst kontinuierlich AudioTrack.

class ToneGenerator { 
    int sampleRate = 8000; 
    double sample[] = null; 
    byte generatedSnd[] = null; 
    int m_ifreq = 400; 
    Thread m_PlayThread = null; 
    boolean m_bStop = false; 
    AudioTrack m_audioTrack = null; 
    int m_play_length = 1000;//in seconds 

    static public void PlayTone(int freq, int play_length) { 
     ToneGenerator player = new ToneGenerator(); 
     player.m_ifreq = freq; 
     player.m_play_length = play_length; 
     player.play(); 
    } 

    synchronized void stop() { 
     m_bStop = true; 
     if (m_PlayThread != null) { 
      try { 
       m_PlayThread.interrupt(); 
       m_PlayThread.join(); 
       m_PlayThread = null; 
      } catch (Exception e) { 

      } 
     } 
     if (m_audioTrack != null) { 
      m_audioTrack.stop(); 
      m_audioTrack.release(); 
      m_audioTrack = null; 
     } 
    } 

    synchronized void play() { 
     m_bStop = false; 
     m_PlayThread = new Thread() { 
      public void run() { 
       try { 
        int iToneStep = 0; 

        m_audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 
          sampleRate, AudioFormat.CHANNEL_OUT_MONO, 
          AudioFormat.ENCODING_PCM_16BIT, 2 * sampleRate, 
          AudioTrack.MODE_STREAM); 

        while (!m_bStop && m_play_length-- > 0) { 
         genTone(iToneStep++); 

         m_audioTrack.write(generatedSnd, 0, generatedSnd.length); 
         if (iToneStep == 1) { 
          m_audioTrack.play(); 
         } 
        } 
       } catch (Exception e) { 
        Log.e("Tone", e.toString()); 
       } catch (OutOfMemoryError e) { 
        Log.e("Tone", e.toString()); 
       } 

      } 
     }; 
     m_PlayThread.start(); 
    } 

    //Generate tone data for 1 seconds 
    synchronized void genTone(int iStep) { 
     sample = new double[sampleRate]; 

     for (int i = 0; i < sampleRate; ++i) { 
      sample[i] = Math.sin(2 * Math.PI * (i + iStep * sampleRate)/(sampleRate/m_ifreq)); 
     } 

     // convert to 16 bit pcm sound array 
     // assumes the sample buffer is normalised. 
     generatedSnd = new byte[2 * sampleRate]; 
     int idx = 0; 
     for (final double dVal : sample) { 
      // scale to maximum amplitude 
      final short val = (short) ((dVal * 32767)); 
      // in 16 bit wav PCM, first byte is the low order byte 
      generatedSnd[idx++] = (byte) (val & 0x00ff); 
      generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8); 
     } 
    } 

} 
+0

Warum 2 * SampleRate? – Coco

+0

Wegen 16bit Sampling, also 8 * 2 – loretoparisi

0

Sie geben die Bytelänge des Streams weiter. setLoopPoints() erwartet die Anzahl der Audioblöcke im Stream. Siehe getBufferSizeInFrames() in der Dokumentation.

Jedoch. Ich warne Sie, dass die meisten Audioformate nicht blockbasiert sind; Sie basieren auf Beispielen. MP3 ist die einzige Ausnahme; Es ist auf 1152 Byte Grenzen ausgerichtet. Wenn der Quellinhalt MP3 ist und nicht explizit für Block Alignment erstellt wurde, ist Seamless Looping unmöglich. Sie scheinen "whitenoise.wav" als Audioquelle zu verwenden. Wenn die Länge dieser Datei nicht explizit an die Blockgröße angepasst wird, können beim Looping Audioartefakte auftreten. Die Problemumgehung dafür besteht darin, die Anfangs- und Endframeblöcke bei der Schleife zu überblenden und die gesamte Pufferung selbst zu verarbeiten, aber Sie müssten Code schreiben, um dies selbst zu tun.