Hi Sebastian and other hydrogen friends ;-)
I made support for loading playlist in h2cli - and also a little patch around
handling playlist. It works quiet well ..
.. but there is some problem , which I can't cope - it sometimes dump core :(
I hope you can find a bug. Steps for reproduce:
In h2cli , change songs on playlist few times - and then try to live (by
pressing CTRL+C i.e. SIGINT signal) it got segfault on line 328 (delete song).
In hydrogen it fail after few fast song changes (via MIDI). Sometimes it can
took a while. I assume that this two problem are related.
#0 NotePropertiesRuler::updateEditor (this=0x1dbd2f0) at
/home/xj/Muzyka/hydrogen/src/gui/src/PatternEditor/NotePropertiesRuler.cpp:1249
#1 0x00000000004ec089 in HydrogenApp::onEventQueueTimer (this=0xb3f630) at
/home/xj/Muzyka/hydrogen/src/gui/src/HydrogenApp.cpp:527
#2 0x00007ffff67b80ef in QMetaObject::activate(QObject*, QMetaObject const*,
int, void**) () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#3 0x00007ffff67bd3ec in QObject::event(QEvent*) () from
/usr/lib/x86_64-linux-gnu/libQtCore.so.4
#4 0x00007ffff700c8ec in QApplicationPrivate::notify_helper(QObject*, QEvent*)
() from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#5 0x00007ffff700f25b in QApplication::notify(QObject*, QEvent*) () from
/usr/lib/x86_64-linux-gnu/libQtGui.so.4
#6 0x00007ffff67a363e in QCoreApplication::notifyInternal(QObject*, QEvent*)
() from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#7 0x00007ffff67d4b72 in ?? () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#8 0x00007ffff67d19a4 in ?? () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#9 0x00007ffff67d19c1 in ?? () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#10 0x00007ffff3c08f05 in g_main_context_dispatch () from
/lib/x86_64-linux-gnu/libglib-2.0.so.0
#11 0x00007ffff3c09248 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x00007ffff3c09304 in g_main_context_iteration () from
/lib/x86_64-linux-gnu/libglib-2.0.so.0
#13 0x00007ffff67d2016 in
QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) ()
from /usr/lib/x86_64-linux-gnu/libQtCore.so.4
#14 0x00007ffff70b21ae in ?? () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#15 0x00007ffff67a238f in
QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from
/usr/lib/x86_64-linux-gnu/libQtCore.so.4
#16 0x00007ffff67a2618 in
QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from
/usr/lib/x86_64-linux-gnu/libQtCore.so.4
#17 0x00007ffff67a7cf6 in QCoreApplication::exec() () from
/usr/lib/x86_64-linux-gnu/libQtCore.so.4
#18 0x000000000044a61f in main (argc=5, argv=<optimized out>) at
/home/xj/Muzyka/hydrogen/src/gui/src/main.cpp:431
Dnia Piątek, 21 Czerwca 2013 21:52 <[email protected]> napisał(a)
> Hi Pawel!
>
> I had a short look at the code that you've mentioned and it has really a
> quite bad design. I don't have the time to refactor those parts, i would
> rather spent my hydrogen-time on fixing bugs for 0.9.6. But if you want
> to make a first try and clean up the code, i can offer to help you with
> that and have a look at your patches and help if you don't now how to
> proceed.
>
> So what has to be done? Basically, all non-gui stuff (setting the song,
> storing it into the 'Preferences' class) should go definitely into the
> core of hydrogen (class hydrogen in src/core/src) or into playlist.cpp.
> The Event that you have found should trigger only the refreshing of the
> gui elements which show song/playlist dependent stuff. I don't think
> that the changes will be huge, since the playlist functionality is quite
> small.
>
> Hope that helps,
> Sebastian
>
> On 2013-06-19 9:43, Pawel wrote:
> > Thanks Sebastian !
> >
> > I was dig a little into code and looks that playlist code is strongly
> > bind to gui code. I was able to implement code for loading playlist ,
> > but this is not enough for load songs. For now there is only possible
> > to load first Song on start (because we can get path from playlist
> > array), but changing song is not possible , because related event:
> > EVENT_PLAYLIST_LOADSONG
> >
> > Is handled by gui/src/HydrogenApp.cpp file. Unfortunately it's far
> > away from my C++/Hydrogen code knowledge to clean this mess (to many
> > dependencies).
> >
> > Therefore I see two option:
> > - someone else clean this mess and then I provide patch for h2cli
> > (better option)
> > - I re-implement load playlist code and EVENT_PLAYLIST_LOADSONG event
> > handling.
> >
> > P.
> >
> > Dnia Niedziela, 16 Czerwca 2013 21:21 <[email protected]> napisał(a)
> >> Hi Pawel,
> >>
> >> thanks again for the patch! I've just pushed it into our git
> >> repository.
> >> About the playlist stuff: I haven't written the playlist code, so i
> >> don't have an answer to your question without looking closer at the
> >> code. But i guess if you look at main.cpp and MainForm.cpp, you should
> >> find the (gui) code for the playlist initialization (if there is
> >> any..).
> >> If you have any problems with the integration just ask again, then i
> >> will have a deeper look at the code on the next weekend :)
> >> Best regards,
> >> Sebastian
> >>
> >> On 15.06.2013 13:06, Pawel wrote:
> >> > Hi,
> >> >
> >> > I improved this patch to allow also map Program Change messages - so
> >> > now user can change songs using Program Change messages ;-)
> >> >
> >> > It is still possible to use PC messages as in previous version (for
> >> > select next pattern) if user map appropriate action.
> >> >
> >> > Please append it to official repo.
> >> >
> >> > BTW. my first question from previous mail is still valid.
> >> >
> >> > Pawel
> >> >
> >> > Dnia Poniedziałek, 10 Czerwca 2013 22:54 Pawel <[email protected]> napisał(a)
> >> >> Hi,
> >> >>
> >> >> I've done simple patch for handling playlist via MIDI. For my
> >> >> purpose I use it for precisely select song to play live (via CC). In
> >> >> my M-Audio Axiom I can set fixed MIDI CC value to buttons.
> >> >>
> >> >> Meantime I have two question:
> >> >> 1) I want to add support for playlist in h2cli. Please tell me it is
> >> >> enough to just call
> >> >> LocalFileMng::loadPlayList
> >> >>
> >> >> ?
> >> >>
> >> >> 2) Currently Program Change messages are restricted to pattern
> >> >> switching , will be OK for you to add support for mapping this
> >> >> messages ? I imagine scenario where I could load playlist in h2cli and
> >> >> change songs via Program Change messages - this is actually my long
> >> >> term goal ;-)
> >> >>
> >> >> Best Regards
> >> >> Xj
> >>
> >>
> >> ------------------------------------------------------------------------------
> >> This SF.net email is sponsored by Windows:
> >>
> >> Build for Windows Store.
> >>
> >> http://p.sf.net/sfu/windows-dev2dev
> >> _______________________________________________
> >> Hydrogen-devel mailing list
> >> [email protected]
> >> https://lists.sourceforge.net/lists/listinfo/hydrogen-devel
> >
> >
> >
> > ------------------------------------------------------------------------------
> > This SF.net email is sponsored by Windows:
> >
> > Build for Windows Store.
> >
> > http://p.sf.net/sfu/windows-dev2dev
> > _______________________________________________
> > Hydrogen-devel mailing list
> > [email protected]
> > https://lists.sourceforge.net/lists/listinfo/hydrogen-devel
>
> ------------------------------------------------------------------------------
> This SF.net email is sponsored by Windows:
>
> Build for Windows Store.
>
> http://p.sf.net/sfu/windows-dev2dev
> _______________________________________________
> Hydrogen-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/hydrogen-devel
diff --git a/src/cli/main.cpp b/src/cli/main.cpp
index ef0cf1f..279bdab 100644
--- a/src/cli/main.cpp
+++ b/src/cli/main.cpp
@@ -39,6 +39,7 @@
#include <hydrogen/h2_exception.h>
#include <hydrogen/playlist.h>
#include <hydrogen/helpers/filesystem.h>
+#include <hydrogen/LocalFileMng.h>
#include <iostream>
#include <signal.h>
@@ -51,6 +52,7 @@ void showUsage();
static struct option long_opts[] = {
{"driver", required_argument, NULL, 'd'},
{"song", required_argument, NULL, 's'},
+ {"playlist", required_argument, NULL, 'p'},
{"bits", required_argument, NULL, 'b'},
{"rate", required_argument, NULL, 'r'},
{"outfile", required_argument, NULL, 'o'},
@@ -93,6 +95,7 @@ int main(int argc, char *argv[])
// Deal with the options
QString songFilename;
+ QString playlistFilename;
QString outFilename = NULL;
QString sSelectedDriver;
bool showVersionOpt = false;
@@ -105,10 +108,9 @@ int main(int argc, char *argv[])
short interpolation = 0;
int c;
- for (;;) {
+ while ( 1 ) {
c = getopt_long(argc, argv, opts, long_opts, NULL);
- if (c == -1)
- break;
+ if ( c == -1 ) break;
switch(c) {
case 'd':
@@ -117,6 +119,9 @@ int main(int argc, char *argv[])
case 's':
songFilename = QString::fromLocal8Bit(optarg);
break;
+ case 'p':
+ playlistFilename = QString::fromLocal8Bit(optarg);
+ break;
case 'o':
outFilename = QString::fromLocal8Bit(optarg);
break;
@@ -138,11 +143,7 @@ int main(int argc, char *argv[])
showVersionOpt = true;
break;
case 'V':
- if ( optarg ) {
- logLevelOpt = optarg;
- } else {
- logLevelOpt = "Warning";
- }
+ logLevelOpt = (optarg) ? optarg : "Warning";
break;
case 'h':
case '?':
@@ -227,28 +228,48 @@ int main(int argc, char *argv[])
H2Core::Hydrogen::create_instance();
H2Core::Hydrogen *hydrogen = H2Core::Hydrogen::get_instance();
- // Load default song
+ // Load playlist
H2Core::Song *song = NULL;
- if ( !songFilename.isEmpty() ) {
- song = H2Core::Song::load( songFilename );
- }
- else {
- /* Try load last song */
- bool restoreLastSong = preferences->isRestoreLastSongEnabled();
- QString filename = preferences->getLastSongFilename();
- if ( restoreLastSong && ( !filename.isEmpty() )) {
- song = H2Core::Song::load( filename );
+ if( ! playlistFilename.isEmpty() ){
+ H2Core::LocalFileMng fileMng;
+ int err = fileMng.loadPlayList( playlistFilename.toLocal8Bit().constData() );
+ if ( err == 0 ) {
+ preferences->setLastPlaylistFilename( playlistFilename );
+ Playlist::get_instance()->setNextSongByNumber( 0 );
+ song = hydrogen->getSong();
+
+ if( hydrogen->m_PlayList.size() > 0){
+ for ( uint i = 0; i < hydrogen->m_PlayList.size(); ++i ) {
+ std::cout << i << "." << hydrogen->m_PlayList[i].m_hFile.toLocal8Bit().constData() << std::endl;
+ }
+ }
+ } else {
+ ___ERRORLOG( "Error loading the playlist" );
}
}
- if (! song) {
- ___INFOLOG("Starting with empty song");
- song = H2Core::Song::get_empty_song();
- song->set_filename( "" );
- }
+ // Load song - if wasn't already loaded with playlist
+ if ( ! song ) {
+ if ( !songFilename.isEmpty() ) {
+ song = H2Core::Song::load( songFilename );
+ } else {
+ /* Try load last song */
+ bool restoreLastSong = preferences->isRestoreLastSongEnabled();
+ QString filename = preferences->getLastSongFilename();
+ if ( restoreLastSong && ( !filename.isEmpty() ))
+ song = H2Core::Song::load( filename );
+ }
- hydrogen->setSong( song );
- preferences->setLastSongFilename( songFilename );
+ /* Still not loaded */
+ if (! song) {
+ ___INFOLOG("Starting with empty song");
+ song = H2Core::Song::get_empty_song();
+ song->set_filename( "" );
+ }
+
+ hydrogen->setSong( song );
+ preferences->setLastSongFilename( songFilename );
+ }
if( ! drumkitToLoad.isEmpty() ){
H2Core::Drumkit* drumkitInfo = H2Core::Drumkit::load( H2Core::Filesystem::drumkit_path_search( drumkitToLoad ), true );
@@ -301,12 +322,11 @@ int main(int argc, char *argv[])
}
}
- if ( (hydrogen->getState() == STATE_PLAYING) ) {
+ if ( hydrogen->getState() == STATE_PLAYING )
hydrogen->sequencer_stop();
- }
- delete Playlist::get_instance();
delete song;
+ delete Playlist::get_instance();
delete eQueue;
delete hydrogen;
@@ -360,6 +380,7 @@ void showUsage()
std::cout << "Usage: hydrogen [-v] [-h] -s file" << std::endl;
std::cout << " -d, --driver AUDIODRIVER - Use the selected audio driver (jack, alsa, oss)" << std::endl;
std::cout << " -s, --song FILE - Load a song (*.h2song) at startup" << std::endl;
+ std::cout << " -p, --playlist FILE - Load a playlist (*.h2playlist) at startup" << std::endl;
std::cout << " -o, --outfile FILE - Output to file (export)" << std::endl;
std::cout << " -r, --rate RATE - Set bitrate while exporting file" << std::endl;
std::cout << " -b, --bits BITS - Set bits depth while exporting file" << std::endl;
diff --git a/src/core/src/playlist.cpp b/src/core/src/playlist.cpp
index ad69db5..da32ccf 100644
--- a/src/core/src/playlist.cpp
+++ b/src/core/src/playlist.cpp
@@ -29,11 +29,8 @@
#include <vector>
#include <cstdlib>
-
-
using namespace H2Core;
-
Playlist* Playlist::__instance = NULL;
const char* Playlist::__class_name = "Playlist";
@@ -53,16 +50,12 @@ Playlist::Playlist()
activeSongNumber = -1;
}
-
-
Playlist::~Playlist()
{
//_INFOLOG( "[~Playlist]" );
__instance = NULL;
}
-
-
void Playlist::create_instance()
{
if ( __instance == 0 ) {
@@ -70,48 +63,64 @@ void Playlist::create_instance()
}
}
-
-
void Playlist::setNextSongByNumber(int songNumber)
{
+ Hydrogen *hydrogen = Hydrogen::get_instance();
-
- if ( songNumber > (int)Hydrogen::get_instance()->m_PlayList.size() -1 || (int)Hydrogen::get_instance()->m_PlayList.size() == 0 )
+ if ( songNumber > (int) hydrogen->m_PlayList.size() -1 || (int) hydrogen->m_PlayList.size() == 0 )
return;
setSelectedSongNr( songNumber );
setActiveSongNumber( songNumber );
+ QString selected = hydrogen->m_PlayList[ songNumber ].m_hFile;
+ Song *pSong = Song::load( selected );
+ if ( ! pSong ) return;
+
+ Song* oldSong = hydrogen->getSong();
+ if (oldSong != NULL) {
+ hydrogen->removeSong();
+ delete oldSong;
+ oldSong = NULL;
+ }
+
+ if ( hydrogen->getState() == STATE_PLAYING )
+ hydrogen->sequencer_stop();
+ hydrogen->m_timelinetagvector.clear();
+ hydrogen->setSelectedPatternNumber( 0 );
+ hydrogen->setSong( pSong );
+
+ Preferences *pPref = Preferences::get_instance();
+ Preferences::get_instance()->setLastSongFilename( pSong->get_filename() );
+ vector<QString> recentFiles = pPref->getRecentFiles();
+ recentFiles.insert( recentFiles.begin(), selected );
+ pPref->setRecentFiles( recentFiles );
+
EventQueue::get_instance()->push_event( EVENT_PLAYLIST_LOADSONG, songNumber);
execScript( songNumber );
}
-
void Playlist::setSelectedSongNr( int songNumber )
{
selectedSongNumber = songNumber;
}
-
int Playlist::getSelectedSongNr()
{
return selectedSongNumber;
}
-
void Playlist::setActiveSongNumber( int ActiveSongNumber)
{
activeSongNumber = ActiveSongNumber ;
}
-
int Playlist::getActiveSongNumber()
{
return activeSongNumber;
}
-
void Playlist::execScript( int index)
{
QString file;
diff --git a/src/gui/src/MainForm.cpp b/src/gui/src/MainForm.cpp
index 0b0e354..c163118 100644
--- a/src/gui/src/MainForm.cpp
+++ b/src/gui/src/MainForm.cpp
@@ -1491,9 +1491,25 @@ void MainForm::errorEvent( int nErrorCode )
void MainForm::playlistLoadSongEvent(int nIndex)
{
+ Hydrogen *engine = Hydrogen::get_instance();
+
+ Song *pSong = engine->getSong();
+ if ( ! pSong ) return;
+
+ h2app->getSongEditorPanel()->updateAll();
+ h2app->getPatternEditorPanel()->updateSLnameLabel();
+
+ QString songName( pSong->__name );
+ if( songName == "Untitled Song" && !pSong->get_filename().isEmpty() ){
+ songName = pSong->get_filename();
+ songName = songName.section( '/', -1 );
+ }
+ setWindowTitle( songName );
+
+ h2app->getMainForm()->updateRecentUsedSongList();
+ h2app->closeFXProperties();
+ h2app->m_undoStack->clear();
- QString selected = Hydrogen::get_instance()->m_PlayList[ nIndex ].m_hFile;
- openSongFile(selected);
EventQueue::get_instance()->push_event( EVENT_METRONOME, 3 );
HydrogenApp::get_instance()->setScrollStatusBarMessage( trUtf8( "Playlist: Set song No. %1" ).arg( nIndex +1 ), 5000 );
}
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Hydrogen-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/hydrogen-devel