简体   繁体   中英

How can I decompress an OGG sound file using FMOD?

Is there a way to decompress sound files using the FMOD library in c++?

I'm developing a sound editor, using the FMOD Engine library, but I got to the problem with compressed audio files, specifically OGG types.

For now I'm just reading the raw data using FMOD::Sound::readData() , and then normalize it and display it to the screen using SFML. This works fine with WAV files, because they are not compressed, but I need to do more steps for compressed formats.

This is what I'm doing now:

  FMOD_RESULT r;

  FMOD::System* m_fmodSystem = nullptr;
  int m_maxChannels = 64;
  
  // Create fmod system
  r = FMOD::System_Create(&m_fmodSystem);
  FMOD_ERROR_CHECK(r);
  
  // Initialize system
  r = m_fmodSystem->init(m_maxChannels, FMOD_INIT_NORMAL, nullptr);
  FMOD_ERROR_CHECK(r);
  
  // Create sound
  FMOD::Sound* soundResource = nullptr;
  FMOD::Channel* channel = nullptr;
  r = m_fmodSystem->createSound("640709__chobesha__laser-gun-sound.ogg",
                                FMOD_DEFAULT | FMOD_OPENONLY,
                                nullptr,
                                &soundResource);
  FMOD_ERROR_CHECK(r);
  


  // Get sound length in raw bytes
  unsigned int audioLength = 0;
  FMOD_TIMEUNIT timeUnit = FMOD_TIMEUNIT_RAWBYTES;
  r = soundResource->getLength(&audioLength, timeUnit);
  FMOD_ERROR_CHECK(r);
  
  // Read sound data
  char* audioBuffer = new char[audioLength];
  unsigned int readData = 0;
  r = soundResource->readData(reinterpret_cast<void*>(audioBuffer),
                              audioLength,
                              &readData);
  FMOD_ERROR_CHECK(r);



  signed short* interpretedData = reinterpret_cast<signed short*>(audioBuffer);

  // Analize data to normalize it
  signed short maxValue = -32767;
  signed short minValue = 32767;
  int interpretedDataSize = readData / sizeof(signed short);
  for (int i = 0; i < interpretedDataSize; ++i) {
    if (interpretedData[i] > maxValue) {
      maxValue = interpretedData[i];
    }
    if (interpretedData[i] < minValue) {
      minValue = interpretedData[i];
    }
  }
  
  float maxValF = static_cast<float>(maxValue);
  float minValF = static_cast<float>(minValue);
  float* normalizedArray = new float[interpretedDataSize];
  
  // Normalize data
  float maxAbsValF = abs(maxValF);
  maxAbsValF = maxAbsValF > abs(minValF) ? maxAbsValF : abs(minValF);
  for (int i = 0; i < interpretedDataSize; ++i) {
    normalizedArray[i] = interpretedData[i] / maxAbsValF;
  }

I read on other posts and on the FMOD documentation that I can use the flag FMOD_CREATESAMPLE to tell the createSound function to decompress the data at loadtime, instead of playtime, but It doesn't work in my current structure of the code, I'm guessing because the FMOD_OPENONLY prevents it from closing, and therefor it doesn't gets the chance to decompress, or something. That's what I got from the documentation.

The problem with not using the FMOD_OPENONLY flag, is that I cannot read the data using the readData function, or it returns an error flag.

Searching, I found that I can use the lock function, to help it decompress and to get the pointer to the data of the sound, but even with all of this, it stills appears to be compressed. I don´t know if I'm missing something.

This is the version 2 of the code, with this modifications:

  // Create sound
  FMOD::Sound* soundResource = nullptr;
  FMOD::Channel* channel = nullptr;
  r = m_fmodSystem->createSound("640709__chobesha__laser-gun-sound.ogg",
                                FMOD_DEFAULT | FMOD_CREATESAMPLE,
                                nullptr,
                                &soundResource);
  FMOD_ERROR_CHECK(r);
  


  // Get sound length in raw bytes
  unsigned int audioLength = 0;
  FMOD_TIMEUNIT timeUnit = FMOD_TIMEUNIT_RAWBYTES;
  r = soundResource->getLength(&audioLength, timeUnit);
  FMOD_ERROR_CHECK(r);
  
  // Read sound data
  char* audioBuffer = new char[audioLength];
  void* ptr2 = nullptr;
  unsigned int len1, len2;
  r = soundResource->lock(0, audioLength, reinterpret_cast<void**>(&audioBuffer), &ptr2, &len1, &len2);
  FMOD_ERROR_CHECK(r);
  r = soundResource->unlock(reinterpret_cast<void*>(audioBuffer), ptr2, len1, len2);
  FMOD_ERROR_CHECK(r);

This is the graph I get for a WAV sound

The left side is the sound loaded in the Audacity app, and the right side is my graph.

This is the graph for the first try with the OGG file

And this is the graph for the OGG file with the modifications

For what I can see, the first is the same as the second, so I'm assuming both are compressed and what I changed did nothing.

Someone knows a better way to decompress and read the raw data of a sound, preferably using this library of FMOD. If it's not possible with FMOD, what is the best way to decompress any sound file, knowing its format.

This answer is just a couple minority-position takes and a sketchy description of a process I once used. Maybe the thoughts are worth consideration.

One thought: a person who is editing sound (your target audience?) has the know-how to decompress files (eg, using Audacity), so perhaps adding this capability (handling all possible incoming audio formats) is a lower priority?

Another thought: there are likely many libraries for decompressing sound available. You could employ one of them prior to presenting the results to FMOD. I just did a search on github for "ogg c++" and was shown 51 repositories.

In my own experience, for an application I wrote about seven years ago, I tweaked some code from a Vorbis decoder source so that it output PCM rather than outputting as a .wav. With OGG, the .wav data is converted to PCM prior to compression. So, it decompresses back to PCM before converting that to a .wav. I found the point in the code where the conversion happens and edited that out, leaving the data in a decompressed PCM form.

My application was built to accept PCM, so I actually ended up saving an intermediate step.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM