Skip to content

Commit

Permalink
Fixes for multiple sounds playing at once. (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
NagyD committed Feb 7, 2021
1 parent 35ddcb4 commit ed2586e
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 17 deletions.
7 changes: 4 additions & 3 deletions doc/ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ FIXED: Fixed graphical glitches with an opening gate:
2. with the top half of a big pillar above-right.
FIXED: Validate mode crashed with the error "init_scaling: SDL_CreateTexture: Invalid renderer".
DONE: First implementation of multiple sounds playing at once. (#235)
Problems:
* The screaming of the prince doesn't stop when he lands.
* The level door sliding pops badly. It is erroneously played in multiple copies at the same time, causing the sample values to overflow.
This revealed the following cases when the game relies on sounds interrupting each other:
FIXED: The screaming of the prince doesn't stop when he lands.
FIXED: The level door sliding pops badly. It is erroneously played in multiple copies at the same time, causing the sample values to overflow.
FIXED: The level door sliding doesn't stop when the door slams.
3 changes: 2 additions & 1 deletion src/midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ void midi_callback(void *userdata, Uint8 *stream, int len) {
OPL3_GenerateStream(&opl_chip, temp_buffer, advance_frames);
if (is_sound_on && enable_music) {
for (int sample = 0; sample < advance_frames * 2; ++sample) {
((short*)stream)[sample] += temp_buffer[sample];
//((short*)stream)[sample] += temp_buffer[sample];
saturating_add_to_s16(&( ((short*)stream)[sample] ), temp_buffer[sample]);
}
}
free(temp_buffer);
Expand Down
7 changes: 7 additions & 0 deletions src/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ void show_splash();
void check_quick_op();
void restore_room_after_quick_load();
#endif // USE_QUICKSAVE
void stop_sound(int sound_id);
bool is_sound_playing(int sound_id);

// SEG001.C
int __pascal far proc_cutscene_frame(int wait_frames);
Expand Down Expand Up @@ -635,6 +637,11 @@ void set_chtab_palette(chtab_type* chtab, byte* colors, int n_colors);
int has_timer_stopped(int index);
sound_buffer_type* load_sound(int index);
void free_sound(sound_buffer_type far *buffer);
void stop_digi_from_buffer(sound_buffer_type far *buffer);
bool is_digi_playing_from_buffer(sound_buffer_type far *buffer);
Sint16 saturating_add_s16(Sint16 left, Sint16 right);
void saturating_add_to_s16(Sint16* left, Sint16 right);
int check_sound_playing_except_digi();

// SEQTABLE.C
void apply_seqtbl_patches();
Expand Down
23 changes: 18 additions & 5 deletions src/seg000.c
Original file line number Diff line number Diff line change
Expand Up @@ -1564,6 +1564,15 @@ void fix_sound_priorities() {

// seg000:12C5
void __pascal far play_sound(int sound_id) {
// For digi sounds, use the new system which allows playing multiple sounds at once.
sound_buffer_type* sound = sound_pointers[sound_id];
if (sound != NULL && sound->type == sound_digi_converted) {
// Don't let the same sound play more than once (e.g. loose floors on level 11).
if (is_sound_playing(sound_id)) return;
play_sound_from_buffer(sound);
return;
}
// For other sounds, keep using the old system.
//printf("Would play sound %d\n", sound_id);
if (next_sound < 0 || sound_prio_table[sound_id] <= sound_prio_table[next_sound]) {
if (NULL == sound_pointers[sound_id]) return;
Expand All @@ -1576,20 +1585,24 @@ void __pascal far play_sound(int sound_id) {
// seg000:1304
void __pascal far play_next_sound() {
if (next_sound >= 0) {
/*
if (!check_sound_playing() ||
if (!check_sound_playing_except_digi() ||
(sound_interruptible[current_sound] != 0 && sound_prio_table[next_sound] <= sound_prio_table[current_sound])
) {
*/
current_sound = next_sound;
play_sound_from_buffer(sound_pointers[current_sound]);
/*
}
*/
}
next_sound = -1;
}

void stop_sound(int sound_id) {
stop_digi_from_buffer(sound_pointers[sound_id]);
}

bool is_sound_playing(int sound_id) {
return is_digi_playing_from_buffer(sound_pointers[sound_id]);
}

// seg000:1353
void __pascal far check_sword_vs_sword() {
if (Kid.frame == 167 || Guard.frame == 167) {
Expand Down
3 changes: 2 additions & 1 deletion src/seg003.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ void __pascal far play_level(int level_number) {
do_startpos();
have_sword = /*(level_number != 1)*/ (level_number == 0 || level_number >= custom->have_sword_from_level);
find_start_level_door();
stop_sounds();
// busy waiting?
while (check_sound_playing() && !do_paused()) idle();
while (check_sound_playing_except_digi() && !do_paused()) idle();
stop_sounds();
#ifdef USE_REPLAY
if (replaying) replay_restore_level();
Expand Down
1 change: 1 addition & 0 deletions src/seg005.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ void __pascal far do_fall() {
// seg005:0090
void __pascal far land() {
word seq_id;
stop_sound(sound_1_falling);
is_screaming = 0;
Char.y = y_land[Char.curr_row + 1];
if (get_tile_at_char() != tiles_2_spike) {
Expand Down
3 changes: 2 additions & 1 deletion src/seg006.c
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,7 @@ void __pascal far check_grab() {
play_seq();
grab_timer = 12;
play_sound(sound_9_grab); // grab
stop_sound(sound_1_falling);
is_screaming = 0;
#ifdef FIX_CHOMPERS_NOT_STARTING
if (fixes->fix_chompers_not_starting) start_chompers();
Expand Down Expand Up @@ -1194,7 +1195,7 @@ void __pascal far play_kid() {
load_fram_det_col();
set_start_pos();
}
if (check_sound_playing() && current_sound != 5) { // gate opening
if (check_sound_playing_except_digi() && current_sound != 5) { // gate opening
return;
}
is_show_time = 0;
Expand Down
14 changes: 10 additions & 4 deletions src/seg007.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,13 +439,16 @@ Possible values of trob_type:
if ((sbyte)curr_modifier < 0) {
curr_modifier = 0;
trob.type = -1;
stop_sound(sound_15_leveldoor_sliding);
play_sound(sound_14_leveldoor_closing); // level door closing
} else {
if (trob.type == 4 &&
(sound_flags & sfDigi)
) {
sound_interruptible[sound_15_leveldoor_sliding] = 1;
play_sound(sound_15_leveldoor_sliding); // level door sliding (closing)
if (!is_sound_playing(sound_15_leveldoor_sliding)) {
play_sound(sound_15_leveldoor_sliding); // level door sliding (closing)
}
}
}
} else {
Expand All @@ -454,9 +457,10 @@ Possible values of trob_type:
if (curr_modifier >= 43) {
trob.type = -1;
#ifdef FIX_FEATHER_INTERRUPTED_BY_LEVELDOOR
if (!(fixes->fix_feather_interrupted_by_leveldoor && is_feather_fall))
//if (!(fixes->fix_feather_interrupted_by_leveldoor && is_feather_fall))
#endif
stop_sounds();
//stop_sounds();
stop_sound(sound_15_leveldoor_sliding);
if (leveldoor_open == 0 || leveldoor_open == 2) {
leveldoor_open = 1;
if (current_level == /*4*/ custom->mirror_level) {
Expand All @@ -467,7 +471,9 @@ Possible values of trob_type:
}
} else {
sound_interruptible[sound_15_leveldoor_sliding] = 0;
play_sound(sound_15_leveldoor_sliding); // level door sliding (opening)
if (!is_sound_playing(sound_15_leveldoor_sliding)) {
play_sound(sound_15_leveldoor_sliding); // level door sliding (opening)
}
}
}
}
Expand Down
45 changes: 43 additions & 2 deletions src/seg009.c
Original file line number Diff line number Diff line change
Expand Up @@ -1893,8 +1893,20 @@ void __pascal far play_speaker_sound(sound_buffer_type far *buffer) {
SDL_PauseAudio(0);
}

// Sound samples should be mixed together like this to prevent popping.
Sint16 saturating_add_s16(Sint16 left, Sint16 right) {
Sint32 result = (Sint32)left + (Sint32)right;
if (result < INT16_MIN) result = INT16_MIN;
if (result > INT16_MAX) result = INT16_MAX;
return result;
}

void saturating_add_to_s16(Sint16* left, Sint16 right) {
*left = saturating_add_s16(*left, right);
}

void digi_callback(void *userdata, Uint8 *stream, int len) {
printf("playing_digi_count = %d\n", playing_digi_count);
//printf("playing_digi_count = %d\n", playing_digi_count);
for (int digi_index = 0; digi_index < playing_digi_count; digi_index++) {
playing_digi_type* current_playing_digi = &playing_digis[digi_index];

Expand All @@ -1910,7 +1922,8 @@ void digi_callback(void *userdata, Uint8 *stream, int len) {
int copy_samples = copy_len / 2; // Assuming 16 bits per sample!
short* temp_buffer = (short*)current_playing_digi->digi_remaining_pos;
for (int sample = 0; sample < copy_samples; sample++) {
((short*)stream)[sample] += temp_buffer[sample];
//((short*)stream)[sample] += temp_buffer[sample];
saturating_add_to_s16(&( ((short*)stream)[sample] ), temp_buffer[sample]);
}
} else {
// If sound is off: Mute the sound but keep track of where we are.
Expand All @@ -1932,6 +1945,7 @@ void digi_callback(void *userdata, Uint8 *stream, int len) {
}

// Delete the ended sounds from the list.
// Inspired by process_trobs().
int dest_index = 0;
for (int source_index = 0; source_index < playing_digi_count; source_index++) {
if (playing_digis[source_index].digi_remaining_length > 0) {
Expand Down Expand Up @@ -2320,6 +2334,29 @@ void __pascal far play_digi_sound(sound_buffer_type far *buffer) {
SDL_PauseAudio(0);
}

void stop_digi_from_buffer(sound_buffer_type far *buffer) {
if (buffer->type != sound_digi_converted) return;
SDL_LockAudio();
byte* digi_buffer = (byte*) buffer->converted.samples;
for (int source_index = 0; source_index < playing_digi_count; source_index++) {
if (playing_digis[source_index].digi_buffer == digi_buffer) {
playing_digis[source_index].digi_remaining_length = 0;
}
}
SDL_UnlockAudio();
}

bool is_digi_playing_from_buffer(sound_buffer_type far *buffer) {
if (buffer->type != sound_digi_converted) return false;
byte* digi_buffer = (byte*) buffer->converted.samples;
for (int source_index = 0; source_index < playing_digi_count; source_index++) {
if (playing_digis[source_index].digi_buffer == digi_buffer) {
return true;
}
}
return false;
}

void free_sound(sound_buffer_type far *buffer) {
if (buffer == NULL) return;
if (buffer->type == sound_ogg) {
Expand Down Expand Up @@ -2380,6 +2417,10 @@ int __pascal far check_sound_playing() {
return speaker_playing || digi_playing || midi_playing || ogg_playing;
}

int check_sound_playing_except_digi() {
return speaker_playing || midi_playing || ogg_playing;
}

void apply_aspect_ratio() {
// Allow us to use a consistent set of screen co-ordinates, even if the screen size changes
if (use_correct_aspect_ratio) {
Expand Down

0 comments on commit ed2586e

Please sign in to comment.