1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
import os
from pathlib import Path
from .notifier import Notifier
from .player_mpv import Player
class SoloTool:
def __init__(self, songPool: str, player=None):
self._songPool = Path(songPool)
self._player = Player() if player is None else player
self._notifier = Notifier(self._player)
self._songs = []
self._song = None
self._keyPoints = []
self._keyPoint = None
def __del__(self):
del self._player
def _updateSong(self, index):
previousSong = self._song
self._song = index
self._player.pause()
self._player.setCurrentSong(self._songPool / self._songs[index])
self._notifier.notify(Notifier.CURRENT_SONG_EVENT, index)
previousKp = self._keyPoint
self._keyPoint = self.keyPoints[0] if len(self.keyPoints) > 0 else 0.0
if previousKp != self._keyPoint:
self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, self._keyPoint)
if previousSong is None or self._keyPoints[previousSong] != self._keyPoints[index]:
self._notifier.notify(Notifier.KEY_POINT_LIST_EVENT, self.keyPoints)
@staticmethod
def _keyPointValid(kp: float) -> bool:
return kp is not None and kp >= 0.0 and kp < 1.0
@property
def songs(self) -> list[str]:
return self._songs.copy()
def addSong(self, fileName: str) -> None:
path = self._songPool / fileName
if not os.path.isfile(path):
raise FileNotFoundError(path)
if path in self._songs:
return
self._songs.append(fileName)
self._keyPoints.append([])
self._notifier.notify(Notifier.SONG_LIST_EVENT, self.songs)
if self.song is None:
self.song = 0
@property
def song(self) -> int:
return self._song
@song.setter
def song(self, new: int) -> None:
if new is not None \
and new >= 0 \
and new < len(self._songs) \
and new != self._song:
self._updateSong(new)
@property
def keyPoints(self) -> list[float]:
if self._song is None:
return None
return self._keyPoints[self._song].copy()
@keyPoints.setter
def keyPoints(self, new: list[float]) -> None:
if new is not None and self._song is not None:
sanitized = sorted(list(set([p for p in new if SoloTool._keyPointValid(p)])))
self._keyPoints[self._song] = sanitized.copy()
self._notifier.notify(Notifier.KEY_POINT_LIST_EVENT, self.keyPoints)
@property
def keyPoint(self) -> float:
return float(self._keyPoint) if self._keyPoint is not None else None
@keyPoint.setter
def keyPoint(self, new: float) -> None:
if self._song is not None and SoloTool._keyPointValid(new) and new != self._keyPoint:
self._keyPoint = new
self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, new)
def play(self):
self._player.play()
def pause(self):
self._player.pause()
@property
def playing(self) -> bool:
return self._player.isPlaying()
def jump(self):
self._player.setPlaybackPosition(self._keyPoint)
@property
def rate(self) -> float:
return self._player.getPlaybackRate()
@rate.setter
def rate(self, new: float) -> None:
if new is not None and new >= 0.0 and new != self._player.getPlaybackRate():
self._player.setPlaybackRate(new)
self._notifier.notify(Notifier.PLAYBACK_RATE_EVENT, new)
@property
def volume(self) -> float:
return self._player.getPlaybackVolume()
@volume.setter
def volume(self, new: float) -> None:
if new is not None and new >= 0.0 and new != self._player.getPlaybackVolume():
self._player.setPlaybackVolume(new)
self._notifier.notify(Notifier.PLAYBACK_VOLUME_EVENT, new)
@property
def position(self) -> float:
return self._player.getPlaybackPosition()
@position.setter
def position(self, new: float) -> None:
if new is not None and new != self._player.getPlaybackPosition():
self._player.setPlaybackPosition(min(max(0.0, new), 1.0))
def registerSongSelectionCallback(self, callback):
self._notifier.registerCallback(Notifier.CURRENT_SONG_EVENT, callback)
def registerSongListCallback(self, callback):
self._notifier.registerCallback(Notifier.SONG_LIST_EVENT, callback)
def registerKeyPointSelectionCallback(self, callback):
self._notifier.registerCallback(Notifier.CURRENT_KEY_POINT_EVENT, callback)
def registerKeyPointListCallback(self, callback):
self._notifier.registerCallback(Notifier.KEY_POINT_LIST_EVENT, callback)
def registerPlayingStateCallback(self, callback):
self._notifier.registerCallback(Notifier.PLAYING_STATE_EVENT, callback)
def registerVolumeCallback(self, callback):
self._notifier.registerCallback(Notifier.PLAYBACK_VOLUME_EVENT, callback)
def registerRateCallback(self, callback):
self._notifier.registerCallback(Notifier.PLAYBACK_RATE_EVENT, callback)
|