From: <sv...@op...> - 2024-08-08 18:19:09
|
Author: sagamusix Date: Thu Aug 8 20:18:56 2024 New Revision: 21370 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=21370 Log: [New] MED: Embedded sound bank support now also supports embedded SF2 banks. [Fix] MID: Embedded DLS sound banks were not properly read for god knows how long (r7125 would be an obvious candidate but it appears they were already broken before that). Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp trunk/OpenMPT/soundlib/Dlsbank.h trunk/OpenMPT/soundlib/Load_mid.cpp Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp Thu Aug 8 14:44:55 2024 (r21369) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp Thu Aug 8 20:18:56 2024 (r21370) @@ -616,15 +616,22 @@ bool CDLSBank::IsDLSBank(const mpt::PathString &filename) { + if(filename.empty()) + return false; + mpt::IO::InputFile f(filename, false); + if(!f.IsValid()) + return false; + return IsDLSBank(GetFileReader(f)); +} + + +bool CDLSBank::IsDLSBank(FileReader file) +{ + file.Rewind(); RIFFChunkID riff; - if(filename.empty()) return false; - mpt::ifstream f(filename, std::ios::binary); - if(!f) - { + if(!file.ReadStruct(riff)) return false; - } - MemsetZero(riff); - mpt::IO::Read(f, riff); + // Check for embedded DLS sections if(riff.id_RIFF == IFFID_FORM) { @@ -632,28 +639,31 @@ do { uint32 len = mpt::bit_cast<uint32be>(riff.riff_len); - if (len <= 4) break; - if (riff.id_DLS == IFFID_XDLS) + if(len <= 4) break; + if(riff.id_DLS == IFFID_XDLS) { - mpt::IO::Read(f, riff); - break; + if(!file.ReadStruct(riff)) + return false; + break; // found it } if((len % 2u) != 0) len++; - if (!mpt::IO::SeekRelative(f, len-4)) break; - } while (mpt::IO::Read(f, riff)); + if(!file.Skip(len - 4)) + return false; + } while(file.ReadStruct(riff)); } else if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_RMID) { for (;;) { - if(!mpt::IO::Read(f, riff)) - break; - if (riff.id_DLS == IFFID_DLS) - break; // found it + if(!file.ReadStruct(riff)) + return false; + if(riff.id_DLS == IFFID_DLS || riff.id_DLS == IFFID_sfbk) + break; // found it int len = riff.riff_len; if((len % 2u) != 0) len++; - if ((len <= 4) || !mpt::IO::SeekRelative(f, len-4)) break; + if((len <= 4) || !file.Skip(len - 4)) + return false; } } return ((riff.id_RIFF == IFFID_RIFF) @@ -733,7 +743,7 @@ } -bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const +bool CDLSBank::FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum, FileReader *file) const { ModInstrument *pIns = sndFile.Instruments[ins]; if(pIns == nullptr) @@ -747,7 +757,7 @@ || FindInstrument(isDrum, 0xFFFF, isDrum ? 0xFF : program, key, &dlsIns)) { if(key < 0x80) drumRgn = GetRegionFromKey(dlsIns, key); - if(ExtractInstrument(sndFile, ins, dlsIns, drumRgn)) + if(ExtractInstrument(sndFile, ins, dlsIns, drumRgn, file)) { pIns = sndFile.Instruments[ins]; // Reset pointer because ExtractInstrument may delete the previous value. if((key >= 24) && (key < 24 + std::size(szMidiPercussionNames))) @@ -1416,12 +1426,8 @@ m_szFileName = file.GetOptionalFileName().value(); file.Rewind(); - size_t dwMemLength = file.GetLength(); - size_t dwMemPos = 0; if(!file.CanRead(256)) - { return false; - } RIFFChunkID riff; file.ReadStruct(riff); @@ -1430,11 +1436,9 @@ { while(file.ReadStruct(riff)) { - if(riff.id_RIFF == IFFID_RIFF && riff.id_DLS == IFFID_DLS) - { - file.SkipBack(sizeof(riff)); + if(riff.id_RIFF == IFFID_RIFF && (riff.id_DLS == IFFID_DLS || riff.id_DLS == IFFID_sfbk)) break; - } + uint32 len = riff.riff_len; if((len % 2u) != 0) len++; @@ -1477,13 +1481,12 @@ m_WaveForms.clear(); m_Envelopes.clear(); nInsDef = 0; - if (dwMemLength > 8 + riff.riff_len + dwMemPos) dwMemLength = 8 + riff.riff_len + dwMemPos; bool applyPaddingToSampleChunk = true; while(file.CanRead(sizeof(IFFCHUNK))) { IFFCHUNK chunkHeader; file.ReadStruct(chunkHeader); - dwMemPos = file.GetPosition(); + const auto chunkStartPos = file.GetPosition(); FileReader chunk = file.ReadChunk(chunkHeader.len); bool applyPadding = (chunkHeader.len % 2u) != 0; @@ -1539,7 +1542,7 @@ if (((listid == IFFID_wvpl) && (m_nType & SOUNDBANK_TYPE_DLS)) || ((listid == IFFID_sdta) && (m_nType & SOUNDBANK_TYPE_SF2))) { - m_dwWavePoolOffset = dwMemPos + 4; + m_dwWavePoolOffset = chunkStartPos + 4; #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Wave Pool offset: {}")(m_dwWavePoolOffset)); #endif @@ -1694,17 +1697,16 @@ } -bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length) const +std::vector<uint8> CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, FileReader *file) const { - waveData.clear(); - length = 0; + std::vector<uint8> waveData; if (nIns >= m_Instruments.size() || !m_dwWavePoolOffset) { #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("ExtractWaveForm({}) failed: m_Instruments.size()={} m_dwWavePoolOffset={} m_WaveForms.size()={}")(nIns, m_Instruments.size(), m_dwWavePoolOffset, m_WaveForms.size())); #endif - return false; + return waveData; } const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) @@ -1712,7 +1714,7 @@ #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("invalid waveform region: nIns={} nRgn={} pSmp->nRegions={}")(nIns, nRgn, dlsIns.Regions.size())); #endif - return false; + return waveData; } uint32 nWaveLink = dlsIns.Regions[nRgn].nWaveLink; if(nWaveLink >= m_WaveForms.size()) @@ -1720,29 +1722,34 @@ #ifdef DLSBANK_LOG MPT_LOG_GLOBAL(LogDebug, "DLSBANK", MPT_UFORMAT("Invalid wavelink id: nWaveLink={} nWaveForms={}")(nWaveLink, m_WaveForms.size())); #endif - return false; + return waveData; } - mpt::ifstream f(m_szFileName, std::ios::binary); - if(!f) + std::unique_ptr<mpt::IO::InputFile> inputFile; + FileReader f; + if(file) { - return false; + f = *file; + } else + { + inputFile = std::make_unique<mpt::IO::InputFile>(m_szFileName, false); + if(!inputFile->IsValid()) + return waveData; + f = GetFileReader(*inputFile); } - mpt::IO::Offset sampleOffset = mpt::saturate_cast<mpt::IO::Offset>(m_WaveForms[nWaveLink] + m_dwWavePoolOffset); - if(mpt::IO::SeekAbsolute(f, sampleOffset)) + auto sampleOffset = mpt::saturate_cast<FileReader::pos_type>(m_WaveForms[nWaveLink] + m_dwWavePoolOffset); + if(f.Seek(sampleOffset)) { if (m_nType & SOUNDBANK_TYPE_SF2) { if (m_SamplesEx[nWaveLink].dwLen) { - if (mpt::IO::SeekRelative(f, 8)) + if (f.Skip(8)) { - length = m_SamplesEx[nWaveLink].dwLen; try { - waveData.assign(length + 8, 0); - mpt::IO::ReadRaw(f, waveData.data(), length); + f.ReadVector(waveData, m_SamplesEx[nWaveLink].dwLen); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); @@ -1752,16 +1759,14 @@ } else { LISTChunk chunk; - if(mpt::IO::Read(f, chunk)) + if(f.ReadStruct(chunk)) { if((chunk.id == IFFID_LIST) && (chunk.listid == IFFID_wave) && (chunk.len > 4)) { - length = chunk.len + 8; try { - waveData.assign(chunk.len + sizeof(IFFCHUNK), 0); - memcpy(waveData.data(), &chunk, sizeof(chunk)); - mpt::IO::ReadRaw(f, waveData.data() + sizeof(chunk), length - sizeof(chunk)); + f.SkipBack(sizeof(chunk)); + f.ReadVector(waveData, chunk.len + sizeof(IFFCHUNK)); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); @@ -1770,14 +1775,12 @@ } } } - return !waveData.empty(); + return waveData; } -bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose) const +bool CDLSBank::ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose, FileReader *file) const { - std::vector<uint8> pWaveForm; - uint32 dwLen = 0; bool ok, hasWaveform; if(nIns >= m_Instruments.size()) @@ -1785,9 +1788,8 @@ const DLSINSTRUMENT &dlsIns = m_Instruments[nIns]; if(nRgn >= dlsIns.Regions.size()) return false; - if(!ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen)) - return false; - if(dwLen < 16) + const std::vector<uint8> waveData = ExtractWaveForm(nIns, nRgn, file); + if(waveData.size() < 16) return false; ok = false; @@ -1806,10 +1808,10 @@ #endif sample.Initialize(); - FileReader chunk{mpt::as_span(pWaveForm.data(), dwLen)}; + FileReader chunk{mpt::as_span(waveData)}; if(!p.compressed || !sndFile.ReadSampleFromFile(nSample, chunk, false, false)) { - sample.nLength = dwLen / 2; + sample.nLength = mpt::saturate_cast<SmpLength>(waveData.size() / 2); SampleIO( SampleIO::_16bit, SampleIO::mono, @@ -1830,8 +1832,8 @@ hasWaveform = sample.HasSampleData(); } else { - FileReader file(mpt::as_span(pWaveForm.data(), dwLen)); - hasWaveform = sndFile.ReadWAVSample(nSample, file, false, &wsmpChunk); + FileReader wavChunk(mpt::as_span(waveData)); + hasWaveform = sndFile.ReadWAVSample(nSample, wavChunk, false, &wsmpChunk); if(dlsIns.szName[0]) sndFile.m_szNames[nSample] = mpt::String::ReadAutoBuf(dlsIns.szName); } @@ -2041,7 +2043,7 @@ } -bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const +bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn, FileReader *file) const { uint32 minRegion, maxRegion, nEnv; @@ -2202,7 +2204,7 @@ // Load the sample if(!duplicateRegion || !sndFile.GetSample(nSmp).HasSampleData()) { - ExtractSample(sndFile, nSmp, nIns, nRgn, transpose); + ExtractSample(sndFile, nSmp, nIns, nRgn, transpose, file); extractedSamples.insert(rgn.nWaveLink); } } else if(duplicateRegion && sndFile.GetSample(RgnToSmp[dupRegion]).GetNumChannels() == 1) @@ -2221,9 +2223,8 @@ const uint8 offsetOrig = (pan1 < pan2) ? 1 : 0; const uint8 offsetNew = (pan1 < pan2) ? 0 : 1; - std::vector<uint8> pWaveForm; - uint32 dwLen = 0; - if(!ExtractWaveForm(nIns, nRgn, pWaveForm, dwLen)) + const std::vector<uint8> waveData = ExtractWaveForm(nIns, nRgn, file); + if(waveData.empty()) continue; extractedSamples.insert(rgn.nWaveLink); @@ -2238,8 +2239,8 @@ // Now read the other channel if(m_SamplesEx[m_Instruments[nIns].Regions[nRgn].nWaveLink].compressed) { - FileReader file{mpt::as_span(pWaveForm)}; - if(sndFile.ReadSampleFromFile(nSmp, file, false, false)) + FileReader smpChunk{mpt::as_span(waveData)}; + if(sndFile.ReadSampleFromFile(nSmp, smpChunk, false, false)) { pDest = sampleCopy.sample16() + offsetNew; const SmpLength copyLength = std::min(sample.nLength, sampleCopy.nLength); @@ -2250,10 +2251,10 @@ } } else { - SmpLength len = std::min(dwLen / 2u, sampleCopy.nLength); - const std::byte *src = mpt::byte_cast<const std::byte *>(pWaveForm.data()); + SmpLength len = std::min(mpt::saturate_cast<SmpLength>(waveData.size() / 2u), sampleCopy.nLength); + const std::byte *src = mpt::byte_cast<const std::byte *>(waveData.data()); int16 *dst = sampleCopy.sample16() + offsetNew; - CopySample<SC::ConversionChain<SC::Convert<int16, int16>, SC::DecodeInt16<0, littleEndian16>>>(dst, len, 2, src, pWaveForm.size(), 1); + CopySample<SC::ConversionChain<SC::Convert<int16, int16>, SC::DecodeInt16<0, littleEndian16>>>(dst, len, 2, src, waveData.size(), 1); } sample.FreeSample(); sample = sampleCopy; Modified: trunk/OpenMPT/soundlib/Dlsbank.h ============================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.h Thu Aug 8 14:44:55 2024 (r21369) +++ trunk/OpenMPT/soundlib/Dlsbank.h Thu Aug 8 20:18:56 2024 (r21370) @@ -127,6 +127,7 @@ bool operator==(const CDLSBank &other) const noexcept { return !mpt::PathCompareNoCase(m_szFileName, other.m_szFileName); } static bool IsDLSBank(const mpt::PathString &filename); + static bool IsDLSBank(FileReader file); static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));} static uint32 MakeDrumCode(uint32 rgn, uint32 instr) { return (0x80000000 | (rgn << 16) | (instr));} @@ -142,16 +143,16 @@ uint32 GetNumSamples() const { return static_cast<uint32>(m_WaveForms.size()); } const DLSINSTRUMENT *GetInstrument(uint32 iIns) const { return iIns < m_Instruments.size() ? &m_Instruments[iIns] : nullptr; } [[nodiscard]] const DLSINSTRUMENT *FindInstrument(bool isDrum, uint32 bank = 0xFF, uint32 program = 0xFF, uint32 key = 0xFF, uint32 *pInsNo = nullptr) const; - bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum) const; + bool FindAndExtract(CSoundFile &sndFile, const INSTRUMENTINDEX ins, const bool isDrum, FileReader *file = nullptr) const; uint32 GetRegionFromKey(uint32 nIns, uint32 nKey) const; - bool ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector<uint8> &waveData, uint32 &length) const; - bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0) const; - bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const; + bool ExtractSample(CSoundFile &sndFile, SAMPLEINDEX nSample, uint32 nIns, uint32 nRgn, int transpose = 0, FileReader *file = nullptr) const; + bool ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn, FileReader *file = nullptr) const; const char *GetRegionName(uint32 nIns, uint32 nRgn) const; uint16 GetPanning(uint32 ins, uint32 region) const; // Internal Loader Functions protected: + std::vector<uint8> ExtractWaveForm(uint32 nIns, uint32 nRgn, FileReader *file) const; bool UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chunk); bool UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &header, FileReader &chunk); bool ConvertSF2ToDLS(SF2LoaderInfo &sf2info); Modified: trunk/OpenMPT/soundlib/Load_mid.cpp ============================================================================== --- trunk/OpenMPT/soundlib/Load_mid.cpp Thu Aug 8 14:44:55 2024 (r21369) +++ trunk/OpenMPT/soundlib/Load_mid.cpp Thu Aug 8 20:18:56 2024 (r21370) @@ -1320,11 +1320,11 @@ std::unique_ptr<CDLSBank> cachedBank, embeddedBank; - if(CDLSBank::IsDLSBank(file.GetOptionalFileName().value_or(P_("")))) + if(CDLSBank::IsDLSBank(file)) { // Soundfont embedded in MIDI file embeddedBank = std::make_unique<CDLSBank>(); - embeddedBank->Open(file.GetOptionalFileName().value_or(P_(""))); + embeddedBank->Open(file); } else { // Soundfont with same name as MIDI file @@ -1352,7 +1352,7 @@ else if(pIns->nMidiProgram) midiCode = (pIns->nMidiProgram - 1) & 0x7F; - if(embeddedBank && embeddedBank->FindAndExtract(*this, ins, midiCode >= 0x80)) + if(embeddedBank && embeddedBank->FindAndExtract(*this, ins, midiCode >= 0x80, &file)) { continue; } |