Fix fading; lots of tidying!

This commit is contained in:
Keith Edmunds 2021-03-30 19:42:39 +01:00
parent 6643da84b6
commit d3b739dc36
9 changed files with 340 additions and 212 deletions

View File

@ -8,6 +8,8 @@ class Config(object):
DBFS_SILENCE = -50 DBFS_SILENCE = -50
DISPLAY_SQL = False DISPLAY_SQL = False
ERRORS_TO = ['kae@midnighthax.com'] ERRORS_TO = ['kae@midnighthax.com']
FADE_STEPS = 20
FADE_TIME = 5000
LOG_LEVEL_STDERR = logging.DEBUG LOG_LEVEL_STDERR = logging.DEBUG
LOG_LEVEL_SYSLOG = logging.DEBUG LOG_LEVEL_SYSLOG = logging.DEBUG
LOG_NAME = "musicmuster" LOG_NAME = "musicmuster"

7
app/log.py Executable file → Normal file
View File

@ -35,9 +35,10 @@ syslog.addFilter(filter)
stderr.addFilter(filter) stderr.addFilter(filter)
# create formatter and add it to the handlers # create formatter and add it to the handlers
formatter = logging.Formatter('[%(name)s] %(leveltag)s: %(message)s') stderr_fmt = logging.Formatter('%(leveltag)s: %(message)s')
stderr.setFormatter(formatter) syslog_fmt = logging.Formatter('[%(name)s] %(leveltag)s: %(message)s')
syslog.setFormatter(formatter) stderr.setFormatter(stderr_fmt)
syslog.setFormatter(syslog_fmt)
# add the handlers to the log # add the handlers to the log
log.addHandler(stderr) log.addHandler(stderr)

View File

@ -17,11 +17,8 @@ from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.orm import relationship, sessionmaker
from config import Config from config import Config
from log import DEBUG, ERROR, INFO from log import DEBUG, ERROR, INFO
INFO("Starting")
# Create session at the global level as per # Create session at the global level as per
# https://docs.sqlalchemy.org/en/13/orm/session_basics.html # https://docs.sqlalchemy.org/en/13/orm/session_basics.html
@ -138,8 +135,10 @@ class Playlists(Base):
def get_only_playlist(cls): def get_only_playlist(cls):
return session.query(Playlists).filter(Playlists.id == 1).one() return session.query(Playlists).filter(Playlists.id == 1).one()
def add_track(self, track): def add_track(self, track, position):
self.tracks.append(track) glue = PlaylistTracks(sort=position)
glue.track_id = track.id
self.tracks.append(glue)
def get_tracks(self): def get_tracks(self):
return [a.tracks for a in self.tracks] return [a.tracks for a in self.tracks]
@ -181,10 +180,9 @@ class Tracks(Base):
@staticmethod @staticmethod
def get_path(id): def get_path(id):
try: try:
path = session.query(Tracks.path).filter(Tracks.id == id).one()[0] return session.query(Tracks.path).filter(Tracks.id == id).one()[0]
return os.path.join(Config.ROOT, path)
except NoResultFound: except NoResultFound:
print(f"Can't find track id {id}") ERROR(f"Can't find track id {id}")
return None return None
@staticmethod @staticmethod
@ -210,6 +208,9 @@ class Tracks(Base):
return session.query(Tracks).filter( return session.query(Tracks).filter(
Tracks.id == id).one() Tracks.id == id).one()
def update_lastplayed(self):
self.lastplayed = datetime.now()
class Playdates(Base): class Playdates(Base):
__tablename__ = 'playdates' __tablename__ = 'playdates'
@ -226,4 +227,5 @@ class Playdates(Base):
pd.lastplayed = datetime.now() pd.lastplayed = datetime.now()
pd.track_id = track.id pd.track_id = track.id
session.add(pd) session.add(pd)
track.update_lastplayed()
session.commit() session.commit()

View File

