1 amaroK VIS_PLAN - Created: 22-11-2003
6 In order to create a visualisation framework that is superior to anything
7 popular available for Linux today we should plan amaroK's thoroughly
8 before implementation. This document exists to map out our ideas and is
9 available for anyone to edit, please, if you have some good suggestion, or
10 experience with this kind of work, add some comments! Thanks, Max Howell
15 The document has no regimented formatting, but do try to keep the wordwrap set
16 the same! Feel free to recommend formatting if the document becomes
22 My initial thoughts were to make visualisations a separate process rather than
23 separate thread. The reasoning being, a crash in the vis won't crash amaroK,
24 threads can be unmanageable, *nix is good for new processes, we can use DCOP to
25 control the vis and presumable we just need to pass a handle to the relevant
26 arts server to the vis and leave it. Since the music playing bit is already a
27 separate process it makes sense to make the visualisation separate too! Also
28 this may mean that these visuals could be separate from amaroK and just depend
31 I was also thinking that this means it may be possible to not use Qt to
32 do rendering. There are probably better libraries for high speed graphics and if
33 there isn't a way to make DCOP not depend on a QApplication, then maybe we could
34 write something. It would be sorted if we could make something that can react to
35 arts sound output in general.
36 <markey> we could use SDL for 2d and OpenGL for 3d rendering.
38 I was also thinking it would be neat to embed the visuals somehow into amaroK,
39 so as the background in the playlist perhaps (I know, this would probably not
40 work well due to the need to re-render all the AA text all the time, but still
41 the idea is neat) This is similar to Sonique on Windows if anyone has ever used
44 If we make the visualisations not amaroK specific it may be possible to embed
45 visualisations into the Kicker, onto the desktop, etc.
47 Do we want more than an FFT of the audio data? Would other data
48 be useful to visuals at all? Beat detection certainly would be a useful thing to
49 offer the visualisations, and it would certainly stop every visual implementing
53 Vis Process Architecture
54 ========================
55 I suggest having a separate process for each visualization. Each vis process would
56 only load one visualization plugin. This way we have good crash safety and it's also
57 possible to develop and ship plugins separately from amaroK. So we have one "vis loader
58 skeleton" in amaroK, which will be instanciated whenever we need a vis. This loader could
59 get started with the vis plugin as cli argument. It would also contain all the socket and
60 interface needed to communicate with amaroK.
62 We should take care to keep the design as simple as possible.
64 <mxcl> Why make visualisations plugins as well as binaries? It seems sensible to have
65 visualisations as separate processes and then communicate with amK through the socket.
66 Why have the extra layer of plugins if you're going to force each process to only load
70 Merging Analyzer and Vis
71 ========================
72 If we decide on unifying vis and analyzer, the question arises how to get the rendered
73 bitmap graphic back into amaroK's playerwidget. It seems we have the following options:
75 * Writing it into a shared memory buffer. amaroK must then read the buffer and bitBlt()
76 the pixmap into the framebuffer
77 * Transferring the pixmap over a Unix socket (or UDP network socket). This can amount to
78 several megabytes per second. After the transfer amaroK must bitBlt() it to the
80 * Writing it directly into the framebuffer at the desired position, like a video overlay.
81 There might be technical problems doing so, and it will be difficult when the user
86 [Comment from muesli, to be integrated into the paragraphs above]
88 imho, it would be cool to offer this service via sockets. udp would fit per-
89 fectly, since it has to be realtime, anyways (better loose a packet and show
90 nothing, instead of a out-of-sync beat). e.g., you would be able to have
91 various of visualizations-clients connected to amarok, showing different
92 animations, at the same time. this would also remove the DCOP-dependency-chains
93 for the OpenGL clients.
95 right now, i can imagine two implementation methods:
97 A) transmit the frequency vector of the analyzer to the vis-client. beat-detection and
98 all that stuff gets done by the vis-client.
100 B) basic beat-detection and music analysis gets done by amarok itself. the
101 results of that process are sent to the vis-clients.
103 <mxcl> IMO it would be good to offer services like beat detection. This
104 way vis-writers have less to do and are more likely to write a vis since
105 beat-detection is already done, also it means beat-detection is likely to be better
106 as we will over time offer a really good implementation, and it means that if the user
107 has many visuals running, the beat-detection is only done once for all visualisations.
114 //FIXME <markey> beat detection code temporarily moved here
117 // Muesli's Beat Detection - A Night's Oddysee
118 // shift old elements
119 for ( uint x = 0; x < 18; ++x )
120 for ( uint y = 42; y > 0; --y ) m_beatEnergy[x][y] = m_beatEnergy[x][y - 1];
122 // get current energy values
123 for ( uint x = 0; x < pScopeVector->size(); ++x ) m_beatEnergy[x][0] = pScopeVector->at(x);
125 // compare to old elements and get averages
127 // double beatVariance[18];
128 // double beatMood[18];
130 for ( uint x = 0; x < 18; ++x )
133 for ( uint y = 1; y < 44; ++y ) beatAvg[x] += m_beatEnergy[x][y];
135 beatAvg[x] = beatAvg[x] / 43;
138 /* for ( uint x = 0; x < 18; ++x )
141 for ( uint y = 0; y < 42; ++y ) beatVariance[x] += (pow((m_beatEnergy[x][y] - beatAvg[x]), 2) / 43);
144 for ( uint x = 0; x < 18; ++x )
145 beatMood[x] = (-0.0025714 * beatVariance[x]) + 1.5142857;
148 // do we have a beat? let's dance!
149 /* int total_hits = 0;
150 for ( uint x = 0; x < 18; ++x )
152 double factor = cos( x * 4 ) * 18;
153 factor = beatAvg[x] * factor;
155 if ( m_beatEnergy[x][0] > factor )
158 kDebug() << "*CLAP* factor: " << factor << " - x: " << x << " - average energy: " << beatAvg[x] << " - current peak: " << m_beatEnergy[x][0] << endl;
162 if ( total_hits > 3 ) kDebug() << "***CLAPCLAPCLAP***" << endl;