From: <sag...@us...> - 2013-04-12 17:44:07
|
Revision: 1866 http://sourceforge.net/p/modplug/code/1866 Author: saga-games Date: 2013-04-12 17:43:54 +0000 (Fri, 12 Apr 2013) Log Message: ----------- [Ref] Moved song message functionality to own class SongMessage. Use std::string as an implementation base. Modified Paths: -------------- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp trunk/OpenMPT/mptrack/CleanupSong.cpp trunk/OpenMPT/mptrack/Ctrl_com.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/mptrack/Undo.cpp trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/mptrack/VstPresets.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/mod2midi.cpp trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/soundlib/Dlsbank.cpp trunk/OpenMPT/soundlib/LOAD_DMF.CPP trunk/OpenMPT/soundlib/Load_669.cpp trunk/OpenMPT/soundlib/Load_ams.cpp trunk/OpenMPT/soundlib/Load_far.cpp trunk/OpenMPT/soundlib/Load_gdm.cpp trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Load_mdl.cpp trunk/OpenMPT/soundlib/Load_med.cpp trunk/OpenMPT/soundlib/Load_mid.cpp trunk/OpenMPT/soundlib/Load_mt2.cpp trunk/OpenMPT/soundlib/Load_mtm.cpp trunk/OpenMPT/soundlib/Load_ult.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Message.cpp trunk/OpenMPT/soundlib/ModSequence.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/unzip/unzip.cpp trunk/OpenMPT/unzip/unzip.h Added Paths: ----------- trunk/OpenMPT/soundlib/FloatMixer.h trunk/OpenMPT/soundlib/Message.h Modified: trunk/OpenMPT/mptrack/AbstractVstEditor.cpp =================================================================== --- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -19,6 +19,7 @@ #include "../common/StringFixer.h" #include "MIDIMacros.h" #include "VstPresets.h" +#include "../soundlib/FileReader.h" #ifndef NO_VST Modified: trunk/OpenMPT/mptrack/CleanupSong.cpp =================================================================== --- trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -14,6 +14,7 @@ #include "Mainfrm.h" #include "modsmp_ctrl.h" #include "CleanupSong.h" +#include "../common/StringFixer.h" // Default checkbox state bool CModCleanupDlg::m_bCheckBoxes[CU_MAX_CLEANUP_OPTIONS] = Modified: trunk/OpenMPT/mptrack/Ctrl_com.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_com.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Ctrl_com.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -127,9 +127,10 @@ m_EditComments.SetRedraw(FALSE); m_EditComments.SetSel(0, -1, TRUE); m_EditComments.ReplaceSel(""); - if (m_pSndFile->m_lpszSongComments) + if(!m_pSndFile->songMessage.empty()) { - CHAR s[256], *p = m_pSndFile->m_lpszSongComments, c; + CHAR s[256], c; + const char *p = m_pSndFile->songMessage.c_str(); UINT ln = 0; while ((c = *p++) != NULL) { @@ -167,24 +168,23 @@ void CCtrlComments::OnCommentsChanged() //------------------------------------- { - CHAR s[256], *oldcomments = NULL; - if ((m_nLockCount) || (!m_pSndFile) || !m_pSndFile->GetModSpecifications().hasComments) return; if ((!m_bInitialized) || (!m_EditComments.m_hWnd) || (!m_EditComments.GetModify())) return; - if (m_pSndFile->m_lpszSongComments) - { - oldcomments = m_pSndFile->m_lpszSongComments; - m_pSndFile->m_lpszSongComments = NULL; - } + + CHAR s[LINE_LENGTH + 2]; + const char *oldMsg = m_pSndFile->songMessage.c_str(); + // Updating comments { - - UINT n = m_EditComments.GetLineCount(); LPSTR p = new char[n * LINE_LENGTH + 1]; + if (!p) + { + return; + } p[0] = 0; - if (!p) return; + for (UINT i=0; i<n; i++) { int ln = m_EditComments.GetLine(i, s, LINE_LENGTH); @@ -206,27 +206,20 @@ len--; p[len] = 0; } - if (p[0]) - m_pSndFile->m_lpszSongComments = p; - else - delete[] p; - if (oldcomments) + + m_EditComments.SetModify(FALSE); + if(p != m_pSndFile->songMessage) { - bool bSame = false; - if ((m_pSndFile->m_lpszSongComments) - && (!strcmp(m_pSndFile->m_lpszSongComments, oldcomments))) bSame = true; - delete[] oldcomments; - if (bSame) return; - } else - { - if (!m_pSndFile->m_lpszSongComments) return; + m_pSndFile->songMessage.assign(p); + + if(m_pModDoc) + { + m_pModDoc->SetModified(); + m_pModDoc->UpdateAllViews(NULL, HINT_MODCOMMENTS, this); + } } - if (m_pModDoc) - { - m_EditComments.SetModify(FALSE); - m_pModDoc->SetModified(); - m_pModDoc->UpdateAllViews(NULL, HINT_MODCOMMENTS, this); - } + + delete[] p; } } Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -27,6 +27,7 @@ #include "modsmp_ctrl.h" #include "Autotune.h" #include "../common/StringFixer.h" +#include "../soundlib/FileReader.h" #include <Shlwapi.h> #ifdef _DEBUG Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -624,9 +624,9 @@ m_CbnGenre.GetWindowText(sText, sizeof(sText)); m_FileTags.genre = sText; - if (m_pSndFile->m_lpszSongComments) + if(!m_pSndFile->songMessage.empty()) { - m_FileTags.comments = m_pSndFile->GetSongMessage(leLF); + m_FileTags.comments = m_pSndFile->songMessage.GetFormatted(SongMessage::leLF); } else { Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -16,6 +16,7 @@ #include "dlsbank.h" #include "modsmp_ctrl.h" #include "../common/misc_util.h" +#include "../common/StringFixer.h" #pragma warning(disable:4244) //"conversion from 'type1' to 'type2', possible loss of data" Modified: trunk/OpenMPT/mptrack/Undo.cpp =================================================================== --- trunk/OpenMPT/mptrack/Undo.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Undo.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -14,6 +14,7 @@ #include "MainFrm.h" #include "modsmp_ctrl.h" #include "Undo.h" +#include "../common/StringFixer.h" #define new DEBUG_NEW Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -277,7 +277,7 @@ m_SongFile->Create(lpStream, NULL, dwLen); // Destroy some stuff that we're not going to use anyway. m_SongFile->Patterns.DestroyPatterns(); - m_SongFile->FreeMessage(); + m_SongFile->songMessage.clear(); } f.Unlock(); } Modified: trunk/OpenMPT/mptrack/VstPresets.cpp =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/VstPresets.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -11,10 +11,11 @@ #include "stdafx.h" #ifndef NO_VST -#include "Sndfile.h" +#include "../soundlib/Sndfile.h" #include "Vstplug.h" #include <vstsdk2.4/pluginterfaces/vst2.x/vstfxstore.h> #include "VstPresets.h" +#include "../soundlib/FileReader.h" // This part of the header is identical for both presets and banks. Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -25,6 +25,7 @@ #include "../common/version.h" #include "midimappingdialog.h" #include "../common/StringFixer.h" +#include "../soundlib/FileReader.h" #include "../soundlib/plugins/JBridge.h" #ifdef VST_USE_ALTERNATIVE_MAGIC //Pelya's plugin ID fix. Breaks fx presets, so let's avoid it for now. #define ZLIB_WINAPI Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/Vstplug.h 2013-04-12 17:43:54 UTC (rev 1866) @@ -18,6 +18,8 @@ #include "../soundlib/Snd_defs.h" #include "../soundlib/plugins/PluginMixBuffer.h" +#include "../common/StringFixer.h" + //#define kBuzzMagic 'Buzz' #define kDmoMagic 'DXMO' Modified: trunk/OpenMPT/mptrack/mod2midi.cpp =================================================================== --- trunk/OpenMPT/mptrack/mod2midi.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/mod2midi.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -11,6 +11,7 @@ #include "stdafx.h" #include "Mptrack.h" #include "../soundlib/Sndfile.h" +#include "../common/StringFixer.h" #include "mod2midi.h" #include "Wav.h" @@ -393,12 +394,13 @@ } // Add Song comments on track 0 - if ((m_pSndFile->m_lpszSongComments) && (m_pSndFile->m_lpszSongComments[0])) + if(!m_pSndFile->songMessage.empty()) { + const std::string msg = m_pSndFile->songMessage.GetFormatted(SongMessage::leCR); tmp[0] = 0; tmp[1] = 0xff; tmp[2] = 0x02; Tracks[0].Write(tmp, 3); - Tracks[0].WriteLen(strlen(m_pSndFile->m_lpszSongComments)); - Tracks[0].Write(m_pSndFile->m_lpszSongComments, strlen(m_pSndFile->m_lpszSongComments)); + Tracks[0].WriteLen(msg.length()); + Tracks[0].Write(msg.c_str(), msg.length()); } // Add channel names Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-04-12 17:43:54 UTC (rev 1866) @@ -1291,6 +1291,10 @@ > </File> <File + RelativePath="..\soundlib\Message.h" + > + </File> + <File RelativePath="..\soundlib\Load_669.cpp" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-04-12 17:43:54 UTC (rev 1866) @@ -417,6 +417,7 @@ <ClInclude Include="..\soundlib\FileReader.h" /> <ClInclude Include="..\soundlib\ITCompression.h" /> <ClInclude Include="..\soundlib\ITTools.h" /> + <ClInclude Include="..\soundlib\Message.h" /> <ClInclude Include="..\soundlib\MIDIEvents.h" /> <ClInclude Include="..\soundlib\MIDIMacros.h" /> <ClInclude Include="..\soundlib\MixerSettings.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-04-12 17:43:54 UTC (rev 1866) @@ -789,6 +789,9 @@ <ClInclude Include="..\sounddev\SoundDevice.h"> <Filter>Header Files\sounddev</Filter> </ClInclude> + <ClInclude Include="..\soundlib\Message.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/mptrack/test/test.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -328,7 +328,7 @@ // Global Variables VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[0], "Test Module"), 0); - VERIFY_EQUAL_NONCONT(pSndFile->m_lpszSongComments[0], 'O'); + VERIFY_EQUAL_NONCONT(pSndFile->songMessage.at(0), 'O'); VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultTempo, 139); VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultSpeed, 5); VERIFY_EQUAL_NONCONT(pSndFile->m_nGlobalVolume, 128); @@ -522,7 +522,7 @@ // Global Variables VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[0], "Test Module_____________X"), 0); - VERIFY_EQUAL_NONCONT(pSndFile->m_lpszSongComments[0], 'O'); + VERIFY_EQUAL_NONCONT(pSndFile->songMessage.at(0), 'O'); VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultTempo, 139); VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultSpeed, 5); VERIFY_EQUAL_NONCONT(pSndFile->m_nGlobalVolume, 128); Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp =================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -15,6 +15,7 @@ #include "dlsbank.h" #include "Wav.h" #include "../common/StringFixer.h" +#include "../soundlib/FileReader.h" #include "SampleIO.h" //#define DLSBANK_LOG Added: trunk/OpenMPT/soundlib/FloatMixer.h =================================================================== --- trunk/OpenMPT/soundlib/FloatMixer.h (rev 0) +++ trunk/OpenMPT/soundlib/FloatMixer.h 2013-04-12 17:43:54 UTC (rev 1866) @@ -0,0 +1,389 @@ +// FIXME left vs right +// FIXME: Playing samples backwards should reverse interpolation LUTs as well - we might need separate LUTs because otherwise we will add tons of branches. Done for linear interpolation. +// Konzept loop-wraparound: +// Hinter dem eigentlichen Sample Platz lassen f\xFCr 2x max LUT size * num channels * samplesize +// Die letzten LUT samples vor dem loopend und die ersten LUT samples nach dem loopstart werden dorthin kopiert +// -> Bzw bei pingpong-samples die letzten LUT samples umdrehen, statt die ersten LUT samples zu verwenden +// Je nachdem, wo wir uns im sample befinden, beim rendern dann das normale sample oder den loopteil hinter dem sample als pointer verwenden +// -> Auch f\xFCr pingpong-samples am samplestart? + +typedef float mixsample_t; + +extern mixsample_t gFastSincf[]; +extern mixsample_t gKaiserSincf[]; // 8-taps polyphase +extern mixsample_t gDownsample13xf[]; // 1.3x downsampling +extern mixsample_t gDownsample2xf[]; // 2x downsampling +extern mixsample_t gLinearInterpolationForward[]; +extern mixsample_t gLinearInterpolationBackward[]; + +////////////////////////////////////////////////////////////////////////// +// Sample conversion traits + +template<int channelsOut, int channelsIn, typename out, typename in> +struct BasicTraits +{ + static const int numChannelsIn = channelsIn; // Number of channels in sample + static const int numChannelsOut = channelsOut; // Number of mixer output channels + typedef out output_t; // Output buffer sample type + typedef in input_t; // Input buffer sample type + typedef out outbuf_t[channelsOut]; // Output buffer sampling point type + // To perform sample conversion, add a function with the following signature to your derived classes: + // static forceinline output_t Convert(const input_t x) +}; + +template<int channelsOut, int channelsIn, typename out, typename in, int int2float> +struct IntToFloatTraits : public BasicTraits<channelsOut, channelsIn, out, in> +{ + static_assert(std::numeric_limits<input_t>::is_integer, "Input must be integer"); + static_assert(!std::numeric_limits<output_t>::is_integer, "Output must be floating point"); + + static forceinline output_t Convert(const input_t x) + { + return static_cast<output_t>(x) * (static_cast<output_t>(1.0f) / static_cast<output_t>(int2float)); + } +}; + +typedef IntToFloatTraits<2, 1, mixsample_t, int8, -int8_min> Int8MToFloatS; +typedef IntToFloatTraits<2, 1, mixsample_t, int16, -int16_min> Int16MToFloatS; +typedef IntToFloatTraits<2, 2, mixsample_t, int8, -int8_min> Int8SToFloatS; +typedef IntToFloatTraits<2, 2, mixsample_t, int16, -int16_min> Int16SToFloatS; + + +////////////////////////////////////////////////////////////////////////// +// Interpolation templates + +template<class Traits> +struct NoInterpolation +{ + forceinline void Start(const ModChannel &) { } + forceinline void End(const ModChannel &) { } + + forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32) + { + static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels"); + + for(int i = 0; i < Traits::numChannelsIn; i++) + { + outSample[i] = Traits::Convert(inBuffer[i]); + } + } +}; + + +template<class Traits> +struct LinearInterpolation +{ + const mixsample_t *lut; + int dir; + + forceinline void Start(const ModChannel &chn) + { + lut = chn.nInc >= 0 ? gLinearInterpolationForward : gLinearInterpolationBackward; + dir = chn.nInc >= 0 ? Traits::numChannelsIn : -Traits::numChannelsIn; + } + + forceinline void End(const ModChannel &) { } + + forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo) + { + static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels"); + const mixsample_t fract = lut[posLo >> 8]; + + for(int i = 0; i < Traits::numChannelsIn; i++) + { + Traits::output_t srcVol = Traits::Convert(inBuffer[i]); + Traits::output_t destVol = Traits::Convert(inBuffer[i + dir]); + + outSample[i] = srcVol + fract * (destVol - srcVol); + } + } +}; + + +template<class Traits> +struct FastSincInterpolation +{ + forceinline void Start(const ModChannel &) { } + forceinline void End(const ModChannel &) { } + + forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo) + { + static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels"); + const mixsample_t *lut = gFastSincf + ((posLo >> 6) & 0x3FC); + + for(int i = 0; i < Traits::numChannelsIn; i++) + { + outSample[i] = + lut[0] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + + lut[1] * Traits::Convert(inBuffer[i]) + + lut[2] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + + lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]); + } + } +}; + + +template<class Traits> +struct PolyphaseInterpolation +{ + const mixsample_t *sinc; + forceinline void Start(const ModChannel &chn) + { + sinc = (((chn.nInc > 0x13000) || (chn.nInc < -0x13000)) ? + (((chn.nInc > 0x18000) || (chn.nInc < -0x18000)) ? gDownsample2xf : gDownsample13xf) : gKaiserSincf); + } + + forceinline void End(const ModChannel &) { } + + forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo) + { + static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels"); + const mixsample_t *lut = sinc + ((posLo >> 1) & ~0x1F); + + for(int i = 0; i < Traits::numChannelsIn; i++) + { + outSample[i] = + lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn]) + + lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn]) + + lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + + lut[3] * Traits::Convert(inBuffer[i]) + + lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + + lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]) + + lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]) + + lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]); + } + } +}; + + +template<class Traits> +struct FIRFilterInterpolation +{ + forceinline void Start(const ModChannel &) { } + forceinline void End(const ModChannel &) { } + + forceinline void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32 posLo) + { + static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels"); + const mixsample_t * const lut = CWindowedFIR::lutf + (((posLo + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK); + + for(int i = 0; i < Traits::numChannelsIn; i++) + { + outSample[i] = + lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn]) + + lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn]) + + lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]) + + lut[3] * Traits::Convert(inBuffer[i]) + + lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn]) + + lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]) + + lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]) + + lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]); + } + } +}; + + +////////////////////////////////////////////////////////////////////////// +// Mixing templates (add sample to stereo mix) + +template<class Traits> +struct NoRamp +{ + typename Traits::output_t lVol, rVol; + + forceinline void Start(const ModChannel &chn) + { + lVol = static_cast<Traits::output_t>(chn.nLeftVol) * (1.0f / 4096.0f); + rVol = static_cast<Traits::output_t>(chn.nRightVol) * (1.0f / 4096.0f); + } + + forceinline void End(const ModChannel &) { } +}; + + +struct Ramp +{ + int32 lRamp, rRamp; + + forceinline void Start(const ModChannel &chn) + { + lRamp = chn.nRampLeftVol; + rRamp = chn.nRampRightVol; + } + + forceinline void End(ModChannel &chn) + { + chn.nRampLeftVol = lRamp; chn.nLeftVol = lRamp >> VOLUMERAMPPRECISION; + chn.nRampRightVol = rRamp; chn.nRightVol = rRamp >> VOLUMERAMPPRECISION; + } +}; + + +// Legacy optimization: If chn.nLeftVol == chn.nRightVol, save one multiplication instruction +template<class Traits> +struct MixMonoFastNoRamp : public NoRamp<Traits> +{ + forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer) + { + Traits::output_t vol = outSample[0] * lVol; + for(int i = 0; i < Traits::numChannelsOut; i++) + { + outBuffer[i] += vol; + } + } +}; + + +template<class Traits> +struct MixMonoNoRamp : public NoRamp<Traits> +{ + forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer) + { + outBuffer[0] += outSample[0] * lVol; + outBuffer[1] += outSample[0] * rVol; + } +}; + + +template<class Traits> +struct MixMonoRamp : public Ramp +{ + forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer) + { + // TODO volume is not float! + lRamp += chn.nLeftRamp; + rRamp += chn.nRightRamp; + outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); + outBuffer[1] += outSample[0] * (rRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); + } +}; + + +template<class Traits> +struct MixStereoNoRamp : public NoRamp<Traits> +{ + forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const outBuffer) + { + outBuffer[0] += outSample[0] * lVol; + outBuffer[1] += outSample[1] * rVol; + } +}; + + +template<class Traits> +struct MixStereoRamp : public Ramp +{ + forceinline void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const outBuffer) + { + // TODO volume is not float! + lRamp += chn.nLeftRamp; + rRamp += chn.nRightRamp; + outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); + outBuffer[1] += outSample[1] * (rRamp >> VOLUMERAMPPRECISION) * (1.0f / 4096.0f); + } +}; + + +////////////////////////////////////////////////////////////////////////// +// Filter templates + + +template<class Traits> +struct NoFilter +{ + forceinline void Start(const ModChannel &) { } + forceinline void End(const ModChannel &) { } + + forceinline void operator() (const typename Traits::outbuf_t &, const ModChannel &) { } +}; + + +// Resonant filter +template<class Traits> +struct ResonantFilter +{ + // Filter history + typename Traits::output_t fy[Traits::numChannelsIn][2]; + + forceinline void Start(const ModChannel &chn) + { + for(int i = 0; i < Traits::numChannelsIn; i++) + { + fy[i][0] = chn.nFilter_Y[i][0]; + fy[i][1] = chn.nFilter_Y[i][1]; + } + } + + forceinline void End(ModChannel &chn) + { + for(int i = 0; i < Traits::numChannelsIn; i++) + { + chn.nFilter_Y[i][0] = fy[i][0]; + chn.nFilter_Y[i][1] = fy[i][1]; + } + } + + // Filter values are clipped to double the input range +#define ClipFilter(x) Clamp(x, static_cast<Traits::output_t>(-2.0f), static_cast<Traits::output_t>(2.0f)) + + forceinline void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn) + { + static_assert(Traits::numChannelsIn <= Traits::numChannelsOut, "Too many input channels"); + + for(int i = 0; i < Traits::numChannelsIn; i++) + { + Traits::output_t val = (outSample[i] * chn.nFilter_A0 + ClipFilter(fy[i][0]) * chn.nFilter_B0 + ClipFilter(fy[i][1]) * chn.nFilter_B1); + fy[i][1] = fy[i][0]; + fy[i][0] = val - (outSample[i] * chn.nFilter_HPf); + outSample[i] = val; + } + } + +#undef ClipFilter +}; + + +////////////////////////////////////////////////////////////////////////// +// Main sample render loop template + + +// Template parameters: +// Traits: A BasicTraits instance that defines the number of channels, sample buffer types, etc.. +// InterpolationFunc: Functor for reading the sample data and doing the SRC +// FilterFunc: Functor for applying the resonant filter +// MixFunc: Functor for mixing the computed sample data into the output buffer +template<class Traits, class InterpolationFunc, class FilterFunc, class MixFunc> +static void MPPASMCALL SampleLoop(ModChannel &chn, typename Traits::output_t *outBuffer, int numSamples) +{ + register ModChannel &c = chn; + const Traits::input_t *inSample = static_cast<const Traits::input_t *>(c.pCurrentSample) + c.nPos * Traits::numChannelsIn; + int32 smpPos = c.nPosLo; // 16.16 sample position relative to c.nPos + + InterpolationFunc interpolate; + FilterFunc filter; + MixFunc mix; + + // Do initialisation if necessary + interpolate.Start(c); + filter.Start(c); + mix.Start(c); + + register int samples = numSamples; + do + { + Traits::outbuf_t outSample; + interpolate(outSample, inSample + (smpPos >> 16) * Traits::numChannelsIn, (smpPos & 0xFFFF)); + filter(outSample, c); + mix(outSample, c, outBuffer); + outBuffer += Traits::numChannelsOut; + + smpPos += c.nInc; + } while(--samples); + + mix.End(c); + filter.End(c); + interpolate.End(c); + + c.nPos += smpPos >> 16; + c.nPosLo = smpPos & 0xFFFF; +}; Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2013-04-12 17:43:54 UTC (rev 1866) @@ -1030,7 +1030,7 @@ chunk = chunks.GetChunk(DMFChunk::idCMSG); if(chunk.IsValid()) { - ReadFixedLineLengthMessage(chunk, chunk.GetLength() - 1, 40, 0); + songMessage.ReadFixedLineLength(chunk, chunk.GetLength() - 1, 40, 0); } // Read sample headers + data Modified: trunk/OpenMPT/soundlib/Load_669.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_669.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_669.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -129,7 +129,7 @@ // Copy first song message line into song title StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], fileHeader.songMessage, 36); // Song Message - ReadFixedLineLengthMessage(reinterpret_cast<const BYTE *>(fileHeader.songMessage), 108, 36, 0); + songMessage.ReadFixedLineLength(fileHeader.songMessage, 108, 36, 0); // Reading Orders Order.ReadFromArray(fileHeader.orders); Modified: trunk/OpenMPT/soundlib/Load_ams.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_ams.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -450,7 +450,7 @@ } // Packed text doesn't include any line breaks! - ReadFixedLineLengthMessage(&textOut[0], textOut.size(), 76, 0, ConvertAMSTextChars); + songMessage.ReadFixedLineLength(&textOut[0], textOut.size(), 76, 0, ConvertAMSTextChars); } // Read Order List @@ -828,7 +828,7 @@ uint8 composerLength = file.ReadUint8(); if(composerLength) { - ReadMessage(file, composerLength, leAutodetect, ConvertAMSTextChars); + songMessage.Read(file, composerLength, SongMessage::leAutodetect, ConvertAMSTextChars); } // Channel names @@ -867,7 +867,7 @@ } } // Packed text doesn't include any line breaks! - ReadFixedLineLengthMessage(&textOut[0], descriptionHeader.unpackedLen, 74, 0, ConvertAMSTextChars); + songMessage.ReadFixedLineLength(&textOut[0], descriptionHeader.unpackedLen, 74, 0, ConvertAMSTextChars); } // Read Order List Modified: trunk/OpenMPT/soundlib/Load_far.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_far.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_far.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -165,7 +165,7 @@ // Read song message if(fileHeader.messageLength != 0) { - ReadFixedLineLengthMessage(file, fileHeader.messageLength, 132, 0); // 132 characters per line... wow. :) + songMessage.ReadFixedLineLength(file, fileHeader.messageLength, 132, 0); // 132 characters per line... wow. :) } // Read orders Modified: trunk/OpenMPT/soundlib/Load_gdm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_gdm.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_gdm.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -509,7 +509,7 @@ // Read song comments if(fileHeader.messageTextLength > 0 && file.Seek(fileHeader.messageTextOffset)) { - ReadMessage(file, fileHeader.messageTextLength, leAutodetect); + songMessage.Read(file, fileHeader.messageTextLength, SongMessage::leAutodetect); } return true; Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -580,7 +580,7 @@ // Generally, IT files should use CR for line endings. However, ChibiTracker uses LF. One could do... // if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0214 && itHeader.reserved == ITFileHeader::chibiMagic) --> Chibi detected. // But we'll just use autodetection here: - ReadMessage(file, fileHeader.msglength, leAutodetect); + songMessage.Read(file, fileHeader.msglength, SongMessage::leAutodetect); } } @@ -1156,10 +1156,10 @@ // Comments uint16 msglength = 0; - if(m_lpszSongComments) + if(!songMessage.empty()) { itHeader.special |= ITFileHeader::embedSongMessage; - itHeader.msglength = msglength = (uint16)MIN(strlen(m_lpszSongComments) + 1, uint16_max); + itHeader.msglength = msglength = (uint16)MIN(songMessage.length() + 1, uint16_max); itHeader.msgoffset = dwHdrPos + dwExtra + (itHeader.insnum + itHeader.smpnum + itHeader.patnum) * 4; } @@ -1226,7 +1226,7 @@ if(itHeader.special & ITFileHeader::embedSongMessage) { dwPos += msglength; - fwrite(m_lpszSongComments, 1, msglength, f); + fwrite(songMessage.c_str(), 1, msglength, f); } // Writing instruments Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -51,7 +51,7 @@ } // Song comments - ReadMessage(file, file.ReadUint32LE(), leCR); + songMessage.Read(file, file.ReadUint32LE(), SongMessage::leCR); // Song global config m_SongFlags = static_cast<SongFlags>(file.ReadUint32LE() & SONG_FILE_FLAGS); @@ -295,11 +295,14 @@ // Song comments // comment string length - id = m_lpszSongComments ? strlen(m_lpszSongComments)+1 : 0; - fwrite(&id, 1, sizeof(id), f); + { + const size_t msgLength = songMessage.empty() ? 0 : songMessage.length() + 1; + id = msgLength; + fwrite(&id, 1, sizeof(id), f); - // comment string - if(m_lpszSongComments) fwrite(&m_lpszSongComments[0], 1, strlen(m_lpszSongComments)+1, f); + // comment string + if(msgLength) fwrite(songMessage.c_str(), 1, msgLength, f); + } // Song global config Modified: trunk/OpenMPT/soundlib/Load_mdl.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mdl.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_mdl.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -348,7 +348,7 @@ #endif if(blocklen) { - ReadMessage(lpStream + dwMemPos, blocklen - 1, leCR); + songMessage.Read(lpStream + dwMemPos, blocklen - 1, SongMessage::leCR); } break; // PA: Pattern Data Modified: trunk/OpenMPT/soundlib/Load_med.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_med.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_med.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -706,7 +706,7 @@ annolen = MIN(annolen, MED_MAX_COMMENT_LENGTH); //Thanks to Luigi Auriemma for pointing out an overflow risk if ((annotxt) && (annolen) && (annolen <= dwMemLength) && (annotxt <= dwMemLength - annolen) ) { - ReadMessage(lpStream + annotxt, annolen - 1, leAutodetect); + songMessage.Read(lpStream + annotxt, annolen - 1, SongMessage::leAutodetect); } // Song Name UINT songname = BigEndian(pmex->songname); Modified: trunk/OpenMPT/soundlib/Load_mid.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mid.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_mid.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -722,17 +722,17 @@ memcpy(m_szNames[0], ptrk->ptracks, len); m_szNames[0][len] = 0; } else - if ((!m_lpszSongComments) && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F)) + if (songMessage.empty() && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F)) { - ReadMessage(ptrk->ptracks, len, leAutodetect); + songMessage.Read(ptrk->ptracks, len, SongMessage::leAutodetect); } break; // FF.02 [text]: Song Copyright case 0x02: if (!len) break; - if ((!m_lpszSongComments) && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F) && (len > 7)) + if (songMessage.empty() && (ptrk->ptracks[0]) && (ptrk->ptracks[0] < 0x7F) && (len > 7)) { - ReadMessage(ptrk->ptracks, len, leAutodetect); + songMessage.Read(ptrk->ptracks, len, SongMessage::leAutodetect); } break; // FF.03: Sequence Name Modified: trunk/OpenMPT/soundlib/Load_mt2.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mt2.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_mt2.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -267,7 +267,7 @@ { DWORD nTxtLen = dwLen; if (nTxtLen > 32000) nTxtLen = 32000; - ReadMessage(lpStream + dwMemPos + 1, nTxtLen - 1, leCRLF); + songMessage.Read(lpStream + dwMemPos + 1, nTxtLen - 1, SongMessage::leCRLF); } break; // SUM -> author name (or "Unregistered") Modified: trunk/OpenMPT/soundlib/Load_mtm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mtm.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_mtm.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -186,7 +186,7 @@ { // Read message with a fixed line length of 40 characters // (actually the last character is always null, so make that 39 + 1 padding byte) - ReadFixedLineLengthMessage(file, fileHeader.commentSize, 39, 1); + songMessage.ReadFixedLineLength(file, fileHeader.commentSize, 39, 1); } // Reading Samples Modified: trunk/OpenMPT/soundlib/Load_ult.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ult.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_ult.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -392,7 +392,7 @@ SetModFlag(MSF_COMPATIBLE_PLAY, true); // read "messageLength" lines, each containing 32 characters. - ReadFixedLineLengthMessage(file, fileHeader.messageLength * 32, 32, 0); + songMessage.ReadFixedLineLength(file, fileHeader.messageLength * 32, 32, 0); m_nSamples = static_cast<SAMPLEINDEX>(file.ReadUint8()); if(GetNumSamples() >= MAX_SAMPLES) Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -440,7 +440,7 @@ // Read song comments: "text" if(file.ReadMagic("text")) { - ReadMessage(file, file.ReadUint32LE(), leCR); + songMessage.Read(file, file.ReadUint32LE(), SongMessage::leCR); madeWith |= verConfirmed; } @@ -866,13 +866,13 @@ if(!compatibilityExport) { // Writing song comments - if ((m_lpszSongComments) && (m_lpszSongComments[0])) + if(!songMessage.empty()) { DWORD d = 0x74786574; fwrite(&d, 1, 4, f); - d = strlen(m_lpszSongComments); + d = songMessage.length(); fwrite(&d, 1, 4, f); - fwrite(m_lpszSongComments, 1, d, f); + fwrite(songMessage.c_str(), 1, d, f); } // Writing midi cfg if (m_SongFlags[SONG_EMBEDMIDICFG]) Modified: trunk/OpenMPT/soundlib/Message.cpp =================================================================== --- trunk/OpenMPT/soundlib/Message.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Message.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -14,59 +14,25 @@ #include "stdafx.h" -#include "Sndfile.h" +#include "Message.h" +#include "FileReader.h" -// Allocate memory for song message. -// [in] length: text length in characters, without possible trailing null terminator. -// [out] returns true on success. -bool CSoundFile::AllocateMessage(size_t length) -//--------------------------------------------- -{ - FreeMessage(); - try - { - if(length == Util::MaxValueOfType(length)) - { - return false; - } - length++; // + 1 for trailing null - m_lpszSongComments = new char[length]; - memset(m_lpszSongComments, 0, length); - return true; - } catch(MPTMemoryException) - { - m_lpszSongComments = nullptr; - return false; - } -} - - -// Free previously allocated song message memory -void CSoundFile::FreeMessage() -//---------------------------- -{ - delete[] m_lpszSongComments; - m_lpszSongComments = nullptr; -} - - // Read song message from a mapped file. // [in] data: pointer to the data in memory that is going to be read // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). // [in] lineEnding: line ending formatting of the text in memory. // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). // [out] returns true on success. -bool CSoundFile::ReadMessage(const BYTE *data, size_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &)) -//---------------------------------------------------------------------------------------------------------------------- +bool SongMessage::Read(const void *data, size_t length, LineEnding lineEnding, ConverterFunc pTextConverter) +//---------------------------------------------------------------------------------------------------------- { - while(length != 0 && data[length - 1] == '\0') + const char *str = static_cast<const char *>(data); + while(length != 0 && str[length - 1] == '\0') { // Ignore trailing null character. length--; } - char c; - // Simple line-ending detection algorithm. VERY simple. if(lineEnding == leAutodetect) { @@ -75,7 +41,7 @@ // find CRs, LFs and CRLFs for(size_t i = 0; i < length; i++) { - c = data[i]; + char c = str[i]; if(pTextConverter != nullptr) pTextConverter(c); @@ -100,7 +66,7 @@ // calculate the final amount of characters to be allocated. for(size_t i = 0; i < length; i++) { - c = data[i]; + char c = str[i]; if(pTextConverter != nullptr) pTextConverter(c); @@ -108,13 +74,12 @@ finalLength++; } - if(!AllocateMessage(finalLength)) - return false; + resize(finalLength); size_t cpos = 0; for(size_t i = 0; i < length; i++, cpos++) { - c = data[i]; + char c = str[i]; if(pTextConverter != nullptr) pTextConverter(c); @@ -122,22 +87,22 @@ { case '\r': if(lineEnding != leLF) - m_lpszSongComments[cpos] = INTERNAL_LINEENDING; + at(cpos) = INTERNAL_LINEENDING; else - m_lpszSongComments[cpos] = ' '; + at(cpos) = ' '; if(lineEnding == leCRLF) i++; // skip the LF break; case '\n': if(lineEnding != leCR && lineEnding != leCRLF) - m_lpszSongComments[cpos] = INTERNAL_LINEENDING; + at(cpos) = INTERNAL_LINEENDING; else - m_lpszSongComments[cpos] = ' '; + at(cpos) = ' '; break; case '\0': - m_lpszSongComments[cpos] = ' '; + at(cpos) = ' '; break; default: - m_lpszSongComments[cpos] = c; + at(cpos) = c; break; } } @@ -146,6 +111,16 @@ } +bool SongMessage::Read(FileReader &file, const size_t length, LineEnding lineEnding, ConverterFunc pTextConverter) +//---------------------------------------------------------------------------------------------------------------- +{ + FileReader::off_t readLength = std::min(static_cast<FileReader::off_t>(length), file.BytesLeft()); + bool success = Read(file.GetRawData(), readLength, lineEnding, pTextConverter); + file.Skip(readLength); + return success; +} + + // Read comments with fixed line length from a mapped file. // [in] data: pointer to the data in memory that is going to be read // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). @@ -153,34 +128,35 @@ // [in] lineEndingLength: The padding space between two fixed lines. (there could for example be a null char after every line) // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). // [out] returns true on success. -bool CSoundFile::ReadFixedLineLengthMessage(const BYTE *data, const size_t length, const size_t lineLength, const size_t lineEndingLength, void (*pTextConverter)(char &)) -//------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +bool SongMessage::ReadFixedLineLength(const void *data, const size_t length, const size_t lineLength, const size_t lineEndingLength, ConverterFunc pTextConverter) +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- { + const char *str = static_cast<const char *>(data); if(lineLength == 0) return false; const size_t numLines = (length / (lineLength + lineEndingLength)); const size_t finalLength = numLines * (lineLength + 1); - if(!AllocateMessage(finalLength)) - return false; + clear(); + reserve(finalLength); for(size_t line = 0, fpos = 0, cpos = 0; line < numLines; line++, fpos += (lineLength + lineEndingLength), cpos += (lineLength + 1)) { - memcpy(m_lpszSongComments + cpos, data + fpos, std::min(lineLength, length - fpos)); - m_lpszSongComments[cpos + lineLength] = INTERNAL_LINEENDING; + append(str + fpos, std::min(lineLength, length - fpos)); + at(cpos + lineLength) = INTERNAL_LINEENDING; // fix weird chars for(size_t lpos = 0; lpos < lineLength; lpos++) { // Pre-process text - if(pTextConverter != nullptr) pTextConverter(m_lpszSongComments[cpos + lpos]); + if(pTextConverter != nullptr) pTextConverter(at(cpos + lpos)); - switch(m_lpszSongComments[cpos + lpos]) + switch(at(cpos + lpos)) { case '\0': case '\n': case '\r': - m_lpszSongComments[cpos + lpos] = ' '; + at(cpos + lpos) = ' '; break; } @@ -190,46 +166,57 @@ } +bool SongMessage::ReadFixedLineLength(FileReader &file, const size_t length, const size_t lineLength, const size_t lineEndingLength, ConverterFunc pTextConverter) +//---------------------------------------------------------------------------------------------------------------------------------------------------------------- +{ + FileReader::off_t readLength = std::min(static_cast<FileReader::off_t>(length), file.BytesLeft()); + bool success = ReadFixedLineLength(file.GetRawData(), readLength, lineLength, lineEndingLength, pTextConverter); + file.Skip(readLength); + return success; +} + + // Retrieve song message. // [in] lineEnding: line ending formatting of the text in memory. // [in] pTextConverter: Pointer to a callback function which can be used to post-process the written characters, if necessary (nullptr otherwise). // [out] returns formatted song message. -mpt::String CSoundFile::GetSongMessage(const enmLineEndings lineEnding, void (*pTextConverter)(char &)) const -//------------------------------------------------------------------------------------------------------- +std::string SongMessage::GetFormatted(const LineEnding lineEnding, ConverterFunc pTextConverter) const +//---------------------------------------------------------------------------------------------------- { - mpt::String comments; + std::string comments; - if(m_lpszSongComments == nullptr) + if(empty()) { return comments; } - const size_t len = strlen(m_lpszSongComments); - comments.reserve(len); + const size_t len = length(); + comments.resize(len); + size_t writePos = 0; for(size_t i = 0; i < len; i++) { - if(m_lpszSongComments[i] == INTERNAL_LINEENDING) + if(at(i) == INTERNAL_LINEENDING) { switch(lineEnding) { case leCR: default: - comments.append(1, '\r'); + comments.at(writePos++) = '\r'; break; case leCRLF: - comments.append(1, 'r'); + comments.at(writePos++) = '\r'; // Intentional fall-through case leLF: - comments.append(1, '\n'); + comments.at(writePos++) = '\n'; break; } } else { - char c = m_lpszSongComments[i]; + char c = at(i); // Pre-process text if(pTextConverter != nullptr) pTextConverter(c); - comments.append(1, c); + comments.at(writePos++) = c; } } return comments; Added: trunk/OpenMPT/soundlib/Message.h =================================================================== --- trunk/OpenMPT/soundlib/Message.h (rev 0) +++ trunk/OpenMPT/soundlib/Message.h 2013-04-12 17:43:54 UTC (rev 1866) @@ -0,0 +1,64 @@ +/* + * Message.h + * --------- + * Purpose: Various functions for processing song messages (allocating, reading from file...) + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include <string> + +class FileReader; + +//==================================== +class SongMessage : public std::string +//==================================== +{ +public: + + typedef void (*ConverterFunc)(char &); + + // Line ending types (for reading song messages from module files) + enum LineEnding + { + leCR, // Carriage Return (0x0D, \r) + leLF, // Line Feed (0x0A \n) + leCRLF, // Carriage Return, Line Feed (0x0D0A, \r\n) + leMixed, // It is not defined whether Carriage Return or Line Feed is the actual line ending. Both are accepted. + leAutodetect, // Detect suitable line ending + }; + + enum + { + INTERNAL_LINEENDING = '\r', // The character that represents line endings internally + }; + + // Read song message from a mapped file. + // [in] data: pointer to the data in memory that is going to be read + // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). + // [in] lineEnding: line ending formatting of the text in memory. + // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). + // [out] returns true on success. + bool Read(const void *data, const size_t length, LineEnding lineEnding, ConverterFunc pTextConverter = nullptr); + bool Read(FileReader &file, const size_t length, LineEnding lineEnding, ConverterFunc pTextConverter = nullptr); + + // Read comments with fixed line length from a mapped file. + // [in] data: pointer to the data in memory that is going to be read + // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). + // [in] lineLength: The fixed length of a line. + // [in] lineEndingLength: The padding space between two fixed lines. (there could for example be a null char after every line) + // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). + // [out] returns true on success. + bool ReadFixedLineLength(const void *data, const size_t length, const size_t lineLength, const size_t lineEndingLength, ConverterFunc pTextConverter = nullptr); + bool ReadFixedLineLength(FileReader &file, const size_t length, const size_t lineLength, const size_t lineEndingLength, ConverterFunc pTextConverter = nullptr); + + // Retrieve song message. + // [in] lineEnding: line ending formatting of the text in memory. + // [in] pTextConverter: Pointer to a callback function which can be used to post-process the written characters, if necessary (nullptr otherwise). + // [out] returns formatted song message. + std::string GetFormatted(const LineEnding lineEnding, ConverterFunc pTextConverter = nullptr) const; +}; Modified: trunk/OpenMPT/soundlib/ModSequence.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/ModSequence.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -17,6 +17,7 @@ #include "../common/version.h" #include "../common/serialization_utils.h" #include "../common/Reporting.h" +#include "FileReader.h" #include <functional> #define str_SequenceTruncationNote (GetStrI18N((_TEXT("Module has sequence of length %u; it will be truncated to maximum supported length, %u.")))) Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -16,9 +16,10 @@ #endif // MODPLUG_TRACKER #include "../common/version.h" #include "../common/serialization_utils.h" -#include "sndfile.h" +#include "Sndfile.h" #include "tuningcollection.h" #include "../common/StringFixer.h" +#include "FileReader.h" #ifndef NO_COPYRIGHT #ifndef NO_MMCMP_SUPPORT @@ -432,7 +433,6 @@ m_nMixChannels = 0; m_nSamples = 0; m_nInstruments = 0; - m_lpszSongComments = nullptr; m_nFreqFactor = m_nTempoFactor = 128; m_nMinPeriod = MIN_PERIOD; m_nMaxPeriod = 0x7FFF; @@ -529,7 +529,6 @@ m_nSamplePreAmp = 48; m_nVSTiVolume = 48; m_nMaxOrderPosition = 0; - m_lpszSongComments = nullptr; m_nMixLevels = mixLevels_compatible; // Will be overridden if appropriate. MemsetZero(ChnMix); MemsetZero(Instruments); @@ -538,6 +537,7 @@ //Order.assign(MAX_ORDERS, Order.GetInvalidPatIndex()); Order.resize(1); Patterns.ClearPatterns(); + songMessage.clear(); for (CHANNELINDEX nChn = 0; nChn < MAX_BASECHANNELS; nChn++) { @@ -647,9 +647,9 @@ #ifdef ZIPPED_MOD_SUPPORT // Read archive comment if there is no song comment - if((!m_lpszSongComments) && unzip.GetComments(false)) + if(!songMessage.empty() && unzip.GetComments(false)) { - m_lpszSongComments = (LPSTR)unzip.GetComments(true); + songMessage.assign(unzip.GetComments(true)); } #endif #ifdef MMCMP_SUPPORT @@ -835,7 +835,7 @@ Patterns.DestroyPatterns(); - FreeMessage(); + songMessage.clear(); for(SAMPLEINDEX i = 1; i < MAX_SAMPLES; i++) { Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-04-12 17:43:54 UTC (rev 1866) @@ -31,7 +31,7 @@ #include "modcommand.h" #include "plugins/PlugInterface.h" #include "RowVisitor.h" -#include "FileReader.h" +#include "Message.h" #include "Resampler.h" #include "../sounddsp/Reverb.h" @@ -65,17 +65,6 @@ #include "patternContainer.h" #include "ModSequence.h" - -// Line ending types (for reading song messages from module files) -enum enmLineEndings -{ - leCR, // Carriage Return (0x0D, \r) - leLF, // Line Feed (0x0A \n) - leCRLF, // Carriage Return, Line Feed (0x0D0A, \r\n) - leMixed, // It is not defined whether Carriage Return or Line Feed is the actual line ending. Both are accepted. - leAutodetect, // Detect suitable line ending -}; - #define INTERNAL_LINEENDING '\r' // The character that represents line endings internally @@ -310,7 +299,6 @@ LONG m_nRepeatCount; // -1 means repeat infinitely. DWORD m_nGlobalFadeSamples, m_nGlobalFadeMaxSamples; UINT m_nMaxOrderPosition; - LPSTR m_lpszSongComments; UINT ChnMix[MAX_CHANNELS]; // Channels to be mixed ModChannel Chn[MAX_CHANNELS]; // Mixing channels... First m_nChannel channels are master channels (i.e. they are never NNA channels)! ModChannelSettings ChnSettings[MAX_BASECHANNELS]; // Initial channels settings @@ -336,6 +324,9 @@ // For handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav. RowVisitor visitedSongRows; + // Song message + SongMessage songMessage; + // -> CODE#0023 // -> DESC="IT project files (.itp)" mpt::String m_szInstrumentPath[MAX_INSTRUMENTS]; @@ -682,54 +673,6 @@ // WAV export UINT Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lmax24, DWORD dwByteInc); - // Song message helper functions -public: - // Allocate memory for song message. - // [in] length: text length in characters, without possible trailing null terminator. - // [out] returns true on success. - bool AllocateMessage(size_t length); - - // Free previously allocated song message memory. - void FreeMessage(); - - // Retrieve song message. - // [in] lineEnding: line ending formatting of the text in memory. - // [in] pTextConverter: Pointer to a callback function which can be used to post-process the written characters, if necessary (nullptr otherwise). - // [out] returns formatted song message. - mpt::String GetSongMessage(const enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr) const; - -protected: - // Read song message from a mapped file. - // [in] data: pointer to the data in memory that is going to be read - // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). - // [in] lineEnding: line ending formatting of the text in memory. - // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). - // [out] returns true on success. - bool ReadMessage(const BYTE *data, FileReader::off_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr); - bool ReadMessage(FileReader &file, FileReader::off_t length, enmLineEndings lineEnding, void (*pTextConverter)(char &) = nullptr) - { - FileReader::off_t readLength = std::min(length, file.BytesLeft()); - bool success = ReadMessage(reinterpret_cast<const BYTE*>(file.GetRawData()), readLength, lineEnding, pTextConverter); - file.Skip(readLength); - return success; - } - - // Read comments with fixed line length from a mapped file. - // [in] data: pointer to the data in memory that is going to be read - // [in] length: number of characters that should be read, not including a possible trailing null terminator (it is automatically appended). - // [in] lineLength: The fixed length of a line. - // [in] lineEndingLength: The padding space between two fixed lines. (there could for example be a null char after every line) - // [in] pTextConverter: Pointer to a callback function which can be used to pre-process the read characters, if necessary (nullptr otherwise). - // [out] returns true on success. - bool ReadFixedLineLengthMessage(const BYTE *data, const FileReader::off_t length, const size_t lineLength, const size_t lineEndingLength, void (*pTextConverter)(char &) = nullptr); - bool ReadFixedLineLengthMessage(FileReader &file, const FileReader::off_t length, const size_t lineLength, const size_t lineEndingLength, void (*pTextConverter)(char &) = nullptr) - { - FileReader::off_t readLength = std::min(length, file.BytesLeft()); - bool success = ReadFixedLineLengthMessage(reinterpret_cast<const BYTE*>(file.GetRawData()), readLength, lineLength, lineEndingLength, pTextConverter); - file.Skip(readLength); - return success; - } - private: PLUGINDEX GetChannelPlugin(CHANNELINDEX nChn, PluginMutePriority respectMutes) const; PLUGINDEX GetActiveInstrumentPlugin(CHANNELINDEX, PluginMutePriority respectMutes) const; Modified: trunk/OpenMPT/unzip/unzip.cpp =================================================================== --- trunk/OpenMPT/unzip/unzip.cpp 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/unzip/unzip.cpp 2013-04-12 17:43:54 UTC (rev 1866) @@ -205,8 +205,8 @@ } -void *CZipArchive::GetComments(bool get) -//-------------------------------------- +const char *CZipArchive::GetComments(bool get) +//-------------------------------------------- { unz_global_info info; if(zipFile == nullptr || unzGetGlobalInfo(zipFile, &info) != UNZ_OK) @@ -216,7 +216,7 @@ if(!get) { - return reinterpret_cast<void *>((info.size_comment > 0) ? 1 : 0); + return reinterpret_cast<char *>((info.size_comment > 0) ? 1 : 0); } else if(info.size_comment > 0) { if(info.size_comment < Util::MaxValueOfType(info.size_comment)) Modified: trunk/OpenMPT/unzip/unzip.h =================================================================== --- trunk/OpenMPT/unzip/unzip.h 2013-04-12 17:05:17 UTC (rev 1865) +++ trunk/OpenMPT/unzip/unzip.h 2013-04-12 17:43:54 UTC (rev 1866) @@ -23,7 +23,7 @@ FileReader GetOutputFile() const { return outFile; } bool IsArchive() const; bool ExtractFile(); - void *GetComments(bool get); + const char *GetComments(bool get); CZipArchive(FileReader &file, const std::vector<const char *> &ext); ~CZipArchive(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |