diff --git a/ChangeLog b/ChangeLog index a1027d8c..5723a934 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ + * Removed libindicate support + * Added Best of playlist generator + * Gstreamer-1.22 and wxwidgets-3.2 support + * Fullscreen cover view on cover panel click * Bugfixes + +2023-02-24 0.4.7 + * Added to CoverEditor the option to select a cover from a file and also to download it from an url + * Enable last.fm cover download + * Updated lyric sources + * Better gstreamer integration (formats support, audio pipeline reworked) + * UI changes + * Bugfixes + 2019-06-05 0.4.6 diff --git a/README.md b/README.md index a752bf6a..606bd250 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Its been developed in XUbuntu ### Ubuntu (pre 20.0): ```bash -sudo apt install libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libwxsqlite3-3.0-dev libwxbase3.0-dev +sudo apt install libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libwxsqlite3-3.0-dev libwxbase3.0-dev binutils ``` --- @@ -53,13 +53,23 @@ sudo apt install libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-bas ### Ubuntu 20.04 ```bash -sudo apt install libgpod-dev libjsoncpp-dev libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libwxsqlite3-3.0-dev libwxbase3.0-dev libtag1-dev libcurl4-gnutls-dev +sudo apt install libgpod-dev libjsoncpp-dev libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libwxsqlite3-3.0-dev libwxbase3.0-dev libtag1-dev libcurl4-gnutls-dev binutils ``` +--- + ### Ubuntu 22.04 ```bash -sudo apt install libgpod-dev libjsoncpp-dev libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libwxsqlite3-3.0-dev libwxbase3.0-dev libtag1-dev libcurl4-gnutls-dev libdbus-1-dev gettext +sudo apt install libgpod-dev libjsoncpp-dev libgdk-pixbuf2.0-dev libtag-extras-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libwxsqlite3-3.0-dev libwxbase3.0-dev libtag1-dev libcurl4-gnutls-dev libdbus-1-dev gettext binutils +``` + +--- + +### Mageia 9 + +``` +sudo urpmi lib64wx_gtk3u_wxsqlite3_3.2-devel lib64taglib-devel lib64sqlite3-devel lib64curl-devel gstreamer1.0-devtools lib64dbus-devel lib64gio2.0_0 lib64jsoncpp-devel binutils ``` --- @@ -77,6 +87,8 @@ sudo make install ### Faster build on multi-core systems +#### Old cmake versions + ```bash ./build \ -j$(nproc) \ @@ -84,3 +96,13 @@ sudo make install sudo make install ``` +#### New cmake versions + +```bash +./build \ + "" \ + -j$(nproc) +sudo make install +``` + +--- diff --git a/src/audio/FaderPlaybin.cpp b/src/audio/FaderPlaybin.cpp index 95843032..9d96c49d 100644 --- a/src/audio/FaderPlaybin.cpp +++ b/src/audio/FaderPlaybin.cpp @@ -390,7 +390,7 @@ static void gst_about_to_finish( GstElement * playbin, guFaderPlaybin::WeakPtr * static void gst_audio_changed( GstElement * playbin, guFaderPlaybin::WeakPtr * wpp ) { guLogDebug( "gst_audio_changed << %p", wpp ); - if( wpp == NULL) + if( (wpp == NULL) || (!GST_IS_BIN(playbin)) ) { guLogTrace( "gst_audio_changed: parent fader playbin is null" ); return; @@ -514,6 +514,7 @@ guFaderPlaybin::guFaderPlaybin( guMediaCtrl * mediactrl, const wxString &uri, co guFaderPlaybin::~guFaderPlaybin() { guLogDebug( wxT( "guFaderPlaybin::~guFaderPlaybin (%li) e: %i" ), m_Id, m_ErrorCode ); + m_SharedPointer.reset(); if( m_RecordBin != NULL ) guGstPipelineActuator( m_RecordBin ).Disable(); //m_Player->RemovePlayBin( this ); @@ -537,13 +538,6 @@ guFaderPlaybin::~guFaderPlaybin() guLogDebug( "guFaderPlaybin::~guFaderPlaybin wait on GST_STATE_CHANGE_ASYNC" ); gst_element_get_state( m_Playbin, NULL, NULL, GST_SECOND ); } - // guLogDebug( "mPlaybin refcount: %i", GST_OBJECT_REFCOUNT( m_Playbin ) ); - GstBus * bus = gst_pipeline_get_bus( GST_PIPELINE( m_Playbin ) ); - gst_bus_remove_watch( bus ); - // guLogDebug( "mPlaybin bus refcount: %i", GST_OBJECT_REFCOUNT( bus ) - 1 ); - gst_object_unref( bus ); - gst_object_unref( GST_OBJECT( m_Playbin ) ); - guGstStateToNullAndUnref( m_FaderVolume ); guGstStateToNullAndUnref( m_Volume ); @@ -551,6 +545,13 @@ guFaderPlaybin::~guFaderPlaybin() guGstStateToNullAndUnref( m_ReplayGain ); guGstStateToNullAndUnref( m_ReplayGainLimiter ); + + // guLogDebug( "mPlaybin refcount: %i", GST_OBJECT_REFCOUNT( m_Playbin ) ); + GstBus * bus = gst_pipeline_get_bus( GST_PIPELINE( m_Playbin ) ); + gst_bus_remove_watch( bus ); + // guLogDebug( "mPlaybin bus refcount: %i", GST_OBJECT_REFCOUNT( bus ) - 1 ); + gst_object_unref( bus ); + gst_object_unref( GST_OBJECT( m_Playbin ) ); } if( m_FaderTimeLine ) diff --git a/src/misc/Utils.h b/src/misc/Utils.h index be142d4c..693274cc 100644 --- a/src/misc/Utils.h +++ b/src/misc/Utils.h @@ -50,6 +50,12 @@ namespace Guayadeque { #define guDEFAULT_BROWSER_USER_AGENT wxT( "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36" ) +#if wxCHECK_VERSION(3, 2, 0) +#define guENSURE_BITMAP(x) (x.GetBitmap(x.GetDefaultSize())) +#else +#define guENSURE_BITMAP(x) (x) +#endif + class guTrackArray; class guMediaViewer; diff --git a/src/ui/aui/AuiNotebook.cpp b/src/ui/aui/AuiNotebook.cpp index a6c271ff..c46bfe67 100644 --- a/src/ui/aui/AuiNotebook.cpp +++ b/src/ui/aui/AuiNotebook.cpp @@ -293,7 +293,7 @@ void guAuiTabArt::DrawTab(wxDC &dc, wxWindow * wnd, const wxAuiNotebookPage &pag int close_button_width = 0; if( close_button_state != wxAUI_BUTTON_STATE_HIDDEN ) { - close_button_width = m_activeCloseBmp.GetWidth(); + close_button_width = guENSURE_BITMAP(m_activeCloseBmp).GetWidth(); } @@ -303,12 +303,12 @@ void guAuiTabArt::DrawTab(wxDC &dc, wxWindow * wnd, const wxAuiNotebookPage &pag bitmap_offset = tab_x + 8; // draw bitmap - dc.DrawBitmap(page.bitmap, + dc.DrawBitmap(guENSURE_BITMAP(page.bitmap), bitmap_offset, - drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2), + drawn_tab_yoff + (drawn_tab_height/2) - (guENSURE_BITMAP(page.bitmap).GetHeight()/2), true); - text_offset = bitmap_offset + page.bitmap.GetWidth(); + text_offset = bitmap_offset + guENSURE_BITMAP(page.bitmap).GetWidth(); text_offset += 3; // bitmap padding } else @@ -331,12 +331,12 @@ void guAuiTabArt::DrawTab(wxDC &dc, wxWindow * wnd, const wxAuiNotebookPage &pag // draw close button if necessary if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN) { - wxBitmap bmp = m_disabledCloseBmp; + wxBitmap bmp = guENSURE_BITMAP(m_disabledCloseBmp); if (close_button_state == wxAUI_BUTTON_STATE_HOVER || close_button_state == wxAUI_BUTTON_STATE_PRESSED) { - bmp = m_activeCloseBmp; + bmp = guENSURE_BITMAP(m_activeCloseBmp); } wxRect rect(tab_x + tab_width - close_button_width - 1, diff --git a/src/ui/cover/CoverPanel.cpp b/src/ui/cover/CoverPanel.cpp index ce066eaf..47f0894f 100644 --- a/src/ui/cover/CoverPanel.cpp +++ b/src/ui/cover/CoverPanel.cpp @@ -40,6 +40,8 @@ guCoverPanel::guCoverPanel( wxWindow * parent, guPlayerPanel * playerpanel ) : Bind( wxEVT_SIZE, &guCoverPanel::OnSize, this ); Bind( wxEVT_PAINT, &guCoverPanel::OnPaint, this ); Bind( wxEVT_TIMER, &guCoverPanel::OnResizeTimer, this, guCOVERPANEL_RESIZE_TIMER_ID ); + Bind( wxEVT_LEFT_UP, &guCoverPanel::OnClick, this); + Bind( wxEVT_RIGHT_UP, &guCoverPanel::OnClick, this); wxCommandEvent Event; OnUpdatedTrack( Event ); @@ -51,6 +53,8 @@ guCoverPanel::~guCoverPanel() Unbind( wxEVT_SIZE, &guCoverPanel::OnSize, this ); Unbind( wxEVT_PAINT, &guCoverPanel::OnPaint, this ); Unbind( wxEVT_TIMER, &guCoverPanel::OnResizeTimer, this, guCOVERPANEL_RESIZE_TIMER_ID ); + Unbind( wxEVT_LEFT_UP, &guCoverPanel::OnClick, this); + Unbind( wxEVT_RIGHT_UP, &guCoverPanel::OnClick, this); } // -------------------------------------------------------------------------------- // @@ -73,17 +77,32 @@ void guCoverPanel::OnResizeTimer( wxTimerEvent &event ) UpdateImage(); } +// -------------------------------------------------------------------------------- // +void guCoverPanel::OnClick( wxMouseEvent &event ) +{ + if ( m_CoverWindow == NULL ) { + m_CoverWindow = new guCoverWindow( this ); + } + else + { + m_CoverWindow->Raise(); + } + + if( m_CoverWindow ) + { + m_CoverWindow->SetBitmap( m_CoverType, m_CoverPath ); + m_CoverWindow->ShowFullScreen( true ); + } +} + // -------------------------------------------------------------------------------- // void guCoverPanel::OnSize( wxSizeEvent &event ) { wxSize Size = event.GetSize(); int MinSize = wxMin( Size.GetWidth(), Size.GetHeight() ); - //guLogMessage( wxT( "NewSize: %u" ), MinSize ); if( MinSize != m_LastSize ) { m_LastSize = MinSize; - //guLogMessage( wxT( "Updating Size: %u" ), MinSize ); -// UpdateImage(); if( m_ResizeTimer.IsRunning() ) { m_ResizeTimer.Stop(); @@ -149,6 +168,9 @@ void guCoverPanel::OnUpdatedTrack( wxCommandEvent &event ) { m_CoverType = CurrentTrack->m_CoverType; m_CoverPath = CurrentTrack->m_CoverPath; + if ( m_CoverWindow != NULL ) { + m_CoverWindow->SetBitmap( m_CoverType, m_CoverPath ); + } guLogMessage( wxT( "Changed image to %i '%s'" ), m_CoverType, m_CoverPath.c_str() ); } else diff --git a/src/ui/cover/CoverPanel.h b/src/ui/cover/CoverPanel.h index 97bb9a86..6fc6a007 100644 --- a/src/ui/cover/CoverPanel.h +++ b/src/ui/cover/CoverPanel.h @@ -22,6 +22,7 @@ #ifndef __COVERPANEL_H__ #define __COVERPANEL_H__ +#include "CoverWindow.h" #include "PlayerPanel.h" #include @@ -45,7 +46,7 @@ class guCoverPanel : public wxPanel guPlayerPanel * m_PlayerPanel; int m_LastSize; wxBitmap m_CoverImage; - int m_CoverType; + guSongCoverType m_CoverType; wxString m_CoverPath; wxMutex m_CoverImageMutex; wxTimer m_ResizeTimer; @@ -53,6 +54,7 @@ class guCoverPanel : public wxPanel virtual void OnSize( wxSizeEvent &event ); virtual void OnPaint( wxPaintEvent &event ); virtual void OnResizeTimer( wxTimerEvent &event ); + virtual void OnClick( wxMouseEvent &event ); void UpdateImage( void ); @@ -60,6 +62,8 @@ class guCoverPanel : public wxPanel guCoverPanel( wxWindow * parent, guPlayerPanel * playerpanel ); ~guCoverPanel(); + guCoverWindow * m_CoverWindow = NULL; + void OnUpdatedTrack( wxCommandEvent &event ); }; diff --git a/src/ui/cover/CoverWindow.cpp b/src/ui/cover/CoverWindow.cpp new file mode 100644 index 00000000..d07e7fc0 --- /dev/null +++ b/src/ui/cover/CoverWindow.cpp @@ -0,0 +1,203 @@ +// -------------------------------------------------------------------------------- // +// Copyright (C) 2008-2023 J.Rios anonbeat@gmail.com +// +// This Program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This Program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file LICENSE. If not, write to +// the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/copyleft/gpl.html +// +// -------------------------------------------------------------------------------- // +#include "CoverWindow.h" + +#include "CoverPanel.h" +#include "Images.h" +#include "TagInfo.h" + +#define guCOVERWINDOW_RESIZE_TIMER_TIME 250 +#define guCOVERWINDOW_RESIZE_TIMER_ID 10 + +namespace Guayadeque { + +// -------------------------------------------------------------------------------- // +guCoverWindow::guCoverWindow( guCoverPanel * parent, wxWindowID id, const wxString & title, const wxPoint & pos, const wxSize & size, long style ) : + wxFrame( parent, id, title, pos, size, style ), + m_ResizeTimer( this, guCOVERWINDOW_RESIZE_TIMER_ID ) +{ + m_LastSize = 100; + m_CoverPanel = parent; + + m_Panel = new wxPanel(this); + + Bind( wxEVT_SIZE, &guCoverWindow::OnSize, this ); + Bind( wxEVT_PAINT, &guCoverWindow::OnPaint, this ); + Bind( wxEVT_TIMER, &guCoverWindow::OnResizeTimer, this, guCOVERWINDOW_RESIZE_TIMER_ID ); + Bind( wxEVT_LEFT_UP, &guCoverWindow::OnClick, this); + Bind( wxEVT_RIGHT_UP, &guCoverWindow::OnRightClick, this); + Bind( wxEVT_MOUSEWHEEL, &guCoverWindow::OnClick, this); + m_Panel->Bind( wxEVT_KEY_UP, &guCoverWindow::OnKey, this); + m_Panel->SetFocus(); + + wxCommandEvent Event; + OnUpdatedTrack( Event ); +} + +// -------------------------------------------------------------------------------- // +guCoverWindow::~guCoverWindow() +{ + guLogDebug("guCoverWindow::~guCoverWindow"); + + m_CoverPanel->m_CoverWindow = NULL; + + m_Panel->Unbind( wxEVT_KEY_UP, &guCoverWindow::OnKey, this); + + Unbind( wxEVT_SIZE, &guCoverWindow::OnSize, this ); + Unbind( wxEVT_PAINT, &guCoverWindow::OnPaint, this ); + Unbind( wxEVT_TIMER, &guCoverWindow::OnResizeTimer, this, guCOVERWINDOW_RESIZE_TIMER_ID ); + Unbind( wxEVT_LEFT_UP, &guCoverWindow::OnClick, this); + Unbind( wxEVT_RIGHT_UP, &guCoverWindow::OnRightClick, this); + Unbind( wxEVT_MOUSEWHEEL, &guCoverWindow::OnClick, this); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::OnPaint( wxPaintEvent &event ) +{ + wxCoord Width; + wxCoord Height; + GetClientSize( &Width, &Height ); + if( Width && Height ) + { + wxMutexLocker Lock( m_CoverImageMutex ); + wxPaintDC dc( this ); + dc.DrawBitmap( m_CoverImage, ( Width - m_LastSize ) / 2, ( Height - m_LastSize ) / 2, false ); + } + event.Skip(); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::OnResizeTimer( wxTimerEvent &event ) +{ + UpdateImage(); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::OnClick( wxMouseEvent &event ) +{ + guLogDebug("guCoverWindow::OnClick"); + Close(); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::OnRightClick( wxMouseEvent &event ) +{ + guLogDebug("guCoverWindow::OnRightClick"); + if ( IsFullScreen() ) { + ShowFullScreen( false ); + } + else + { + ShowFullScreen( true ); + } +} + +void guCoverWindow::OnKey( wxKeyEvent &event ) +{ + guLogDebug("guCoverWindow::OnKey"); + Close(); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::OnSize( wxSizeEvent &event ) +{ + guLogDebug("guCoverWindow::OnSize"); + wxSize Size = event.GetSize(); + int MinSize = wxMin( Size.GetWidth(), Size.GetHeight() ); + if( MinSize != m_LastSize ) + { + m_LastSize = MinSize; + if( m_ResizeTimer.IsRunning() ) + { + m_ResizeTimer.Stop(); + } + m_ResizeTimer.Start( guCOVERWINDOW_RESIZE_TIMER_TIME, wxTIMER_ONE_SHOT ); + } + SetFocus(); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::UpdateImage( void ) +{ + guLogDebug("guCoverWindow::UpdateImage"); + wxImage * CoverImage = NULL; + + switch( m_CoverType ) + { + case GU_SONGCOVER_FILE : + CoverImage = new wxImage( m_CoverPath ); + break; + + case GU_SONGCOVER_ID3TAG : + CoverImage = guTagGetPicture( m_CoverPath ); + break; + + case GU_SONGCOVER_RADIO : + CoverImage = new wxImage( guImage( guIMAGE_INDEX_net_radio ) ); + break; + + case GU_SONGCOVER_PODCAST : + CoverImage = new wxImage( guImage( guIMAGE_INDEX_podcast ) ); + break; + + default : + break; + } + + if( !CoverImage || !CoverImage->IsOk() ) + { + if( CoverImage ) + delete CoverImage; + CoverImage = new wxImage( guImage( guIMAGE_INDEX_no_cover ) ); + } + + if( CoverImage ) + { + if( m_LastSize > 0 ) + CoverImage->Rescale( m_LastSize, m_LastSize, wxIMAGE_QUALITY_HIGH ); + wxMutexLocker Lock( m_CoverImageMutex ); + m_CoverImage = wxBitmap( * CoverImage ); + //Update(); + Refresh(); + + delete CoverImage; + } +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::OnUpdatedTrack( wxCommandEvent &event ) +{ + UpdateImage(); +} + +// -------------------------------------------------------------------------------- // +void guCoverWindow::SetBitmap( const guSongCoverType CoverType, const wxString &CoverPath ) +{ + guLogDebug("guCoverWindow::SetBitmap ( %d , %s )", CoverType, CoverPath); + m_CoverType = CoverType; + m_CoverPath = CoverPath; + UpdateImage(); +} + +} // Guayadeque namespace + +// -------------------------------------------------------------------------------- // diff --git a/src/ui/cover/CoverWindow.h b/src/ui/cover/CoverWindow.h new file mode 100644 index 00000000..4f57164e --- /dev/null +++ b/src/ui/cover/CoverWindow.h @@ -0,0 +1,58 @@ + +#ifndef __COVERWINDOW_H__ +#define __COVERWINDOW_H__ + +#include "PlayerPanel.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Guayadeque { + +class guCoverPanel; + +// -------------------------------------------------------------------------------- // +class guCoverWindow : public wxFrame +{ + protected : + guCoverPanel * m_CoverPanel; + + int m_LastSize; + wxBitmap m_CoverImage; + int m_CoverType; + wxString m_CoverPath; + wxMutex m_CoverImageMutex; + wxTimer m_ResizeTimer; + wxPanel * m_Panel; + + virtual void OnSize( wxSizeEvent &event ); + virtual void OnPaint( wxPaintEvent &event ); + virtual void OnResizeTimer( wxTimerEvent &event ); + virtual void OnClick( wxMouseEvent &event ); + virtual void OnRightClick( wxMouseEvent &event ); + virtual void OnKey( wxKeyEvent &event ); + + void UpdateImage( void ); + + public : + guCoverWindow( guCoverPanel * parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500, 500 ), long style = wxDEFAULT_FRAME_STYLE | wxMAXIMIZE ); + ~guCoverWindow(); + + void OnUpdatedTrack( wxCommandEvent &event ); + void SetBitmap( const guSongCoverType CoverType, const wxString &CoverPath = wxEmptyString ); + +}; + +} + +#endif +// -------------------------------------------------------------------------------- //