static boolean ExpandSoundData_SRC(sfxinfo_t *sfxinfo, byte *data, int samplerate, int length) { SRC_DATA src_data; uint32_t i, abuf_index=0, clipped=0; uint32_t alen; int retn; int16_t *expanded; Mix_Chunk *chunk; src_data.input_frames = length; src_data.data_in = malloc(length * sizeof(float)); src_data.src_ratio = (double)mixer_freq / samplerate; // We include some extra space here in case of rounding-up. src_data.output_frames = src_data.src_ratio * length + (mixer_freq / 4); src_data.data_out = malloc(src_data.output_frames * sizeof(float)); assert(src_data.data_in != NULL && src_data.data_out != NULL); // Convert input data to floats for (i=0; i<length; ++i) { // Unclear whether 128 should be interpreted as "zero" or whether a // symmetrical range should be assumed. The following assumes a // symmetrical range. src_data.data_in[i] = data[i] / 127.5 - 1; } // Do the sound conversion retn = src_simple(&src_data, SRC_ConversionMode(), 1); assert(retn == 0); // Allocate the new chunk. alen = src_data.output_frames_gen * 4; chunk = AllocateSound(sfxinfo, src_data.output_frames_gen * 4); if (chunk == NULL) { return false; } expanded = (int16_t *) chunk->abuf; // Convert the result back into 16-bit integers. for (i=0; i<src_data.output_frames_gen; ++i) { // libsamplerate does not limit itself to the -1.0 .. 1.0 range on // output, so a multiplier less than INT16_MAX (32767) is required // to avoid overflows or clipping. However, the smaller the // multiplier, the quieter the sound effects get, and the more you // have to turn down the music to keep it in balance. // 22265 is the largest multiplier that can be used to resample all // of the Vanilla DOOM sound effects to 48 kHz without clipping // using SRC_SINC_BEST_QUALITY. It is close enough (only slightly // too conservative) for SRC_SINC_MEDIUM_QUALITY and // SRC_SINC_FASTEST. PWADs with interestingly different sound // effects or target rates other than 48 kHz might still result in // clipping--I don't know if there's a limit to it. // As the number of clipped samples increases, the signal is // gradually overtaken by noise, with the loudest parts going first. // However, a moderate amount of clipping is often tolerated in the // quest for the loudest possible sound overall. The results of // using INT16_MAX as the multiplier are not all that bad, but // artifacts are noticeable during the loudest parts. float cvtval_f = src_data.data_out[i] * libsamplerate_scale * INT16_MAX; int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5); // Asymmetrical sound worries me, so we won't use -32768. if (cvtval_i < -INT16_MAX) { cvtval_i = -INT16_MAX; ++clipped; } else if (cvtval_i > INT16_MAX) { cvtval_i = INT16_MAX; ++clipped; } // Left and right channels expanded[abuf_index++] = cvtval_i; expanded[abuf_index++] = cvtval_i; } free(src_data.data_in); free(src_data.data_out); if (clipped > 0) { fprintf(stderr, "Sound '%s': clipped %u samples (%0.2f %%)\n", sfxinfo->name, clipped, 400.0 * clipped / chunk->alen); } return true; }
static boolean I_SDL_InitSound(boolean _use_sfx_prefix) { int i; use_sfx_prefix = _use_sfx_prefix; // No sounds yet for (i=0; i<NUM_CHANNELS; ++i) { channels_playing[i] = NULL; } if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to set up sound.\n"); return false; } if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, GetSliceSize()) < 0) { fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); return false; } ExpandSoundData = ExpandSoundData_SDL; Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels); #ifdef HAVE_LIBSAMPLERATE if (use_libsamplerate != 0) { if (SRC_ConversionMode() < 0) { I_Error("I_SDL_InitSound: Invalid value for use_libsamplerate: %i", use_libsamplerate); } ExpandSoundData = ExpandSoundData_SRC; } #else if (use_libsamplerate != 0) { fprintf(stderr, "I_SDL_InitSound: use_libsamplerate=%i, but " "libsamplerate support not compiled in.\n", use_libsamplerate); } #endif // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning // function that can cause the game to lock up. If we're using an old // version, we need to apply a workaround. But the workaround has its // own drawbacks ... { const SDL_version *mixer_version; int v; mixer_version = Mix_Linked_Version(); v = SDL_VERSIONNUM(mixer_version->major, mixer_version->minor, mixer_version->patch); if (v <= SDL_VERSIONNUM(1, 2, 8)) { setpanning_workaround = true; fprintf(stderr, "\n" "ATTENTION: You are using an old version of SDL_mixer!\n" " This version has a bug that may cause " "your sound to stutter.\n" " Please upgrade to a newer version!\n" "\n"); } } Mix_AllocateChannels(NUM_CHANNELS); SDL_PauseAudio(0); sound_initialized = true; return true; }
static boolean I_SDL_InitSound(boolean _use_sfx_prefix) { int i; // SDL 2.0.6 has a bug that makes it unusable. if (SDL_COMPILEDVERSION == SDL_VERSIONNUM(2, 0, 6)) { I_Error( "I_SDL_InitSound: " "You are trying to launch with SDL 2.0.6 which has a known bug " "that makes the game crash. Please either downgrade to " "SDL 2.0.5 or upgrade to 2.0.7. See the following bug for some " "additional context:\n" "<https://github.com/chocolate-doom/chocolate-doom/issues/945>"); } use_sfx_prefix = _use_sfx_prefix; // No sounds yet for (i=0; i<NUM_CHANNELS; ++i) { channels_playing[i] = NULL; } if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to set up sound.\n"); return false; } if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, GetSliceSize()) < 0) { fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError()); return false; } ExpandSoundData = ExpandSoundData_SDL; Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels); #ifdef HAVE_LIBSAMPLERATE if (use_libsamplerate != 0) { if (SRC_ConversionMode() < 0) { I_Error("I_SDL_InitSound: Invalid value for use_libsamplerate: %i", use_libsamplerate); } ExpandSoundData = ExpandSoundData_SRC; } #else if (use_libsamplerate != 0) { fprintf(stderr, "I_SDL_InitSound: use_libsamplerate=%i, but " "libsamplerate support not compiled in.\n", use_libsamplerate); } #endif Mix_AllocateChannels(NUM_CHANNELS); SDL_PauseAudio(0); sound_initialized = true; return true; }