Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 95 lines (48 sloc) 6.126 kb
ccbaa00 @albertz development notes
authored
1 Development notes
2 =================
3
4 In here are a few notes about how the code is organized, used concepts, etc.
5
6533ef4 @albertz Update DevelopmentNotes.md
authored
6 The main code is all pure Python. It is highly modular. The main playing engine is implemented in C/C++ as a Python module ([`ffmpeg.c`](https://github.com/albertz/music-player/blob/master/ffmpeg.c) and related). It uses [FFmpeg](http://ffmpeg.org/) for decoding and [PortAudio](http://www.portaudio.com/) for output.
ccbaa00 @albertz development notes
authored
7
8 A basic principle is to keep the code as simple as possible so that it works. I really want to avoid to overcomplicate things.
9
6533ef4 @albertz Update DevelopmentNotes.md
authored
10 The main entry point is [`main`](https://github.com/albertz/music-player/blob/master/main.py). It initializes all the modules. The list of modules is defined in [`State.modules`](https://github.com/albertz/music-player/blob/master/State.py). It contains for example `queue`, `tracker`, `mediakeys`, `gui`, etc.
ccbaa00 @albertz development notes
authored
11
12
c1c5eae @albertz Update DevelopmentNotes.md
authored
13 ## Module
ccbaa00 @albertz development notes
authored
14
15 A module is controlled by the `utils.Module` class. It refers to a Python module (for example `queue`).
16
17 When you start a module (`Module.start`), it starts a new thread and executes the `<modulename>Main` function.
18
19 A module is supposed to be reloadable. There is the function `Module.reload` and `State.reloadModules` is supposed to reload all modules. This is mostly only used for/while debugging, though and is probably not stable and not well tested.
20
21
c1c5eae @albertz Update DevelopmentNotes.md
authored
22 ## Multithreading and multiprocessing
ccbaa00 @albertz development notes
authored
23
24 The whole code makes heavy use of multithreading and multiprocessing. Every module already runs in its own thread. But some modules itself spawn also other threads. The GUI module spawns a new thread for most actions. Heavy calculations should be done in a seperate process so that the GUI and the playing engine (which run both in the main process) are always responsive. There is `utils.AsyncTask` and `utils.asyncCall` for an easy and stable way to do something in a seperate process.
25
26
c1c5eae @albertz Update DevelopmentNotes.md
authored
27 ## Playing engine
ccbaa00 @albertz development notes
authored
28
3907dce @albertz dev notes: player core module
authored
29 This is all the [Python native-C/C++ module](https://github.com/albertz/music-player-core/).
ccbaa00 @albertz development notes
authored
30
ad0a443 @albertz more
authored
31 The `player` module creates the player object as `State.state.player`. It setups the queue as `queue.queue`. `State.state` provides also some functions to control the player state (`playPause`, `nextSong`).
32
ccbaa00 @albertz development notes
authored
33
c1c5eae @albertz Update DevelopmentNotes.md
authored
34 ## GUI
ccbaa00 @albertz development notes
authored
35
36 The basic idea is that Python objects are directly represented in the GUI. The main window corresponds to the `State.state` object. Attributes of an object which should be shown in the GUI are marked via the `utils.UserAttrib` decorator. There, you can specify some further information to specify more concretely how an attribute should be displayed.
37
6533ef4 @albertz Update DevelopmentNotes.md
authored
38 The GUI has its own module [`gui`](https://github.com/albertz/music-player/blob/master/gui.py). At the moment, only an OSX Cocoa interface ([`guiCocoa`](https://github.com/albertz/music-player/blob/master/guiCocoa.py)) is implemented but a PyQt implementation is planned. There is some special handling for this module as it needs to be run in the main thread in most cases. See `main` for further reference.
ccbaa00 @albertz development notes
authored
39
40
c1c5eae @albertz Update DevelopmentNotes.md
authored
41 ## Database
42
6533ef4 @albertz Update DevelopmentNotes.md
authored
43 This is the module [`songdb`](https://github.com/albertz/music-player/blob/master/songdb.py).
ccbaa00 @albertz development notes
authored
44
d863c1e @albertz Update DevelopmentNotes.md
authored
45 The database is intended to be an optional system which stores some extra data/statistics about a song and also caches some data which is heavy to calculate (e.g. the fingerprint).
ccbaa00 @albertz development notes
authored
46
47 It provides several ways to identify a song:
48
49 - By the SHA1 of its path name (relative to the users home dir).
50 - By the SHA1 of its file.
51 - By the SHA1 of its AcoustId fingerprint.
52
53 This is so that the database stays robust in case the user moves a song file around or changes its metadata.
54
6533ef4 @albertz Update DevelopmentNotes.md
authored
55 It uses [SQLite](http://www.sqlite.org/) as its backend. (As it is used mostly as a key/value store with optional external indexing, a complex SQL-like DB is not strictly needed. Earlier, I tried other DBs. For a history, see the [comment in the source](https://github.com/albertz/music-player/blob/master/songdb.py).)
ccbaa00 @albertz development notes
authored
56
d863c1e @albertz Update DevelopmentNotes.md
authored
57 It uses [binstruct](https://github.com/albertz/binstruct) for the serialization.
58
ccbaa00 @albertz development notes
authored
59
c1c5eae @albertz Update DevelopmentNotes.md
authored
60 ## Song attribute knowledge system
ccbaa00 @albertz development notes
authored
61
6533ef4 @albertz Update DevelopmentNotes.md
authored
62 Some of the initial ideas are presented in [`attribs.txt`](https://github.com/albertz/music-player/blob/master/attribs.txt). This is implemented now mostly for the [`Song` class](https://github.com/albertz/music-player/blob/master/Song.py).
ccbaa00 @albertz development notes
authored
63
64 There are several sources where we can get some song attribute from:
65
66 - The local `song.__dict__`.
67 - The database.
68 - The file metadata (e.g. artist, title, duration).
69 - Calculate it from the file (e.g. duration, fingerprint, ReplayGain).
70 - Look it up from some Internet service like MusicBrainz.
71
72 To have a generic attribute read interface which captures all different cases, there is the function:
73
74 Song.get(self, attrib, timeout, accuracy)
75
76 For each attrib, there might be functions:
77
78 - `Song._estimate_<attrib>`, which is supposed to be fast. This is called no matter what the `timeout` is, in case we did not get it from the database.
79 - `Song._calc_<attrib>`, which is supposed to return the exact value but is heavy to call. If this is needed, it will be executed in a seperate process.
80
6533ef4 @albertz Update DevelopmentNotes.md
authored
81 See [`Song`](https://github.com/albertz/music-player/blob/master/Song.py) for further reference.
ccbaa00 @albertz development notes
authored
82
83
c1c5eae @albertz Update DevelopmentNotes.md
authored
84 ## Playlist queue
ccbaa00 @albertz development notes
authored
85
6533ef4 @albertz Update DevelopmentNotes.md
authored
86 The playlist queue is managed by the [`queue`](https://github.com/albertz/music-player/blob/master/queue.py) module. It has the logic to autofill the queue if there are too less songs in it. The algorithm to automatically select a new song uses the random file queue generator. This is a lazy directory unfolder and random picker, implemented in [`RandomFileQueue`](https://github.com/albertz/music-player/blob/master/RandomFileQueue.py). Every time, it looks at a few songs and selects some song based on
ccbaa00 @albertz development notes
authored
87
88 - the song rating,
89 - the current recently played context (mostly the song genre / tag map).
90
91
f5e7960 @albertz Update DevelopmentNotes.md
authored
92 ## Debugging
93
94 The module [`stdinconsole`](stdinconsole.py), when started with `--shell`, provides a handy IPython shell to the running application (in addition to the GUI which is still loaded). This is quite helpful to play around. In addition, as said earlier, all the modules are reloadable. I made this so I don't need to interrupt my music playing when playing with the code.
Something went wrong with that request. Please try again.