From: <sag...@us...> - 2014-11-09 18:23:38
|
Revision: 4575 http://sourceforge.net/p/modplug/code/4575 Author: saga-games Date: 2014-11-09 18:23:21 +0000 (Sun, 09 Nov 2014) Log Message: ----------- [New] libopenmpt: Added the possibility to play all subsongs consecutively by calling openmpt::module::select_subsong with value -1. [Imp] openmpt123: Play all subsongs consecutively. Modified Paths: -------------- trunk/OpenMPT/libopenmpt/dox/changelog.md trunk/OpenMPT/libopenmpt/libopenmpt.hpp trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp trunk/OpenMPT/openmpt123/openmpt123.cpp trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/libopenmpt/dox/changelog.md =================================================================== --- trunk/OpenMPT/libopenmpt/dox/changelog.md 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/libopenmpt/dox/changelog.md 2014-11-09 18:23:21 UTC (rev 4575) @@ -20,6 +20,12 @@ * [Bug] The -autotools tarballs were not working at all. * Vastly improved MT2 loader. + * Support for "hidden" subsongs has been added. + They are accessible through the same interface as ordinary subsongs, i.e. + use openmpt::module::select_subsong to switch between any kind of subsongs. + * All subsongs can now be played consecutively by passing -1 as the subsong + index in openmpt::module::select_subsong. + * Added documentation for a couple of more functions. ### 2014-09-07 - libopenmpt 0.2-beta7 Modified: trunk/OpenMPT/libopenmpt/libopenmpt.hpp =================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt.hpp 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/libopenmpt/libopenmpt.hpp 2014-11-09 18:23:21 UTC (rev 4575) @@ -221,7 +221,7 @@ /*! \param stream Input stream from which the module is loaded. After the constructor has finished successfully, the input position of stream is set to the byte after the last byte that has been read. If the constructor fails, the state of the input position of stream is undefined. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -229,7 +229,7 @@ /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -238,7 +238,7 @@ \param beg Begin of data to load the module from. \param end End of data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -247,7 +247,7 @@ \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -255,7 +255,7 @@ /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -264,7 +264,7 @@ \param beg Begin of data to load the module from. \param end End of data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -273,7 +273,7 @@ \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -282,7 +282,7 @@ \param data Data to load the module from. \param size Amount of data available. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. - \param ctls A map of initial ctl values, see openmpt::modules::get_ctls. + \param ctls A map of initial ctl values, see openmpt::module::get_ctls. \return Throw an exception derived from openmpt::exception in case the provided file cannot be opened. \remarks The input data can be discarded after an openmpt::module has been constructed succesfully. */ @@ -292,8 +292,8 @@ //! Select a subsong from a multi-song module /*! - \param subsong Index of the subsong. - \return Throws an exception derived from openmpt::exception if subsong is not in range [0,openmpt::module::get_num_subsongs()] + \param subsong Index of the subsong. -1 plays all subsongs consecutively. + \return Throws an exception derived from openmpt::exception if subsong is not in range [-1,openmpt::module::get_num_subsongs()[ */ void select_subsong( std::int32_t subsong ); //! Set Repeat Count Modified: trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp =================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/libopenmpt/libopenmpt_impl.cpp 2014-11-09 18:23:21 UTC (rev 4575) @@ -219,6 +219,15 @@ m_sndFile->AddToLog( static_cast<LogLevel>( loglevel ), mpt::ToUnicode( mpt::CharsetUTF8, text ) ); } +module_impl::subsong_data::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) +{ + return; +} + static ResamplingMode filterlength_to_resamplingmode(std::int32_t length) { if ( length == 0 ) { return SRCMODE_POLYPHASE; @@ -302,6 +311,7 @@ } void module_impl::apply_libopenmpt_defaults() { set_render_param( module::RENDER_STEREOSEPARATION_PERCENT, 100 ); + m_sndFile->Order.SetSequence( 0 ); } void module_impl::init( const std::map< std::string, std::string > & ctls ) { #ifdef LIBOPENMPT_ANCIENT_COMPILER @@ -326,7 +336,6 @@ 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 ); } @@ -697,22 +706,30 @@ 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; + } else if ( m_current_subsong == all_subsongs ) { + // Play all subsongs consecutively. + double total_duration = 0.0; + for ( std::size_t i = 0; i < m_subsongs.size(); ++i ) { + total_duration += m_subsongs[i].duration; + } + return total_duration; } return m_sndFile->GetLength( eNoAdjust ).back().duration; } void module_impl::select_subsong( std::int32_t subsong ) { cache_subsongs(); - if ( subsong < -1 || subsong >= static_cast<std::int32_t>( m_subsongs.size() ) ) { - return; + if ( ( subsong < 0 || subsong >= static_cast<std::int32_t>( m_subsongs.size() ) ) && subsong != all_subsongs ) { + throw openmpt::exception("invalid subsong"); } + m_current_subsong = subsong; + m_sndFile->m_SongFlags.set( SONG_PLAYALLSONGS, subsong == all_subsongs ); if ( subsong == -1 ) { - // default subsong subsong = 0; } - 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 ); + m_currentPositionSeconds = 0.0; } void module_impl::set_repeat_count( std::int32_t repeat_count ) { @@ -725,13 +742,28 @@ return m_currentPositionSeconds; } double module_impl::set_position_seconds( double seconds ) { - 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(); + const subsong_data *subsong; + double base_seconds = 0.0; + if ( m_current_subsong == all_subsongs ) { + // When playing all subsongs, find out which subsong this time would belong to. + for ( std::size_t i = 0; i < m_subsongs.size(); ++i ) { + subsong = &m_subsongs[i]; + if ( base_seconds + subsong->duration > seconds ) { + break; + } + base_seconds += subsong->duration; + } + seconds -= base_seconds; + } else + { + 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->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 ).StartPos( subsong.sequence, subsong.start_order, subsong.start_row ) ).back().duration; + m_currentPositionSeconds = base_seconds + 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 ) { @@ -746,7 +778,6 @@ } else { row = 0; } - m_sndFile->InitializeVisitedRows(); m_sndFile->m_PlayState.m_nCurrentOrder = order; m_sndFile->SetCurrentOrder( order ); m_sndFile->m_PlayState.m_nNextRow = row; Modified: trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp =================================================================== --- trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/libopenmpt/libopenmpt_impl.hpp 2014-11-09 18:23:21 UTC (rev 4575) @@ -57,18 +57,17 @@ 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: + struct subsong_data { + 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 ); + }; // struct subsong_data + static const std::int32_t all_subsongs = -1; + #ifdef LIBOPENMPT_ANCIENT_COMPILER std::tr1::shared_ptr<log_interface> m_Log; #else Modified: trunk/OpenMPT/openmpt123/openmpt123.cpp =================================================================== --- trunk/OpenMPT/openmpt123/openmpt123.cpp 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/openmpt123/openmpt123.cpp 2014-11-09 18:23:21 UTC (rev 4575) @@ -1397,6 +1397,7 @@ { openmpt::module mod( data_stream, silentlog, flags.ctls ); + mod.select_subsong( -1 ); // play all subsongs consecutively silentlog.str( std::string() ); // clear, loader messages get stored to get_metadata( "warnings" ) by libopenmpt internally render_mod_file( flags, filename, filesize, mod, log, audio_stream ); } Modified: trunk/OpenMPT/soundlib/Snd_defs.h =================================================================== --- trunk/OpenMPT/soundlib/Snd_defs.h 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/soundlib/Snd_defs.h 2014-11-09 18:23:21 UTC (rev 4575) @@ -277,6 +277,7 @@ SONG_BREAKTOROW = 0x80000, // Break to row command encountered (internal flag, do not touch) SONG_POSJUMP = 0x100000, // Position jump encountered (internal flag, do not touch) SONG_PT1XMODE = 0x200000, // ProTracker 1/2 playback mode + SONG_PLAYALLSONGS = 0x400000, // Play all subsongs consecutively (libopenmpt) }; DECLARE_FLAGSET(SongFlags) Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-11-09 18:23:21 UTC (rev 4575) @@ -158,6 +158,13 @@ for (;;) { + // Time target reached. + if(target.mode == GetLengthTarget::SeekSeconds && memory.elapsedTime >= target.time) + { + retval.targetReached = true; + break; + } + uint32 rowDelay = 0, tickDelay = 0; nRow = nNextRow; nCurrentOrder = nNextOrder; @@ -244,8 +251,7 @@ nRow = 0; // Check whether target was reached. - if((target.mode == GetLengthTarget::SeekPosition && nCurrentOrder == target.pos.order && nRow == target.pos.row) - || (target.mode == GetLengthTarget::SeekSeconds && memory.elapsedTime >= target.time)) + if(target.mode == GetLengthTarget::SeekPosition && nCurrentOrder == target.pos.order && nRow == target.pos.row) { retval.targetReached = true; break; @@ -866,6 +872,10 @@ m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; } // When adjusting the playback status, we will also want to update the visited rows vector according to the current position. + if(sequence != Order.GetCurrentSequenceIndex()) + { + Order.SetSequence(sequence); + } visitedSongRows.Set(visitedRows); } Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2014-11-09 17:46:22 UTC (rev 4574) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2014-11-09 18:23:21 UTC (rev 4575) @@ -494,9 +494,6 @@ // This is of course not possible during rendering to WAV, so we ignore that case. GetLengthType t = GetLength(eNoAdjust).back(); if(IsRenderingToDisc() || (t.lastOrder == m_PlayState.m_nCurrentOrder && t.lastRow == m_PlayState.m_nRow)) -#else - if(1) -#endif // MODPLUG_TRACKER { // This is really the song's end! visitedSongRows.Initialize(true); @@ -506,6 +503,44 @@ // Ok, this is really dirty, but we have to update the visited rows vector... GetLength(eAdjustOnSuccess, GetLengthTarget(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow)); } +#else + if(m_SongFlags[SONG_PLAYALLSONGS]) + { + // When playing all subsongs consecutively, first search for any hidden subsongs... + if(!visitedSongRows.GetFirstUnvisitedRow(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow, true)) + { + // ...and then try the next sequence. + m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder = 0; + m_PlayState.m_nNextRow = m_PlayState.m_nRow = 0; + if(Order.GetCurrentSequenceIndex() >= Order.GetNumSequences() - 1) + { + Order.SetSequence(0); + visitedSongRows.Initialize(true); + return false; + } + Order.SetSequence(Order.GetCurrentSequenceIndex() + 1); + visitedSongRows.Initialize(true); + } + // When jumping to the next subsong, stop all playing notes from the previous song... + for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) + m_PlayState.Chn[i].Reset(ModChannel::resetSetPosFull, *this, i); + StopAllVsti(); + // ...and the global playback information. + m_PlayState.m_nMusicSpeed = m_nDefaultSpeed; + m_PlayState.m_nMusicTempo = m_nDefaultTempo; + m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume; + + m_PlayState.m_nNextOrder = m_PlayState.m_nCurrentOrder; + m_PlayState.m_nNextRow = m_PlayState.m_nRow; + if(Order.size() > m_PlayState.m_nCurrentOrder) + m_PlayState.m_nPattern = Order[m_PlayState.m_nCurrentOrder]; + visitedSongRows.Visit(m_PlayState.m_nCurrentOrder, m_PlayState.m_nRow); + } else + { + visitedSongRows.Initialize(true); + return false; + } +#endif // MODPLUG_TRACKER } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |