Skip to content

Commit

Permalink
Fixed not loading a pipe if some loop was not suitable for crossfade G…
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg68 committed Dec 30, 2023
1 parent dde2f03 commit 27ba762
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 68 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Fixed not loading a pipe if some loop was not suitable for crossfade https://github.com/GrandOrgue/grandorgue/issues/1724
- Fixed a wrong .wav filename in the log message window https://github.com/GrandOrgue/grandorgue/issues/1724
- Increased the maximum number of Tremulants from 10 to 999
- Fixed setting a reverb file name by default to the current directory https://github.com/GrandOrgue/grandorgue/issues/1741
Expand Down
9 changes: 9 additions & 0 deletions src/grandorgue/loader/GOLoaderFilename.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ class GOLoaderFilename {
* @return a pointer to the GOFile
*/
std::unique_ptr<GOOpenedFile> Open(const GOFileStore &fileStore) const;

wxString GenerateMessage(const wxString &srcMsg) const {
return wxString::Format("%s: %s", m_path, srcMsg);
}

static wxString generateMessage(
const GOLoaderFilename *pFileName, const wxString &srcMsg) {
return pFileName ? pFileName->GenerateMessage(srcMsg) : srcMsg;
}
};

#endif
10 changes: 10 additions & 0 deletions src/grandorgue/model/GOCacheObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include <wx/string.h>

#include "loader/GOLoaderFilename.h"

class GOCache;
class GOCacheWriter;
class GOFileStore;
Expand Down Expand Up @@ -77,6 +79,14 @@ class GOCacheObject {
const GOCacheObject *pObjectFor, const wxString &srcMsg) {
return pObjectFor ? pObjectFor->GenerateMessage(srcMsg) : srcMsg;
}

static const wxString generateMessage(
const GOCacheObject *pObjectFor,
const GOLoaderFilename *pFilename,
const wxString &srcMsg) {
return generateMessage(
pObjectFor, GOLoaderFilename::generateMessage(pFilename, srcMsg));
}
};

#endif
148 changes: 81 additions & 67 deletions src/grandorgue/sound/GOSoundAudioSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#include "loader/cache/GOCache.h"
#include "loader/cache/GOCacheWriter.h"

#include "loader/GOLoaderFilename.h"
#include "model/GOCacheObject.h"

#include "GOAlloc.h"
#include "GOMemoryPool.h"
#include "GOSampleStatistic.h"
Expand Down Expand Up @@ -638,6 +641,7 @@ void GOAudioSection::DoCrossfade(
}

void GOAudioSection::Setup(
const GOCacheObject *pObjectFor,
const GOLoaderFilename *pLoaderFilename,
const void *pcm_data,
const GOWave::SAMPLE_FORMAT pcm_data_format,
Expand Down Expand Up @@ -686,75 +690,85 @@ void GOAudioSection::Setup(
end_seg.next_start_segment_index = i + 1;
const unsigned loop_length
= 1 + end_seg.end_offset - start_seg.start_offset;
unsigned end_length;
wxString loopError;

if (fade_len > loop_length - 1)
throw(wxString) _("Loop too short for crossfade");

if (start_seg.start_offset < fade_len)
throw(wxString) _("Not enough samples for a crossfade");

// calculate the fade segment size and offsets
if (end_seg.end_offset - start_seg.start_offset > SHORT_LOOP_LENGTH) {
end_seg.transition_offset
= end_seg.end_offset - MAX_READAHEAD - fade_len + 1;
end_seg.read_end = end_seg.end_offset - fade_len;
end_length = 2 * MAX_READAHEAD + fade_len;
} else {
end_seg.transition_offset = start_seg.start_offset;
end_seg.read_end = end_seg.end_offset;
end_length = SHORT_LOOP_LENGTH + MAX_READAHEAD;
if (
end_length < MAX_READAHEAD
+ (SHORT_LOOP_LENGTH / loop_length) * SHORT_LOOP_LENGTH + fade_len)
end_length = MAX_READAHEAD
+ (SHORT_LOOP_LENGTH / loop_length) * SHORT_LOOP_LENGTH + fade_len;
}
end_seg.end_size = end_length * m_BytesPerSample;

// Allocate the fade segment
end_seg.end_data = (unsigned char *)m_Pool.Alloc(end_seg.end_size, true);
if (!end_seg.end_data)
throw GOOutOfMemory();
end_seg.end_ptr
= end_seg.end_data - m_BytesPerSample * end_seg.transition_offset;

const unsigned copy_len
= 1 + end_seg.end_offset - end_seg.transition_offset;

// Fill the fade seg with transition data, then with the loop start data
memcpy(
end_seg.end_data,
((const unsigned char *)pcm_data)
+ end_seg.transition_offset * m_BytesPerSample,
copy_len * m_BytesPerSample);
loop_memcpy(
((unsigned char *)end_seg.end_data) + copy_len * m_BytesPerSample,
((const unsigned char *)pcm_data)
+ loop.m_StartPosition * m_BytesPerSample,
loop_length * m_BytesPerSample,
(end_length - copy_len) * m_BytesPerSample);
if (fade_len > 0)
// TODO: Remove the parameter names from the comment and reduce the
// number of parameters of DoCrossfade that the call would be easy
// readable without additional comments
DoCrossfade(
end_seg.end_data, // dest
MAX_READAHEAD, // dest_offset
(const unsigned char *)pcm_data, // src
start_seg.start_offset - fade_len, // src_offset
pcm_data_channels, // channels
m_BitsPerSample, // bits_per_sample
fade_len, // fade_length
loop_length, // loop_length
end_length); // length

end_seg.end_loop_length = loop_length;
end_seg.end_pos = end_length + end_seg.transition_offset;
assert(end_length >= MAX_READAHEAD);

m_StartSegments.push_back(start_seg);
m_EndSegments.push_back(end_seg);
loopError
= wxString::Format(_("Loop %u is too short for crossfade"), i + 1);
else if (start_seg.start_offset < fade_len)
loopError = wxString::Format(
_("Not enough samples for crossfade before loop %u "), i + 1);

if (loopError.IsEmpty()) {
unsigned end_length;

// calculate the fade segment size and offsets
if (end_seg.end_offset - start_seg.start_offset > SHORT_LOOP_LENGTH) {
end_seg.transition_offset
= end_seg.end_offset - MAX_READAHEAD - fade_len + 1;
end_seg.read_end = end_seg.end_offset - fade_len;
end_length = 2 * MAX_READAHEAD + fade_len;
} else {
end_seg.transition_offset = start_seg.start_offset;
end_seg.read_end = end_seg.end_offset;
end_length = SHORT_LOOP_LENGTH + MAX_READAHEAD;
if (
end_length < MAX_READAHEAD
+ (SHORT_LOOP_LENGTH / loop_length) * SHORT_LOOP_LENGTH
+ fade_len)
end_length = MAX_READAHEAD
+ (SHORT_LOOP_LENGTH / loop_length) * SHORT_LOOP_LENGTH
+ fade_len;
}
end_seg.end_size = end_length * m_BytesPerSample;

// Allocate the fade segment
end_seg.end_data
= (unsigned char *)m_Pool.Alloc(end_seg.end_size, true);
if (!end_seg.end_data)
throw GOOutOfMemory();
end_seg.end_ptr
= end_seg.end_data - m_BytesPerSample * end_seg.transition_offset;

const unsigned copy_len
= 1 + end_seg.end_offset - end_seg.transition_offset;

// Fill the fade seg with transition data, then with the loop start data
memcpy(
end_seg.end_data,
((const unsigned char *)pcm_data)
+ end_seg.transition_offset * m_BytesPerSample,
copy_len * m_BytesPerSample);
loop_memcpy(
((unsigned char *)end_seg.end_data) + copy_len * m_BytesPerSample,
((const unsigned char *)pcm_data)
+ loop.m_StartPosition * m_BytesPerSample,
loop_length * m_BytesPerSample,
(end_length - copy_len) * m_BytesPerSample);
if (fade_len > 0)
// TODO: Remove the parameter names from the comment and reduce the
// number of parameters of DoCrossfade that the call would be easy
// readable without additional comments
DoCrossfade(
end_seg.end_data, // dest
MAX_READAHEAD, // dest_offset
(const unsigned char *)pcm_data, // src
start_seg.start_offset - fade_len, // src_offset
pcm_data_channels, // channels
m_BitsPerSample, // bits_per_sample
fade_len, // fade_length
loop_length, // loop_length
end_length); // length

end_seg.end_loop_length = loop_length;
end_seg.end_pos = end_length + end_seg.transition_offset;
assert(end_length >= MAX_READAHEAD);

m_StartSegments.push_back(start_seg);
m_EndSegments.push_back(end_seg);
} else
wxLogWarning(GOCacheObject::generateMessage(
pObjectFor, pLoaderFilename, loopError));
}

/* There is no need to store any samples after the end of the last loop. */
Expand Down
2 changes: 2 additions & 0 deletions src/grandorgue/sound/GOSoundAudioSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

class GOAudioSection;
class GOCache;
class GOCacheObject;
class GOCacheWriter;
class GOLoaderFilename;
class GOMemoryPool;
Expand Down Expand Up @@ -198,6 +199,7 @@ class GOAudioSection {
int history[BLOCK_HISTORY][MAX_OUTPUT_CHANNELS]);

void Setup(
const GOCacheObject *pObjectFor,
const GOLoaderFilename *pLoaderFilename,
const void *pcm_data,
GOWave::SAMPLE_FORMAT pcm_data_format,
Expand Down
2 changes: 2 additions & 0 deletions src/grandorgue/sound/GOSoundProviderSynthedTrem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ void GOSoundProviderSynthedTrem::Create(
m_AttackInfo.push_back(attack_info);
m_Attack.push_back(new GOAudioSection(pool));
m_Attack[0]->Setup(
nullptr,
nullptr,
data.get(),
GOWave::SF_SIGNEDSHORT_16,
Expand All @@ -106,6 +107,7 @@ void GOSoundProviderSynthedTrem::Create(
m_ReleaseInfo.push_back(release_info);
m_Release.push_back(new GOAudioSection(pool));
m_Release[0]->Setup(
nullptr,
nullptr,
data.get() + attack_samples + loop_samples,
GOWave::SF_SIGNEDSHORT_16,
Expand Down
4 changes: 3 additions & 1 deletion src/grandorgue/sound/GOSoundProviderWave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void GOSoundProviderWave::CreateAttack(
GOAudioSection *section = new GOAudioSection(pool);
m_Attack.push_back(section);
section->Setup(
p_ObjectFor,
&loaderFilename,
data + attack_pos * GetBytesPerSample(bits_per_sample) * channels,
(GOWave::SAMPLE_FORMAT)bits_per_sample,
Expand Down Expand Up @@ -166,6 +167,7 @@ void GOSoundProviderWave::CreateRelease(
GOAudioSection *section = new GOAudioSection(pool);
m_Release.push_back(section);
section->Setup(
p_ObjectFor,
&loaderFilename,
data + release_offset * GetBytesPerSample(bits_per_sample) * channels,
(GOWave::SAMPLE_FORMAT)bits_per_sample,
Expand Down Expand Up @@ -287,7 +289,7 @@ void GOSoundProviderWave::LoadFromOneFile(
excText = _("Unknown exception");
}
if (!excText.IsEmpty())
throw wxString::Format("%s: %s", loaderFilename.GetPath(), excText);
throw loaderFilename.GenerateMessage(excText);
}

unsigned GOSoundProviderWave::GetFaderLength(unsigned MidiKeyNumber) {
Expand Down

0 comments on commit 27ba762

Please sign in to comment.