AudioTrack只播放一次音频

时间:2011-10-01 09:17:03

标签: java android audio

我正在制作一个Android程序,需要以非常准确的时间(音乐程序)重复播放音频文件。

我正在使用“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的状态。”

我知道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/data@app@com.android.test-1.apk@classes.dex -> /data/dalvik-cache/data@app@com.android.test-1.apk@classes.dex
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/data@app@com.android.test-2.apk@classes.dex
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

1 个答案:

答案 0 :(得分:1)

也许您应该尝试使用AudioTrack的流式模式而不是静态模式。

相关问题