2011-10-01 133 views
5

我正在開發一個Android程序,需要以非常準確的時序(音樂程序)重複播放音頻文件。AudioTrack將只播放音頻一次

我現在使用的是「AudioTrack」,它具有從WAV樣本中加載的PCM數據。

這裏是我測試這個功能的代碼。它只是循環播放樣本,然後播放它,然後重複播放8次。

下面是我用的,讓我知道如果你需要看到更多的代碼:

class Sequencer { 
    private final double BPM = 120; 
    private final double BPMS = (BPM/60/1000); 
    private long QUARTER_NOTE_DELAY = (long)(1/BPMS); 

    private final int PCM_BYTE_OFFSET = 44; 

    private long lastTick; 
    private long now = 0; 

    private int sampleRate = 8000; 
    private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO; 
    private int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 
    private int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat)*5; 

    private AudioTrack playbackBuffer = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRate, 
      channelConfig,audioFormat,bufferSize,AudioTrack.MODE_STATIC);; 

    private byte[] pcmArray; 

    public Sequencer() 
    { 
     Log.d("AudioTrack", "BUFFER SIZE: " +bufferSize); 

     String path = "samples/classical_guitar_c5_16bit.wav"; 
     try { 
      pcmArray = parsePCMData(path); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      Log.e("Error Initializng Sequencer", "File not Found: " + path); 
      e.printStackTrace(); 
     } 


    } 

    public void play() { 
     new Thread() { 
      public void run() { 

       lastTick = 0; 
       // play 10 times 
       Log.d("Sequencer", "QUARTER-NOTE = " + QUARTER_NOTE_DELAY + "ms"); 
       for (int i = 0; i < 8; i++) 
       { 
        lastTick = System.currentTimeMillis(); 
        while (!update(i)); 
       } 

       playbackBuffer.flush(); 

      } 
     }.start(); 

    } 

    public void stop() { 

    } 

    //load PCM data into the buffer 
    private void loadPCMData(byte[] pcmData) 
    { 
     int numBytesWritten = playbackBuffer.write(pcmData, PCM_BYTE_OFFSET, (pcmData.length-PCM_BYTE_OFFSET)); 
     Log.d("AudioTrack", "LOADED " + numBytesWritten + " BYTES" + " IN " + (System.currentTimeMillis()- now) + "ms!"); 
    } 

    private byte[] parsePCMData(String path) throws IOException 
    { 
     InputStream fileIn = assetManager.open(path); 
     BufferedInputStream buffIn = new BufferedInputStream(fileIn, 8000); 
     DataInputStream dataIn = new DataInputStream(buffIn); 
     byte[] pcmArray; 
     ArrayList<Byte> pcmVector = new ArrayList<Byte>(); 
     int numBytes; 

     //Read the file into the "music" array 
     for(int i=0; dataIn.available() > 0; i++) 
     { 
      pcmVector.add(dataIn.readByte()); 
     } 
     //Close the input streams 
     dataIn.close();               
     buffIn.close(); 
     fileIn.close(); 
     numBytes = pcmVector.size(); 
     pcmArray = new byte[numBytes]; 

     //Copy the data from the arrayLast to the byte array 
     for(int i=0; i<numBytes; i++) 
     { 
      pcmArray[i] = (Byte) pcmVector.get(i); 
     } 

     return pcmArray; 
    } 

    //Start Playback of PCM data 
    private void startPlayback() 
    { 
     //stop playback 
     if(playbackBuffer.getState() != AudioTrack.STATE_NO_STATIC_DATA) 
     { 
      playbackBuffer.stop(); 
      playbackBuffer.flush(); 
     } 

     //start loading the next batch of sounds 
     loadPCMData(pcmArray); 

     //reset head position 
     playbackBuffer.setPlaybackHeadPosition(0); 
     //playbacksounds 
     playbackBuffer.play(); 
    } 

    private boolean update(int i) { 

     now = System.currentTimeMillis(); 

     if (now - lastTick >= QUARTER_NOTE_DELAY) { 
      //start Sounds 
      Log.d("AudioTrack: ", "Starting Playback. Current State: " + Integer.toString(playbackBuffer.getState())); 
      startPlayback(); 
      Log.d("AudioTrack: ", "Playback Started. Current State: " + Integer.toString(playbackBuffer.getState())); 
      Log.d("MainMenu.java: ", "Event Triggered after " + Long.toString(now-lastTick) +"ms"); 
      lastTick = now; 
      //update UI in a seperate thread 
      beatCounter.post(updateUI); 
      return true; 
     } 

     else{ 
      return false; 
     } 
    } 

} 

它發揮完美第一八環,但後面還有就是沉默,不可見的錯誤或警告。 (雖然狀態將保持在1,即「STATE_INITIALIZED」,意思是「可以使用的音頻軌道狀態」

我知道AudioTrack具有循環功能以及「reloadStaticData」方法,但是當我開始編寫實際的應用程序時,我正在測試這個數據會根據用戶生成的序列每次更改)

此外,我最初嘗試使用mediaplayer和soundpool這樣做,但都給了我太多延遲。

作爲一個測試,我也嘗試了重新初始化AudioTrack完全每一個循環,但是這給我太多的延遲是非常有用的。

我爲這個亂七八糟的代碼表示歉意,我真的很希望它只是一些愚蠢的錯誤,因爲我變得非常沮喪。

謝謝!在Android 2.2.2

測試,手持設備(而非模擬的)

這裏的是我的logcat輸出:

10-01 05:07:22.016: DEBUG/AndroidRuntime(23316): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<< 
10-01 05:07:22.016: DEBUG/AndroidRuntime(23316): CheckJNI is OFF 
10-01 05:07:22.016: DEBUG/dalvikvm(23316): creating instr width table 
10-01 05:07:22.094: DEBUG/AndroidRuntime(23316): --- registering native functions --- 
10-01 05:07:22.461: DEBUG/dalvikvm(22329): GC_EXPLICIT freed 236 objects/13984 bytes in 39ms 
10-01 05:07:23.547: DEBUG/PackageParser(1089): Scanning package: /data/app/vmdl67886.tmp 
10-01 05:07:23.680: DEBUG/KeyguardViewMediator(1089): wakeWhenReadyLocked(26) 
10-01 05:07:23.680: DEBUG/KeyguardViewMediator(1089): handleWakeWhenReady(26) 
10-01 05:07:23.680: DEBUG/KeyguardViewMediator(1089): pokeWakelock(5000) 
10-01 05:07:23.680: INFO/power(1089): *** set_screen_state 1 
10-01 05:07:23.696: DEBUG/Sensors(1089): using sensors (name=sensors) 
10-01 05:07:24.088: INFO/PackageManager(1089): Removing non-system package:com.android.test 
10-01 05:07:24.088: INFO/Process(1089): Sending signal. PID: 23293 SIG: 9 
10-01 05:07:24.088: INFO/ActivityManager(1089): Force stopping package com.android.test uid=10081 
10-01 05:07:24.102: INFO/WindowManager(1089): WIN DEATH: Window{44b41118 com.android.test/com.android.test.MainMenu paused=false} 
10-01 05:07:24.118: INFO/UsageStats(1089): Unexpected resume of com.android.launcher while already resumed in com.android.test 
10-01 05:07:24.196: DEBUG/SurfaceFlinger(1089): Screen about to return, flinger = 0x120f38 
10-01 05:07:24.446: DEBUG/PackageManager(1089): Scanning package com.android.test 
10-01 05:07:24.446: INFO/PackageManager(1089): Package com.android.test codePath changed from /data/app/com.android.test-2.apk to /data/app/com.android.test-1.apk; Retaining data and using new 
10-01 05:07:24.453: INFO/PackageManager(1089): /data/app/com.android.test-1.apk changed; unpacking 
10-01 05:07:24.453: DEBUG/installd(1012): DexInv: --- BEGIN '/data/app/com.android.test-1.apk' --- 
10-01 05:07:24.602: DEBUG/dalvikvm(23325): creating instr width table 
10-01 05:07:24.641: DEBUG/dalvikvm(23325): DexOpt: load 11ms, verify 23ms, opt 0ms 
10-01 05:07:24.649: DEBUG/installd(1012): DexInv: --- END '/data/app/com.android.test-1.apk' (success) --- 
10-01 05:07:24.657: DEBUG/PackageManager(1089): Activities: com.android.test.AndroidTestActivity com.android.test.MainMenu 
10-01 05:07:24.657: INFO/ActivityManager(1089): Force stopping package com.android.test uid=10081 
10-01 05:07:24.657: WARN/PackageManager(1089): Code path for pkg : com.android.test changing from /data/app/com.android.test-2.apk to /data/app/com.android.test-1.apk 
10-01 05:07:24.657: WARN/PackageManager(1089): Resource path for pkg : com.android.test changing from /data/app/com.android.test-2.apk to /data/app/com.android.test-1.apk 
10-01 05:07:24.829: INFO/installd(1012): move /data/dalvik-cache/[email protected]@[email protected] -> /data/dalvik-cache/[email protected]@[email protected] 
10-01 05:07:24.829: DEBUG/PackageManager(1089): New package installed in /data/app/com.android.test-1.apk 
10-01 05:07:24.868: DEBUG/KeyguardViewMediator(1089): pokeWakelock(5000) 
10-01 05:07:25.000: DEBUG/KeyguardViewMediator(1089): pokeWakelock(5000) 
10-01 05:07:25.211: WARN/InputManagerService(1089): Got RemoteException sending setActive(false) notification to pid 23293 uid 10081 
10-01 05:07:25.274: INFO/ActivityManager(1089): Force stopping package com.android.test uid=10081 
10-01 05:07:25.571: DEBUG/dalvikvm(1089): GC_EXPLICIT freed 24967 objects/1341840 bytes in 159ms 
10-01 05:07:25.672: DEBUG/VoiceDialerReceiver(22354): onReceive Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.android.test flg=0x10000000 cmp=com.android.voicedialer/.VoiceDialerReceiver (has extras) } 
10-01 05:07:25.977: DEBUG/dalvikvm(1089): GC_EXPLICIT freed 6005 objects/330448 bytes in 141ms 
10-01 05:07:26.016: DEBUG/VoiceDialerReceiver(22354): onReceive Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.android.test flg=0x10000000 cmp=com.android.voicedialer/.VoiceDialerReceiver (has extras) } 
10-01 05:07:26.250: INFO/installd(1012): unlink /data/dalvik-cache/[email protected]@[email protected] 
10-01 05:07:26.258: DEBUG/AndroidRuntime(23316): Shutting down VM 
10-01 05:07:26.266: DEBUG/dalvikvm(23316): Debugger has detached; object registry had 1 entries 
10-01 05:07:26.282: INFO/AndroidRuntime(23316): NOTE: attach of thread 'Binder Thread #3' failed 
10-01 05:07:26.680: DEBUG/AndroidRuntime(23330): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<< 
10-01 05:07:26.680: DEBUG/AndroidRuntime(23330): CheckJNI is OFF 
10-01 05:07:26.680: DEBUG/dalvikvm(23330): creating instr width table 
10-01 05:07:26.735: DEBUG/AndroidRuntime(23330): --- registering native functions --- 
10-01 05:07:27.047: INFO/ActivityManager(1089): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.test/.AndroidTestActivity } 
10-01 05:07:27.110: DEBUG/AndroidRuntime(23330): Shutting down VM 
10-01 05:07:27.110: DEBUG/dalvikvm(23330): Debugger has detached; object registry had 1 entries 
10-01 05:07:27.110: INFO/ActivityManager(1089): Start proc com.android.test for activity com.android.test/.AndroidTestActivity: pid=23337 uid=10081 gids={} 
10-01 05:07:27.125: INFO/AndroidRuntime(23330): NOTE: attach of thread 'Binder Thread #3' failed 
10-01 05:07:27.203: INFO/WindowManager(1089): Setting rotation to 1, animFlags=1 
10-01 05:07:27.227: INFO/ActivityManager(1089): Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=2/1/2 nav=2/2 orien=2 layout=34 uiMode=17 seq=554} 
10-01 05:07:27.613: INFO/ActivityManager(1089): Displayed activity com.android.test/.AndroidTestActivity: 513 ms (total 513 ms) 
10-01 05:07:27.657: WARN/IInputConnectionWrapper(17894): showStatusIcon on inactive InputConnection 
10-01 05:07:28.073: INFO/ActivityManager(1089): Starting activity: Intent { act=com.android.test.CLEARSPLASH cmp=com.android.test/.MainMenu } 
10-01 05:07:28.141: DEBUG/AudioTrack(23337): BUFFER SIZE: 14860 
10-01 05:07:28.571: INFO/ActivityManager(1089): Displayed activity com.android.test/.MainMenu: 488 ms (total 488 ms) 
10-01 05:07:29.930: DEBUG/dalvikvm(1089): GC_EXPLICIT freed 3588 objects/165776 bytes in 182ms 
10-01 05:07:40.172: DEBUG/Sequencer(23337): QUARTER-NOTE = 500ms 
10-01 05:07:40.680: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 2 
10-01 05:07:40.680: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:40.688: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:40.688: DEBUG/MainMenu.java:(23337): Event Triggered after 502ms 
10-01 05:07:41.203: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:41.203: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:41.203: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:41.203: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:41.711: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:41.711: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:41.719: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:41.719: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:42.227: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:42.235: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:42.235: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:42.235: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:42.743: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:42.743: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:42.750: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:42.750: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:43.258: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:43.258: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:43.258: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:43.258: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:43.774: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:43.774: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms! 
10-01 05:07:43.782: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:43.782: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:44.289: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1 
10-01 05:07:44.297: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 2ms! 
10-01 05:07:44.305: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1 
10-01 05:07:44.305: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms 
10-01 05:07:44.344: DEBUG/dalvikvm(22433): GC_EXPLICIT freed 827 objects/40752 bytes in 67ms 
10-01 05:07:49.422: DEBUG/dalvikvm(20018): GC_EXPLICIT freed 596 objects/30440 bytes in 67ms 
10-01 05:07:54.563: DEBUG/dalvikvm(22329): GC_EXPLICIT freed 143 objects/10072 bytes in 80ms 
10-01 05:07:59.696: DEBUG/dalvikvm(22354): GC_EXPLICIT freed 547 objects/30048 bytes in 68ms 
10-01 05:08:09.977: DEBUG/dalvikvm(22363): GC_EXPLICIT freed 483 objects/22512 bytes in 111ms 
10-01 05:08:10.219: INFO/power(1089): *** set_screen_state 0 
10-01 05:08:10.237: DEBUG/SurfaceFlinger(1089): About to give-up screen, flinger = 0x120f38 
10-01 05:08:10.258: DEBUG/Sensors(1089): using accelerometer (name=accelerometer) 
10-01 05:08:15.430: DEBUG/StatusBar(1089): DISABLE_EXPAND: yes 
10-01 05:08:15.469: DEBUG/GoogleLoginService(16965): onBind: Intent { act=android.accounts.AccountAuthenticator cmp=com.google.android.gsf/.loginservice.GoogleLoginService } 
10-01 05:08:15.469: INFO/WindowManager(1089): Setting rotation to 0, animFlags=1 
10-01 05:08:15.493: INFO/ActivityManager(1089): Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=2/1/2 nav=2/2 orien=1 layout=34 uiMode=17 seq=555} 
10-01 05:08:15.821: DEBUG/dalvikvm(23337): GC_FOR_MALLOC freed 1766 objects/427920 bytes in 193ms 
10-01 05:08:15.899: DEBUG/AudioTrack(23337): BUFFER SIZE: 14860 
+0

爲什麼你循環8次?檢查這一行:'for(int i = 0; i <8; i ++)' – iTurki

回答

1

也許你應該嘗試使用AudioTrack的streamming模式,而不是一個靜態的。