Audacity 打开的 Opus 音频文件怎么会有剪辑?

问题描述 投票:0回答:1

我正在使用命令行编码器 opusenc 1.4 将 32 位浮点 Wave (

.wav
) 文件编码为 Opus。

所有 Wave 文件都没有剪辑(= 包含 -1.0 .. +1.0 范围之外的音频样本),但是:

  • 如果我在 Audacity 中打开由命令行编码器生成的

    .opus
    文件,会发现少数个别音频样本的实例低于 -1.0 或高于 +1.0。

  • 如果我通过 opusdec 1.4 解码

    .opus
    文件或通过 C++ 中的
    libopusfile
    读取它,则音频数据中不存在剪辑。

我将我的代码与Audacity的代码(https://github.com/audacity/audacity/blob/5b9d78bc9ecda8dcb84669541c268cce90b06848/modules/mod-opus/ImportOpus.cpp#L193)进行了比较,两者都使用

::op_read_float()

Audacity 有何不同之处?通过拖放到 Audacity 窗口中打开的

.opus
文件如何包含少量剪辑样本,而 opusdec 和我自己的代码却无法复制相同的剪辑样本?

audio encoding opus audacity
1个回答
0
投票

我发现,如果我使用系统提供的

libopus
/
libopusfile
,即使在 Audacity 之外也会出现剪切问题。

因此,官方

opusdec
可执行文件、我的
libopus
/
libopusfile
调试版本和我系统上所述库的 riced 版本之间的解码似乎存在细微差别(编译标志包括
-march=native -Ofast -pipe -fomit-frame-pointer -g0 -fgraphite-identity -fno-common -flto=13 -fmerge-all-constants -falign-functions=32 -fno-stack-protector -floop-strip-mine -floop-block -ftree-vectorize -floop-interchange -floop-nest-optimize -floop-parallelize-all -fstack-check=no -fno-stack-check -fno-stack-clash-protection
) .

以下 C++ 片段与我的系统的

libopus
链接时,确实重现了我在 Audacity 中看到的剪辑:

// Uses a class from the 'AudioFile' library to store audio data
// https://github.com/adamstark/AudioFile
std::unique_ptr<AudioFile<float>> loadOpusFile(const std::string &opusFilePath) {
  std::unique_ptr<AudioFile<float>> audioFile = std::make_unique<AudioFile<float>>();

  ::OggOpusFile *opusFile = ::op_open_file(opusFilePath.c_str(), nullptr);

  std::size_t channelCount = ::op_channel_count(opusFile, -1);
  //std::size_t sampleRate = ::op_head(opusFile, -1)->input_sample_rate;

  // Docs: "The <tt>libopusfile</tt> API always decodes files to 48&nbsp;kHz.
  // The original sample rate is not preserved by the lossy compression, ..."
  audioFile->setSampleRate(48000);

  //audioFile->setNumChannels(channelCount);

  std::vector<std::vector<float>> channels;
  channels.resize(channelCount);

  // Docs: "It is recommended that this be large enough for at least 120 ms
  // of data at 48 kHz per channel (5760 samples per channel)"
  std::vector<float> sampleBuffer;
  sampleBuffer.resize(channelCount * 6144);

  //::op_pcm_t pcm;
  for(;;) {

    // Docs: "he channel count cannot be known a priori (reading more samples might
    // advance us into the next link, with a different channel count)"
    int sampleCountPerChannel = ::op_read_float(
      opusFile, sampleBuffer.data(), sampleBuffer.size(), nullptr
    );
    if(sampleCountPerChannel == 0) {
      break;
    }
    if(sampleCountPerChannel < 0) {
      ::op_free(opusFile);
      throw std::runtime_error(u8"Error reading/decoding OPUS file");
    }

    const ::OpusHead *header = ::op_head(opusFile, -1);
    std::size_t currentChannelCount = header->channel_count;
    if(currentChannelCount != channelCount) {
      ::op_free(opusFile);
      throw std::runtime_error(u8"Channel count changes in the middle of OPUS file");
    }

    // Docs: "Multiple channels are interleaved using the
    // <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
    // channel ordering</a>."
    float *currentSample = sampleBuffer.data();
    for(int sampleIndex = 0; sampleIndex < sampleCountPerChannel; ++sampleIndex) {
      for(int channelIndex = 0; channelIndex < channelCount; ++channelIndex) {
        channels[channelIndex].push_back(*currentSample);
        ++currentSample;
      }
    }
  }

  // Clean up
  ::op_free(opusFile);  

  // No move assignment? But new buffer also needs to be non-const?
  // It would probably be much more efficient to call setAudioBufferSize()
  // and fill the decoded samples directly into the audio buffer.
  audioFile->setAudioBuffer(channels);

  return audioFile;
}
© www.soinside.com 2019 - 2024. All rights reserved.