From: <sag...@us...> - 2014-11-08 23:30:42
|
Revision: 4566 http://sourceforge.net/p/modplug/code/4566 Author: saga-games Date: 2014-11-08 23:30:27 +0000 (Sat, 08 Nov 2014) Log Message: ----------- [Imp] libopenmpt: Add support for hidden subsongs. They are added completely transparently to the already existing subsong functionality. [Imp] xmp-openmpt: Added subsong support. Modified Paths: -------------- trunk/OpenMPT/libopenmpt/libopenmpt.hpp trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp trunk/OpenMPT/libopenmpt/xmp-openmpt.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/soundlib/RowVisitor.cpp trunk/OpenMPT/soundlib/RowVisitor.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/libopenmpt/libopenmpt.hpp =================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt.hpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/libopenmpt/libopenmpt.hpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -196,7 +196,7 @@ RENDER_VOLUMERAMPING_STRENGTH = 4 }; - //! Parameter index to use with get_pattern_row_channel_command, format_pattern_row_channel_command and highlight_pattern_row_channel_command + //! Parameter index to use with openmpt::module::get_pattern_row_channel_command, openmpt::module::format_pattern_row_channel_command and openmpt::module::highlight_pattern_row_channel_command enum command_index { command_note = 0, command_instrument = 1, @@ -317,7 +317,7 @@ //! Get approximate song duration /*! - \return Approximate song duration in seconds. + \return Approximate duration of current subsong in seconds. */ double get_duration_seconds() const; @@ -328,9 +328,9 @@ \sa openmpt::module::get_position_seconds */ double set_position_seconds( double seconds ); - //! Get approximate current song position + //! Get current song position /*! - \return Approximate current song position in seconds. + \return Current song position in seconds. \sa openmpt::module::set_position_seconds */ double get_position_seconds() const; @@ -593,7 +593,7 @@ //! Get the number of rows in a pattern /*! - \param order The pattern whose row count should be retrieved. + \param pattern The pattern whose row count should be retrieved. \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned. */ std::int32_t get_pattern_num_rows( std::int32_t pattern ) const; @@ -603,9 +603,8 @@ \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. - \param command The cell index at which the data should be retrieved. + \param command The cell index at which the data should be retrieved. See openmpt::module::command_index \return The internal, raw pattern data at the given pattern position. - \sa openmpt::module::command_index */ std::uint8_t get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; @@ -615,8 +614,8 @@ \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. \param command The cell index at which the data should be retrieved. - \return The formatted pattern data at the given pattern position. - \sa openmpt::module::command_index + \return The formatted pattern data at the given pattern position. See openmpt::module::command_index + \sa openmpt::module::highlight_pattern_row_channel_command */ std::string format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; @@ -625,7 +624,7 @@ \param pattern The pattern whose data should be retrieved. \param row The row from which the data should be retrieved. \param channel The channel from which the data should be retrieved. - \param command The cell index at which the data should be retrieved. + \param command The cell index at which the data should be retrieved. See openmpt::module::command_index \return The highlighting string for the formatted pattern data as retrived by openmpt::module::get_pattern_row_channel_command at the given pattern position. \remarks The returned string will map each character position of the string returned by openmpt::module::get_pattern_row_channel_command to a highlighting instruction. Possible highlighting characters are: @@ -638,7 +637,7 @@ - "v" : generic volume column parameter - "e" : generic effect column effect - "f" : generic effect column parameter - \sa openmpt::module::command_index + \sa openmpt::module::get_pattern_row_channel_command */ std::string highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; @@ -650,6 +649,7 @@ \param width The maximum number of characters the string should contain. 0 means no limit. \param pad If true, the string will be resized to the exact length provided in the width parameter. \return The formatted pattern data at the given pattern position. + \sa openmpt::module::highlight_pattern_row_channel */ std::string format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; //! Get highlighting information for formatted pattern content @@ -660,7 +660,7 @@ \param width The maximum number of characters the string should contain. 0 means no limit. \param pad If true, the string will be resized to the exact length provided in the width parameter. \return The highlighting string for the formatted pattern data as retrived by openmpt::module::format_pattern_row_channel at the given pattern position. - \sa openmpt::module::format_pattern_row_channel_command + \sa openmpt::module::format_pattern_row_channel */ std::string highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; @@ -673,9 +673,9 @@ - seek.sync_samples: Set to "1" to sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row. - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt::module::read. Supported values are: - 0: No dithering. - - 1: Default mode. Chosen by OpenMPT code, might change. - - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). - - 3: Rectangular, 1 bit depth, simple 1st order noise shaping + - 1: Default mode. Chosen by OpenMPT code, might change. + - 2: Rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker). + - 3: Rectangular, 1 bit depth, simple 1st order noise shaping */ std::vector<std::string> get_ctls() const; @@ -689,7 +689,7 @@ //! Set ctl value /*! \param ctl The ctl key whose value should be set. - \param The value that should be set. + \param value The value that should be set. \sa openmpt::module::get_ctls */ void ctl_set( const std::string & ctl, const std::string & value ); Modified: trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp =================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -325,6 +325,8 @@ m_ctl_load_skip_samples = false; m_ctl_load_skip_patterns = false; m_ctl_seek_sync_samples = false; + m_current_subsong = 0; + m_sndFile->Order.SetSequence( 0 ); for ( std::map< std::string, std::string >::const_iterator i = ctls.begin(); i != ctls.end(); ++i ) { ctl_set( i->first, i->second ); } @@ -692,18 +694,26 @@ double module_impl::get_duration_seconds() const { + cache_subsongs(); + if ( m_current_subsong >= 0 && m_current_subsong < static_cast<std::int32_t>( m_subsongs.size() ) ) { + return m_subsongs[m_current_subsong].duration; + } return m_sndFile->GetLength( eNoAdjust ).back().duration; } void module_impl::select_subsong( std::int32_t subsong ) { - if ( subsong < -1 || subsong >= m_sndFile->Order.GetNumSequences() ) { + cache_subsongs(); + if ( subsong < -1 || subsong >= static_cast<std::int32_t>( m_subsongs.size() ) ) { return; } if ( subsong == -1 ) { // default subsong - m_sndFile->Order.SetSequence( 0 ); - return; + subsong = 0; } - m_sndFile->Order.SetSequence( subsong ); + + m_current_subsong = subsong; + m_sndFile->Order.SetSequence( static_cast<SEQUENCEINDEX>( m_subsongs[subsong].sequence ) ); + set_position_order_row( m_subsongs[subsong].start_order, m_subsongs[subsong].start_row ); + } void module_impl::set_repeat_count( std::int32_t repeat_count ) { m_sndFile->SetRepeatCount( repeat_count ); @@ -715,12 +725,13 @@ return m_currentPositionSeconds; } double module_impl::set_position_seconds( double seconds ) { - GetLengthType t = m_sndFile->GetLength( eNoAdjust, GetLengthTarget( seconds ) ).back(); + const subsong_data &subsong = m_subsongs[m_current_subsong]; + GetLengthType t = m_sndFile->GetLength( eNoAdjust, GetLengthTarget( seconds ).StartPos( subsong.sequence, subsong.start_order, subsong.start_row ) ).back(); m_sndFile->InitializeVisitedRows(); m_sndFile->m_PlayState.m_nCurrentOrder = t.lastOrder; m_sndFile->SetCurrentOrder( t.lastOrder ); m_sndFile->m_PlayState.m_nNextRow = t.lastRow; - m_currentPositionSeconds = m_sndFile->GetLength( m_ctl_seek_sync_samples ? eAdjustSamplePositions : eAdjust, GetLengthTarget( t.lastOrder, t.lastRow ) ).back().duration; + m_currentPositionSeconds = m_sndFile->GetLength( m_ctl_seek_sync_samples ? eAdjustSamplePositions : eAdjust, GetLengthTarget( t.lastOrder, t.lastRow ).StartPos( subsong.sequence, subsong.start_order, subsong.start_row ) ).back().duration; return m_currentPositionSeconds; } double module_impl::set_position_order_row( std::int32_t order, std::int32_t row ) { @@ -885,7 +896,8 @@ } std::int32_t module_impl::get_num_subsongs() const { - return m_sndFile->Order.GetNumSequences(); + cache_subsongs(); + return static_cast<std::int32_t>( m_subsongs.size() ); } std::int32_t module_impl::get_num_channels() const { return m_sndFile->GetNumChannels(); @@ -904,9 +916,10 @@ } std::vector<std::string> module_impl::get_subsong_names() const { + cache_subsongs(); std::vector<std::string> retval; - for ( SEQUENCEINDEX i = 0; i < m_sndFile->Order.GetNumSequences(); ++i ) { - retval.push_back( mod_string_to_utf8( m_sndFile->Order.GetSequence( i ).GetName() ) ); + for ( std::size_t i = 0; i < m_subsongs.size(); ++i ) { + retval.push_back( mod_string_to_utf8( m_sndFile->Order.GetSequence( m_subsongs[i].sequence ).GetName() ) ); } return retval; } @@ -1177,4 +1190,19 @@ } } +void module_impl::cache_subsongs() const { + if ( !m_subsongs.empty() ) { + return; + } + + m_subsongs.reserve( m_sndFile->Order.GetNumSequences() ); + + for ( SEQUENCEINDEX seq = 0; seq < m_sndFile->Order.GetNumSequences(); ++seq ) { + const std::vector<GetLengthType> lengths = m_sndFile->GetLength( eNoAdjust, GetLengthTarget( true ).StartPos( seq, 0, 0 ) ); + for ( std::vector<GetLengthType>::const_iterator l = lengths.begin(); l != lengths.end(); ++l ) { + m_subsongs.push_back( subsong_data( l->duration, l->startRow, l->startOrder, seq ) ); + } + } +} + } // namespace openmpt Modified: trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp =================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -57,6 +57,16 @@ class log_forwarder; +class subsong_data { +public: + double duration; + std::int32_t start_row; + std::int32_t start_order; + std::int32_t sequence; + + subsong_data( double duration, std::int32_t start_row, std::int32_t start_order, std::int32_t sequence ) : duration(duration), start_row(start_row), start_order(start_order), sequence(sequence) { } +}; + class module_impl { protected: #ifdef LIBOPENMPT_ANCIENT_COMPILER @@ -85,6 +95,8 @@ bool m_ctl_load_skip_patterns; bool m_ctl_seek_sync_samples; std::vector<std::string> m_loaderMessages; + mutable std::vector<subsong_data> m_subsongs; + std::int32_t m_current_subsong; public: void PushToCSoundFileLog( const std::string & text ) const; void PushToCSoundFileLog( int loglevel, const std::string & text ) const; @@ -101,6 +113,7 @@ std::size_t read_interleaved_wrapper( std::size_t count, std::size_t channels, float * interleaved ); std::pair< std::string, std::string > format_and_highlight_pattern_row_channel_command( std::int32_t p, std::int32_t r, std::int32_t c, int command ) const; std::pair< std::string, std::string > format_and_highlight_pattern_row_channel( std::int32_t p, std::int32_t r, std::int32_t c, std::size_t width, bool pad ) const; + void cache_subsongs() const; public: static std::vector<std::string> get_supported_extensions(); static bool is_extension_supported( const std::string & extension ); Modified: trunk/OpenMPT/libopenmpt/xmp-openmpt.cpp =================================================================== --- trunk/OpenMPT/libopenmpt/xmp-openmpt.cpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/libopenmpt/xmp-openmpt.cpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -97,6 +97,7 @@ static void apply_and_save_options(); struct self_xmplay_t { + std::vector<float> subsong_lengths; std::size_t samplerate; std::size_t num_channels; openmpt::settings::settings settings; @@ -161,6 +162,21 @@ return &decoded_string[0]; } +static std::string seconds_to_string( float time ) { + std::int64_t time_ms = static_cast<std::int64_t>( time * 1000 ); + std::int64_t seconds = ( time_ms / 1000 ) % 60; + std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 60; + std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) ); + std::ostringstream str; + if ( hours > 0 ) { + str << hours << ":"; + } + str << std::setfill('0') << std::setw(2) << minutes; + str << ":"; + str << std::setfill('0') << std::setw(2) << seconds; + return str.str(); +} + static void save_settings_to_map( std::map<std::string,int> & result, const openmpt::settings::settings & s ) { result.clear(); result[ "Samplerate_Hz" ] = s.samplerate; @@ -763,7 +779,16 @@ apply_options(); self->samplerate = self->settings.samplerate; self->num_channels = self->settings.channels; - xmpfin->SetLength( static_cast<float>( self->mod->get_duration_seconds() ), TRUE ); + + std::int32_t num_subsongs = self->mod->get_num_subsongs(); + self->subsong_lengths.resize( num_subsongs ); + for ( std::int32_t i = 0; i < num_subsongs; ++i ) { + self->mod->select_subsong( i ); + self->subsong_lengths[i] = static_cast<float>( self->mod->get_duration_seconds() ); + } + self->mod->select_subsong( -1 ); + + xmpfin->SetLength( self->subsong_lengths[0], TRUE ); return 2; } catch ( ... ) { self->delete_mod(); @@ -898,7 +923,17 @@ << "Orders" << "\t" << self->mod->get_num_orders() << "\r" << "Patterns" << "\t" << self->mod->get_num_patterns() << "\r" << "Instruments" << "\t" << self->mod->get_num_instruments() << "\r" - << "Samples" << "\t" << self->mod->get_num_samples() << "\r" + << "Samples" << "\t" << self->mod->get_num_samples() << "\r"; + + if( self->subsong_lengths.size() > 1 ) { + std::vector<std::string> names = self->mod->get_subsong_names(); + + for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) { + str << ( i == 0 ? "Subsongs\t" : "\t" ) << (i + 1) << ". " << seconds_to_string( self->subsong_lengths[i]) << " " << names[i] << "\r"; + } + } + + str << "\r" << "Tracker" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("tracker") ) << "\r" << "Player" << "\t" << "xmp-openmpt" << " version " << openmpt::string::get( openmpt::string::library_version ) << "\r" @@ -927,6 +962,14 @@ if ( !self->mod ) { return -1.0; } + + if ( pos & XMPIN_POS_SUBSONG ) { + self->mod->select_subsong( pos & 0xffff ); + xmpfin->SetLength( self->subsong_lengths[pos & 0xffff], TRUE ); + reset_timeinfos( 0 ); + return 0.0; + } + double new_position = self->mod->set_position_seconds( static_cast<double>( pos ) * 0.001 ); reset_timeinfos( new_position ); return new_position; @@ -1016,6 +1059,15 @@ write_xmplay_string( buf, str.str() ); } +static DWORD WINAPI openmpt_GetSubSongs( float * length ) { + *length = 0.0; + for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) { + *length += self->subsong_lengths[i]; + } + + return static_cast<DWORD>( self->subsong_lengths.size() ); +} + #ifdef EXPERIMENTAL_VIS enum ColorIndex @@ -1432,7 +1484,7 @@ openmpt_Process, NULL, // WriteFile openmpt_GetSamples, - NULL, // GetSubSongs + openmpt_GetSubSongs, // GetSubSongs NULL, // GetCues NULL, // GetDownloaded Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -2228,16 +2228,16 @@ { if(lengths.size() > 1) { - s.AppendFormat(_T("\nSong %u, starting at order %u: "), i, lengths[i].startOrder); + s.AppendFormat(_T("\nSong %u, starting at order %u: "), i + 1, lengths[i].startOrder); } double songLength = lengths[i].duration; if(songLength != std::numeric_limits<double>::infinity()) { songLength = Util::Round(songLength); - s.AppendFormat("%.0fmn%02.0fs", std::floor(songLength / 60.0), std::fmod(songLength, 60.0)); + s.AppendFormat(_T("%.0fmn%02.0fs"), std::floor(songLength / 60.0), std::fmod(songLength, 60.0)); } else { - s += "Song too long!"; + s += _T("Song too long!"); } } Modified: trunk/OpenMPT/soundlib/RowVisitor.cpp =================================================================== --- trunk/OpenMPT/soundlib/RowVisitor.cpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/soundlib/RowVisitor.cpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -28,10 +28,15 @@ // Resize / Clear the row vector. // If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset). -void RowVisitor::Initialize(bool reset) -//------------------------------------- +void RowVisitor::Initialize(bool reset, SEQUENCEINDEX sequence) +//------------------------------------------------------------- { - const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + if(sequence < sndFile.Order.GetNumSequences()) + Order = &sndFile.Order.GetSequence(sequence); + else + Order = &sndFile.Order; + + const ORDERINDEX endOrder = Order->GetLengthTailTrimmed(); visitedRows.resize(endOrder); if(reset) { @@ -41,7 +46,7 @@ for(ORDERINDEX order = 0; order < endOrder; order++) { VisitedRowsBaseType &row = visitedRows[order]; - const size_t size = GetVisitedRowsVectorSize(sndFile.Order[order]); + const size_t size = GetVisitedRowsVectorSize(Order->At(order)); if(reset) { // If we want to reset the vectors completely, we overwrite existing items with false. @@ -60,8 +65,8 @@ void RowVisitor::SetVisited(ORDERINDEX order, ROWINDEX row, bool visited) //----------------------------------------------------------------------- { - const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); - if(order >= endOrder || row >= GetVisitedRowsVectorSize(sndFile.Order[order])) + const ORDERINDEX endOrder = Order->GetLengthTailTrimmed(); + if(order >= endOrder || row >= GetVisitedRowsVectorSize(Order->At(order))) { return; } @@ -86,7 +91,7 @@ bool RowVisitor::IsVisited(ORDERINDEX order, ROWINDEX row, bool autoSet) //---------------------------------------------------------------------- { - const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + const ORDERINDEX endOrder = Order->GetLengthTailTrimmed(); if(order >= endOrder) { return false; @@ -138,10 +143,10 @@ bool RowVisitor::GetFirstUnvisitedRow(ORDERINDEX &order, ROWINDEX &row, bool fastSearch) const //-------------------------------------------------------------------------------------------- { - const ORDERINDEX endOrder = sndFile.Order.GetLengthTailTrimmed(); + const ORDERINDEX endOrder = Order->GetLengthTailTrimmed(); for(order = 0; order < endOrder; order++) { - const PATTERNINDEX pattern = sndFile.Order[order]; + const PATTERNINDEX pattern = Order->At(order); if(!sndFile.Patterns.IsValidPat(pattern)) { continue; @@ -197,7 +202,7 @@ { // We're in a new pattern! Forget about which rows we previously visited... visitOrder.clear(); - visitOrder.reserve(GetVisitedRowsVectorSize(sndFile.Order[order])); + visitOrder.reserve(GetVisitedRowsVectorSize(Order->At(order))); currentOrder = order; } // And now add the played row to our memory. Modified: trunk/OpenMPT/soundlib/RowVisitor.h =================================================================== --- trunk/OpenMPT/soundlib/RowVisitor.h 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/soundlib/RowVisitor.h 2014-11-08 23:30:27 UTC (rev 4566) @@ -16,6 +16,7 @@ OPENMPT_NAMESPACE_BEGIN class CSoundFile; +class ModSequence; //============== class RowVisitor @@ -28,6 +29,7 @@ typedef std::vector<VisitedRowsBaseType> VisitedRowsType; const CSoundFile &sndFile; + const ModSequence *Order; // Memory for every row in the module if it has been visited or not. VisitedRowsType visitedRows; @@ -37,16 +39,16 @@ public: - RowVisitor(const CSoundFile &sf) : sndFile(sf), currentOrder(0) + RowVisitor(const CSoundFile &sf, SEQUENCEINDEX sequence = SEQUENCEINDEX_INVALID) : sndFile(sf), currentOrder(0) { - Initialize(true); + Initialize(true, sequence); }; - RowVisitor(const RowVisitor &other) : sndFile(other.sndFile), visitedRows(other.visitedRows), visitOrder(other.visitOrder), currentOrder(other.currentOrder) { }; + RowVisitor(const RowVisitor &other) : sndFile(other.sndFile), Order(other.Order), visitedRows(other.visitedRows), visitOrder(other.visitOrder), currentOrder(other.currentOrder) { }; // Resize / Clear the row vector. // If reset is true, the vector is not only resized to the required dimensions, but also completely cleared (i.e. all visited rows are unset). - void Initialize(bool reset); + void Initialize(bool reset, SEQUENCEINDEX sequence = SEQUENCEINDEX_INVALID); // Mark a row as visited. void Visit(ORDERINDEX order, ROWINDEX row) Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-11-08 23:30:27 UTC (rev 4566) @@ -106,29 +106,35 @@ // [out] endOrder: last order before module loops (UNDEFINED if a target is specified) // [out] endRow: last row before module loops (dito) std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target) -//------------------------------------------------------------------------------------------------------------ +//-------------------------------------------------------------------------------------------------------- { std::vector<GetLengthType> results; GetLengthType retval; + retval.startOrder = target.startOrder; + retval.startRow = target.startRow; // Are we trying to reach a certain pattern position? const bool hasSearchTarget = target.mode != GetLengthTarget::NoTarget; const bool adjustSamplePos = (adjustMode & eAdjustSamplePositions) == eAdjustSamplePositions; - ROWINDEX nRow = 0, nNextRow = 0; + ROWINDEX nRow = target.startRow, nNextRow = nRow; ROWINDEX nNextPatStartRow = 0; // FT2 E60 bug - ORDERINDEX nCurrentOrder = 0, nNextOrder = 0; + ORDERINDEX nCurrentOrder = target.startOrder, nNextOrder = nCurrentOrder; + SEQUENCEINDEX sequence = target.sequence; + if(sequence > Order.GetNumSequences()) sequence = Order.GetCurrentSequenceIndex(); + const ModSequence &orderList = Order.GetSequence(sequence); + GetLengthMemory memory(*this); // Temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time) - RowVisitor visitedRows(*this); + RowVisitor visitedRows(*this, sequence); // Optimize away channels for which it's pointless to adjust sample positions std::vector<bool> adjustSampleChn(GetNumChannels(), true); if(adjustSamplePos && target.mode == GetLengthTarget::SeekPosition) { PATTERNINDEX seekPat = PATTERNINDEX_INVALID; - if(target.pos.order < Order.GetLength()) seekPat = Order[target.pos.order]; + if(target.pos.order < orderList.GetLength()) seekPat = orderList[target.pos.order]; if(!Patterns.IsValidPat(seekPat) || !Patterns[seekPat].IsValidRow(target.pos.row)) seekPat = PATTERNINDEX_INVALID; for(CHANNELINDEX i = 0; i < GetNumChannels(); i++) @@ -156,16 +162,16 @@ nRow = nNextRow; nCurrentOrder = nNextOrder; - if(nCurrentOrder >= Order.size()) + if(nCurrentOrder >= orderList.size()) break; // Check if pattern is valid - PATTERNINDEX nPattern = Order[nCurrentOrder]; + PATTERNINDEX nPattern = orderList[nCurrentOrder]; bool positionJumpOnThisRow = false; bool patternBreakOnThisRow = false; bool patternLoopEndedOnThisRow = false, patternLoopStartedOnThisRow = false; - if(nPattern == Order.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && nCurrentOrder == target.pos.order) + if(nPattern == orderList.GetIgnoreIndex() && target.mode == GetLengthTarget::SeekPosition && nCurrentOrder == target.pos.order) { // Early test: Target is inside +++ pattern retval.targetReached = true; @@ -175,7 +181,7 @@ while(nPattern >= Patterns.Size()) { // End of song? - if((nPattern == Order.GetInvalidPatIndex()) || (nCurrentOrder >= Order.size())) + if((nPattern == orderList.GetInvalidPatIndex()) || (nCurrentOrder >= orderList.size())) { if(nCurrentOrder == m_nRestartPos) break; @@ -185,7 +191,7 @@ { nCurrentOrder++; } - nPattern = (nCurrentOrder < Order.size()) ? Order[nCurrentOrder] : Order.GetInvalidPatIndex(); + nPattern = (nCurrentOrder < orderList.size()) ? orderList[nCurrentOrder] : orderList.GetInvalidPatIndex(); nNextOrder = nCurrentOrder; if((!Patterns.IsValidPat(nPattern)) && visitedRows.IsVisited(nCurrentOrder, 0, true)) { @@ -204,7 +210,7 @@ nRow = nNextRow; nCurrentOrder = nNextOrder; - nPattern = Order[nCurrentOrder]; + nPattern = orderList[nCurrentOrder]; break; } } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2014-11-08 22:49:49 UTC (rev 4565) +++ trunk/OpenMPT/soundlib/Sndfile.h 2014-11-08 23:30:27 UTC (rev 4566) @@ -116,6 +116,10 @@ // Target seek mode for GetLength() struct GetLengthTarget { + ROWINDEX startRow; + ORDERINDEX startOrder; + SEQUENCEINDEX sequence; + union { double time; @@ -138,12 +142,18 @@ GetLengthTarget(bool allSongs = false) { mode = allSongs ? GetAllSubsongs : NoTarget; + sequence = SEQUENCEINDEX_INVALID; + startOrder = 0; + startRow = 0; } // Seek to given pattern position if position is valid. GetLengthTarget(ORDERINDEX order, ROWINDEX row) { mode = NoTarget; + sequence = SEQUENCEINDEX_INVALID; + startOrder = 0; + startRow = 0; if(order != ORDERINDEX_INVALID && row != ROWINDEX_INVALID) { mode = SeekPosition; @@ -156,12 +166,24 @@ GetLengthTarget(double t) { mode = NoTarget; + sequence = SEQUENCEINDEX_INVALID; + startOrder = 0; + startRow = 0; if(t >= 0.0) { mode = SeekSeconds; time = t; } } + + // Set start position from which seeking should begin. + GetLengthTarget &StartPos(SEQUENCEINDEX seq, ORDERINDEX order, ROWINDEX row) + { + sequence = seq; + startOrder = order; + startRow = row; + return *this; + } }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |