Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed hang when using a cached organ #1941

Merged
merged 1 commit into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 6 additions & 18 deletions src/core/go_defs.h.in
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
/*
* GrandOrgue - a free pipe organ simulator
*
* Copyright 2006 Milan Digital Audio LLC
* Copyright 2009-2024 GrandOrgue contributors (see AUTHORS)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* License GPL-2.0 or later
* (https://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
*/

#ifndef GODEFS_H
Expand All @@ -26,8 +12,10 @@
#define APP_VERSION "v@FULL_VERSION@"
#define APP_WIN_VERSION @NUM_WIN_VERSION@

/* Value which is used to identify a valid cached organ data file. */
#define GRANDORGUE_CACHE_MAGIC 0x12341235
/* Value which is used to identify a valid cached organ data file.
It must be changed every time when the cache structure is modefied
*/
#define GRANDORGUE_CACHE_MAGIC 0x12341236

#cmakedefine HAVE_ATOMIC
#cmakedefine HAVE_MUTEX
Expand Down
18 changes: 6 additions & 12 deletions src/grandorgue/sound/GOSoundAudioSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,8 @@ bool GOSoundAudioSection::LoadCache(GOCache &cache) {
EndSegment s;

if (!cache.Read(
&s.next_start_segment_index, sizeof(s.next_start_segment_index)))
return false;
if (!cache.Read(&s.transition_offset, sizeof(s.transition_offset)))
return false;
if (!cache.Read(&s.end_size, sizeof(s.end_size)))
static_cast<EndSegmentDescription *>(&s),
sizeof(EndSegmentDescription)))
return false;
s.end_data = (unsigned char *)cache.ReadBlock(s.end_size);
if (!s.end_data)
Expand Down Expand Up @@ -179,16 +176,13 @@ bool GOSoundAudioSection::SaveCache(GOCacheWriter &cache) const {
if (!cache.Write(&temp, sizeof(temp)))
return false;
for (unsigned i = 0; i < temp; i++) {
const EndSegment *s = &m_EndSegments[i];
const EndSegment &s = m_EndSegments[i];

if (!cache.Write(
&s->next_start_segment_index, sizeof(s->next_start_segment_index)))
return false;
if (!cache.Write(&s->transition_offset, sizeof(s->transition_offset)))
return false;
if (!cache.Write(&s->end_size, sizeof(s->end_size)))
static_cast<const EndSegmentDescription *>(&s),
sizeof(EndSegmentDescription)))
return false;
if (!cache.WriteBlock(s->end_data, s->end_size))
if (!cache.WriteBlock(s.end_data, s.end_size))
return false;
}

Expand Down
18 changes: 10 additions & 8 deletions src/grandorgue/sound/GOSoundAudioSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class GOSoundAudioSection {
* This segment contains copy of samples from a loop end and then from the
* loop start. It is necessary for read-ahead when resampling
*/
struct EndSegment {
struct EndSegmentDescription {
/* A position after the last copied sample in the end segment.
* An end segment has more MAX_READAHEAD samples after end_pos:
* - A loop end segment contains a copy of samples from the loop start
Expand All @@ -52,13 +52,6 @@ class GOSoundAudioSection {
* than end_pos). */
unsigned transition_offset;

/* Uncompressed ending data blob. This data must start before
* sample_offset*/
unsigned char *end_data;

// A virtual pointer to end_data. end_data has transition_offset to end_ptr
unsigned char *end_ptr;

// The size of the end data in bytes
unsigned end_size;

Expand All @@ -67,6 +60,15 @@ class GOSoundAudioSection {
int next_start_segment_index;
};

struct EndSegment : public EndSegmentDescription {
/* Uncompressed ending data blob. This data must start before
* sample_offset*/
unsigned char *end_data;

// A virtual pointer to end_data. end_data has transition_offset to end_ptr
unsigned char *end_ptr;
};

private:
void Compress(bool format16);

Expand Down
20 changes: 18 additions & 2 deletions src/grandorgue/sound/GOSoundStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include "GOSoundStream.h"

#include <wx/log.h>

#include "GOSoundAudioSection.h"
#include "GOSoundReleaseAlignTable.h"

Expand Down Expand Up @@ -293,10 +295,10 @@ bool GOSoundStream::ReadBlock(float *buffer, unsigned int n_blocks) {
// switch to the start of the loop
const GOSoundAudioSection::StartSegment *next
= &audio_section->GetStartSegment(m_NextStartSegmentIndex);
unsigned newPos = next->start_offset + (pos - end_pos);

// switch to the start of the loop
ptr = audio_section->GetData();
m_ResamplingPos.SetIndex(next->start_offset + (pos - end_pos));

/* Find a suitable end segment */
const unsigned next_end_segment_index
Expand All @@ -305,12 +307,26 @@ bool GOSoundStream::ReadBlock(float *buffer, unsigned int n_blocks) {
= &audio_section->GetEndSegment(next_end_segment_index);

assert(next_end->end_pos >= next->start_offset);

cache = next->cache;
cache.ptr = audio_section->GetData() + (intptr_t)cache.ptr;
transition_position = next_end->transition_offset;
end_pos = next_end->end_pos;
end_ptr = next_end->end_ptr;
m_NextStartSegmentIndex = next_end->next_start_segment_index;

m_ResamplingPos.SetIndex(newPos);
if (newPos < end_pos) // valid loop
m_NextStartSegmentIndex = next_end->next_start_segment_index;
else { // invalid loop. Using it might cause infinite iterations here
wxLogError(
"GOSoundStream::ReadBlock: Breaking invalid loop: start_offset=%d, "
"end_pos=%d, new_pos=%d",
next_end->end_pos,
next->start_offset,
newPos);
// force exit at the next iteration
m_NextStartSegmentIndex = -1;
}
} else { // no loop available
// fill the buffer with zeros
float *p = buffer;
Expand Down
Loading