Skip to content

Commit

Permalink
Clean up sound handling
Browse files Browse the repository at this point in the history
  • Loading branch information
SupSuper committed Oct 13, 2018
1 parent a4d28b7 commit 7d9cd99
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 36 deletions.
21 changes: 11 additions & 10 deletions src/Engine/Game.cpp
Expand Up @@ -624,18 +624,19 @@ void Game::defaultLanguage()
*/
void Game::initAudio()
{
Uint16 format;
Uint16 format = MIX_DEFAULT_FORMAT;
if (Options::audioBitDepth == 8)
format = AUDIO_S8;
else
format = AUDIO_S16SYS;
if (Options::audioSampleRate >= 44100)
Options::audioChunkSize = std::max(2048, Options::audioChunkSize);
else if (Options::audioSampleRate >= 22050)
Options::audioChunkSize = std::max(1024, Options::audioChunkSize);
else if (Options::audioSampleRate >= 11025)
Options::audioChunkSize = std::max(512, Options::audioChunkSize);
if (Mix_OpenAudio(Options::audioSampleRate, format, 2, Options::audioChunkSize) != 0)

if (Options::audioSampleRate % 11025 != 0)
{
Log(LOG_WARNING) << "Custom sample rate " << Options::audioSampleRate << "Hz, audio that doesn't match will be distorted!";
Log(LOG_WARNING) << "SDL_mixer only supports multiples of 11025Hz.";
}
int minChunk = Options::audioSampleRate / 11025 * 512;
Options::audioChunkSize = std::max(minChunk, Options::audioChunkSize);

if (Mix_OpenAudio(Options::audioSampleRate, format, MIX_DEFAULT_CHANNELS, Options::audioChunkSize) != 0)
{
Log(LOG_ERROR) << Mix_GetError();
Log(LOG_WARNING) << "No sound device detected, audio disabled.";
Expand Down
61 changes: 35 additions & 26 deletions src/Engine/SoundSet.cpp
Expand Up @@ -43,6 +43,24 @@ SoundSet::~SoundSet()
}
}

/**
* Converts a 8Khz sample to 11Khz.
* @param oldsound Pointer to original sample buffer.
* @param oldsize Original buffer size.
* @param newsound Pointer to converted sample buffer.
* @return Converted buffer size.
*/
int SoundSet::convertSampleRate(Uint8 *oldsound, unsigned int oldsize, Uint8 *newsound) const
{
const Uint32 step16 = (8000 << 16) / 11025;
int newsize = 0;
for (Uint32 offset16 = 0; (offset16 >> 16) < oldsize; offset16 += step16, ++newsound, ++newsize)
{
*newsound = oldsound[offset16 >> 16];
}
return newsize;
}

/**
* Loads the contents of an X-Com CAT file which usually contains
* a set of sound files. The CAT starts with an index of the offset
Expand All @@ -69,57 +87,48 @@ void SoundSet::loadCat(const std::string &filename, bool wav)
unsigned int size = sndFile.getObjectSize(i);

// If there's no WAV header (44 bytes), add it
// Assuming sounds are 8-bit 8000Hz (DOS version)
// Assuming sounds are 6-bit 8000Hz (DOS version)
unsigned char *newsound = 0;
const int headerSize = 44;
if (!wav)
{
if (size > 5) size -= 5; // skip 5 garbage name bytes at beginning
if (size) size--; // omit trailing null byte
if (size != 0)
{
char header[] = {'R', 'I', 'F', 'F', 0x00, 0x00, 0x00, 0x00, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x2b, 0x00, 0x00, 0x11, 0x2b, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00,
'd', 'a', 't', 'a', 0x00, 0x00, 0x00, 0x00};

for (unsigned int n = 0; n < size; ++n) sound[n] *= 4; // scale to 8 bits
if (size > 5) size -= 5; // skip 5 garbage name bytes at beginning
if (size) size--; // omit trailing null byte

newsound = new unsigned char[44 + size*2];
memcpy(newsound, header, 44);
if (size) memcpy(newsound + 44, sound+5, size);
Uint32 step16 = (8000<<16)/11025;
Uint8 *w = newsound+44;
int newsize = 0;
for (Uint32 offset16 = 0; (offset16>>16) < size; offset16 += step16, ++w, ++newsize)
{
*w = sound[5 + (offset16>>16)];
}
size = newsize + 44;
// scale to 8 bits
for (unsigned int n = 0; n < size; ++n) sound[5 + n] *= 4;

// copy and do the conversion...
newsound = new unsigned char[headerSize + size*2];
memcpy(newsound, header, headerSize);
memcpy(newsound + headerSize, sound + 5, size);
int newsize = convertSampleRate(sound + 5, size, newsound + headerSize);
size = newsize + headerSize;

// Rewrite the number of samples in the WAV file
int headersize = newsize + 36;
int soundsize = newsize;
memcpy(newsound + 4, &headersize, sizeof(headersize));
memcpy(newsound + 40, &soundsize, sizeof(soundsize));
}
}
// so it's WAV, but in 8 khz, we have to convert it to 11 khz sound
else if (0x40 == sound[0x18] && 0x1F == sound[0x19] && 0x00 == sound[0x1A] && 0x00 == sound[0x1B])
{
// so it's WAV, but in 8 khz, we have to convert it to 11 khz sound

unsigned char *sound2 = new unsigned char[size*2];

// rewrite the samplerate in the header to 11 khz
sound[0x18]=0x11; sound[0x19]=0x2B; sound[0x1C]=0x11; sound[0x1D]=0x2B;

// copy and do the conversion...
memcpy(sound2, sound, size);
Uint32 step16 = (8000<<16)/11025;
Uint8 *w = sound2+44;
int newsize = 0;
for (Uint32 offset16 = 0; (offset16>>16) < size-44; offset16 += step16, ++w, ++newsize)
{
*w = sound[44 + (offset16>>16)];
}
size = newsize + 44;
int newsize = convertSampleRate(sound + headerSize, size - headerSize, sound2 + headerSize);
size = newsize + headerSize;

// Rewrite the number of samples in the WAV file
memcpy(sound2 + 0x28, &newsize, sizeof(newsize));
Expand Down
3 changes: 3 additions & 0 deletions src/Engine/SoundSet.h
Expand Up @@ -17,6 +17,7 @@
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
*/
#include <SDL_mixer.h>
#include <map>
#include <string>

Expand All @@ -34,6 +35,8 @@ class SoundSet
{
private:
std::map<int, Sound*> _sounds;

int convertSampleRate(Uint8 *oldsound, unsigned int oldsize, Uint8 *newsound) const;
public:
/// Crates a sound set.
SoundSet();
Expand Down

0 comments on commit 7d9cd99

Please sign in to comment.