@ -33,6 +33,7 @@ class Music:
"player": None, "player": None,
"meta": None "meta": None
} }
self.fading = False
def get_current_artist(self): def get_current_artist(self):
try: try:
@ -101,15 +102,26 @@ class Music:
return "" return ""
def fade_current(self): def fade_current(self):
if not self.playing():
return
thread = threading.Thread(target=self._fade_current) thread = threading.Thread(target=self._fade_current)
thread.start() thread.start()
def _fade_current(self): def _fade_current(self):
fade_time = Config.FADE_TIME / 1000
sleep_time = fade_time / Config.FADE_STEPS
step_percent = int((100 / Config.FADE_STEPS) * -1)
player = self.current_track['player'] player = self.current_track['player']
position = player.get_position() position = player.get_position()
for i in range(100, 0, -10): for i in range(100, 0, step_percent):
player.audio_set_volume(i) player.audio_set_volume(i)
sleep(0.2) sleep(sleep_time)
# If the user clicks "fade" and then, before the track has
# finished fading, click "play next", the "play next" will also
# call fade_current. When that second call to fade_current gets
# to the player.pause() line below, it will unpause it. So, we
# only pause if we're acutally playing.
if player.is_playing():
player.pause() player.pause()
player.audio_set_volume(100) player.audio_set_volume(100)
player.set_position(position) player.set_position(position)
@ -118,9 +130,11 @@ class Music:
if self.previous_track['player']: if self.previous_track['player']:
self.previous_track['player'].release() self.previous_track['player'].release()
if self.current_track['player']: if self.current_track['player']:
self.current_track['player'].stop() self.fade_current()
self.previous_track = self.current_track self.previous_track = self.current_track
self.current_track = self.next_track self.current_track = self.next_track
# Next in case player was left in odd (ie, silenced) state
self.current_track['player'].audio_set_volume(100)
self.current_track['player'].play() self.current_track['player'].play()
Playdates.add_playdate(self.current_track['meta']) Playdates.add_playdate(self.current_track['meta'])
@ -210,7 +224,11 @@ class Window(QMainWindow, Ui_MainWindow):
self.actionPlay_next.triggered.connect(self.play_next) self.actionPlay_next.triggered.connect(self.play_next)
self.actionPlay_selected.triggered.connect(self.play_next) self.actionPlay_selected.triggered.connect(self.play_next)
self.actionSearch_database.triggered.connect(self.selectFromDatabase) self.actionSearch_database.triggered.connect(self.selectFromDatabase)
self.btnSearchDatabase.clicked.connect(self.selectFromDatabase)
self.btnSkipNext.clicked.connect(self.play_next)
self.btnStop.clicked.connect(self.fade)
self.playlist.itemSelectionChanged.connect(self.set_next_track) self.playlist.itemSelectionChanged.connect(self.set_next_track)
self.timer.timeout.connect(self.tick) self.timer.timeout.connect(self.tick)
def selectFromDatabase(self): def selectFromDatabase(self):
@ -400,7 +418,8 @@ class DbDialog(QDialog):
# Store in current playlist in database # Store in current playlist in database
db_playlist = Playlists.get_only_playlist() db_playlist = Playlists.get_only_playlist()
db_playlist.add_track(track) # TODO: hack position to be at end of list
db_playlist.add_track(track, 99999)
# Add to on-screen playlist # Add to on-screen playlist
self.parent().add_to_playlist(track) self.parent().add_to_playlist(track)

8
app/songdb.py Executable file → Normal file
View File

@ -9,12 +9,12 @@ from model import Tracks, session
from pydub import AudioSegment from pydub import AudioSegment
from tinytag import TinyTag from tinytag import TinyTag
INFO("Starting")
def main(): def main():
"Main loop" "Main loop"
INFO("Starting")
# Parse command line # Parse command line
p = argparse.ArgumentParser() p = argparse.ArgumentParser()
p.add_argument('-u', '--update', p.add_argument('-u', '--update',
@ -125,9 +125,9 @@ def update_db():
session.commit() session.commit()
elif ext not in [".jpg"]: elif ext not in [".jpg"]:
print(f"Unrecognised file type: {path}") INFO(f"Unrecognised file type: {path}")
print(f"{count} files processed") INFO(f"{count} files processed")
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -16,6 +16,10 @@
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="previous_track_2"> <widget class="QLabel" name="previous_track_2">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -47,24 +51,7 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item>
<widget class="QLabel" name="previous_track">
<property name="font">
<font>
<family>Sans</family>
<pointsize>20</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: #f8d7da;
border: 1px solid rgb(85, 87, 83);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="current_track_2"> <widget class="QLabel" name="current_track_2">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -96,24 +83,7 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item>
<widget class="QLabel" name="current_track">
<property name="font">
<font>
<family>Sans</family>
<pointsize>20</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: #d4edda;
border: 1px solid rgb(85, 87, 83);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="next_track_2"> <widget class="QLabel" name="next_track_2">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -145,7 +115,45 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> </layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="previous_track">
<property name="font">
<font>
<family>Sans</family>
<pointsize>20</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: #f8d7da;
border: 1px solid rgb(85, 87, 83);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="current_track">
<property name="font">
<font>
<family>Sans</family>
<pointsize>20</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: #d4edda;
border: 1px solid rgb(85, 87, 83);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="next_track"> <widget class="QLabel" name="next_track">
<property name="font"> <property name="font">
<font> <font>
@ -162,7 +170,103 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="2"> </layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="lblTOD">
<property name="font">
<font>
<pointsize>35</pointsize>
</font>
</property>
<property name="text">
<string>00:00:00</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="btnPrevious">
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>previous.png</normaloff>previous.png</iconset>
</property>
<property name="iconSize">
<size>
<width>41</width>
<height>41</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnStop">
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>stop.png</normaloff>stop.png</iconset>
</property>
<property name="iconSize">
<size>
<width>41</width>
<height>41</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSkipNext">
<property name="maximumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset>
<normaloff>next.png</normaloff>next.png</iconset>
</property>
<property name="iconSize">
<size>
<width>41</width>
<height>41</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QTableWidget" name="playlist"> <widget class="QTableWidget" name="playlist">
<property name="editTriggers"> <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set> <set>QAbstractItemView::NoEditTriggers</set>
@ -230,11 +334,8 @@ border: 1px solid rgb(85, 87, 83);</string>
</column> </column>
</widget> </widget>
</item> </item>
<item row="4" column="0" colspan="2"> <item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>5</number>
</property>
<item> <item>
<widget class="QFrame" name="frame"> <widget class="QFrame" name="frame">
<property name="frameShape"> <property name="frameShape">
@ -332,8 +433,8 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>13</width>
<height>20</height> <height>60</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -388,8 +489,8 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>13</width>
<height>20</height> <height>60</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -444,8 +545,8 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>13</width>
<height>20</height> <height>60</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -500,8 +601,8 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>13</width>
<height>20</height> <height>60</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -562,16 +663,49 @@ border: 1px solid rgb(85, 87, 83);</string>
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="btnAddFile">
<property name="text">
<string>Add &amp;file...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSearchDatabase">
<property name="text">
<string>Search &amp;database</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QPushButton" name="btnSetNextTrack">
<property name="text">
<string>Set &amp;next track</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnTrackInfo">
<property name="text">
<string>Track &amp;info</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
<zorder>playlist</zorder>
<zorder>current_track</zorder>
<zorder>previous_track</zorder>
<zorder>next_track</zorder>
<zorder>current_track_2</zorder>
<zorder>next_track_2</zorder>
<zorder>previous_track_2</zorder>
</widget> </widget>
<widget class="QMenuBar" name="menubar"> <widget class="QMenuBar" name="menubar">
<property name="geometry"> <property name="geometry">
@ -610,36 +744,6 @@ border: 1px solid rgb(85, 87, 83);</string>
<string notr="true">background-color: rgb(211, 215, 207);</string> <string notr="true">background-color: rgb(211, 215, 207);</string>
</property> </property>
</widget> </widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionPlay_selected"/>
<addaction name="actionPlay_next"/>
<addaction name="actionFade"/>
<addaction name="separator"/>
<addaction name="actionAdd_file"/>
<addaction name="actionSearch_database"/>
<addaction name="separator"/>
<addaction name="actionS_top"/>
</widget>
<widget class="QToolBar" name="toolBar_2">
<property name="windowTitle">
<string>toolBar_2</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="actionPlay_selected"> <action name="actionPlay_selected">
<property name="icon"> <property name="icon">
<iconset> <iconset>

BIN
app/ui/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

BIN
app/ui/previous.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

BIN
app/ui/stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B