首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将原始PCM数据转换为RIFF

将原始PCM数据转换为RIFF
EN

Stack Overflow用户
提问于 2017-12-19 04:12:30
回答 1查看 1.3K关注 0票数 2

我试图将原始音频数据从一种格式转换为另一种格式,以便进行语音识别。

  • 音频是从不和谐服务器以20ms块以48Khz, 16-bit stereo signed BigEndian PCM格式接收的。
  • 我使用CMU狮身人面像进行语音识别,它将音频作为RIFF (little-endian) WAVE audio, 16-bit, mono 16,000Hz中的一个InputStream

音频数据在长度为byte[]3840中接收。此byte[]数组包含上述格式1的音频的20ms。这意味着1秒的音频是3840 * 50,也就是192,000。这就是每秒的192,000样本。这是合理的,48KHz采样率,乘以2 (96K样本),因为一个字节是8位,我们的音频是16位,另外两倍的立体声。所以48,000 * 2 * 2 = 192,000

因此,每次收到音频数据包时,我首先调用此方法:

代码语言:javascript
复制
private void addToPacket(byte[] toAdd) {
    if(packet.length >= 576000 && !done) {
        System.out.println("Processing needs to occur...");
        getResult(convertAudio());
        packet = null; // reset the packet
        return;
    }

    byte[] newPacket = new byte[packet.length + 3840];
    // copy old packet onto new temp array
    System.arraycopy(packet, 0, newPacket, 0, packet.length);
    // copy toAdd packet onto new temp array
    System.arraycopy(toAdd, 0, newPacket, 3840, toAdd.length);
    // overwrite the old packet with the newly resized packet
    packet = newPacket;
}

这只会将新的数据包添加到一个大的byte[]上,直到byte[]包含3秒的音频数据(576,000个样本,或192000 * 3)。3秒的音频数据是足够的时间(只是猜测),以检测用户是否说机器人的激活热门词,如“嘿嘿计算机”。下面是我如何转换声音数据:

代码语言:javascript
复制
    private byte[] convertAudio() {
        // STEP 1 - DROP EVERY OTHER PACKET TO REMOVE STEREO FROM THE AUDIO
        byte[] mono = new byte[96000];
        for(int i = 0, j = 0; i % 2 == 0 && i < packet.length; i++, j++) {
            mono[j] = packet[i];
        }

        // STEP 2 - DROP EVERY 3RD PACKET TO CONVERT TO 16K HZ Audio
        byte[] resampled = new byte[32000];
        for(int i = 0, j = 0; i % 3 == 0 && i < mono.length; i++, j++) {
            resampled[j] = mono[i];
        }

        // STEP 3 - CONVERT TO LITTLE ENDIAN
        ByteBuffer buffer = ByteBuffer.allocate(resampled.length);
        buffer.order(ByteOrder.BIG_ENDIAN);
        for(byte b : resampled) {
            buffer.put(b);
        }
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        buffer.rewind();
        for(int i = 0; i < resampled.length; i++) {
            resampled[i] = buffer.get(i);
        }

        return resampled;
    }

最后,试着承认这句话:

代码语言:javascript
复制
private void getResult(byte[] toProcess) {
    InputStream stream = new ByteArrayInputStream(toProcess);
    recognizer.startRecognition(stream);
    SpeechResult result;
    while ((result = recognizer.getResult()) != null) {
        System.out.format("Hypothesis: %s\n", result.getHypothesis());
    }
    recognizer.stopRecognition();
}

我遇到的问题是,CMUSphinx没有崩溃,也没有提供任何错误信息,它只是每3秒提出一个空假设。我不太清楚为什么,但我的猜测是我没有正确地转换声音。有什么想法吗?任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-24 05:34:08

因此,实际上有一个更好的内部解决方案,用于从byte[]转换音频。

下面是我发现的效果很好的东西:

代码语言:javascript
复制
        // Specify the output format you want
        AudioFormat target = new AudioFormat(16000f, 16, 1, true, false);
        // Get the audio stream ready, and pass in the raw byte[]
        AudioInputStream is = AudioSystem.getAudioInputStream(target, new AudioInputStream(new ByteArrayInputStream(raw), AudioReceiveHandler.OUTPUT_FORMAT, raw.length));
        // Write a temporary file to the computer somewhere, this method will return a InputStream that can be used for recognition
        try {
            AudioSystem.write(is, AudioFileFormat.Type.WAVE, new File("C:\\filename.wav"));
        } catch(Exception e) {}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47879925

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档