summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/Visualisation.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
committermanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
commitffca21f2743a7b367fa212799c6e2fea6190dd5d (patch)
tree0608ea3a29cf644ec9ab204e2b4bb9bfaae1c381 /xbmc/addons/Visualisation.cpp
downloadkodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.gz
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.bz2
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.zip
initial commit for kodi master
Diffstat (limited to 'xbmc/addons/Visualisation.cpp')
-rw-r--r--xbmc/addons/Visualisation.cpp486
1 files changed, 486 insertions, 0 deletions
diff --git a/xbmc/addons/Visualisation.cpp b/xbmc/addons/Visualisation.cpp
new file mode 100644
index 0000000..a64ee59
--- /dev/null
+++ b/xbmc/addons/Visualisation.cpp
@@ -0,0 +1,486 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "system.h"
21#include "Visualisation.h"
22#include "utils/fft.h"
23#include "GUIInfoManager.h"
24#include "Application.h"
25#include "guilib/GraphicContext.h"
26#include "guilib/WindowIDs.h"
27#include "music/tags/MusicInfoTag.h"
28#include "settings/Settings.h"
29#include "settings/AdvancedSettings.h"
30#include "settings/DisplaySettings.h"
31#include "windowing/WindowingFactory.h"
32#include "utils/URIUtils.h"
33#include "utils/StringUtils.h"
34#include "cores/IPlayer.h"
35#include "cores/AudioEngine/AEFactory.h"
36#ifdef TARGET_POSIX
37#include <dlfcn.h>
38#include "filesystem/SpecialProtocol.h"
39#endif
40
41using namespace std;
42using namespace MUSIC_INFO;
43using namespace ADDON;
44
45CAudioBuffer::CAudioBuffer(int iSize)
46{
47 m_iLen = iSize;
48 m_pBuffer = new float[iSize];
49}
50
51CAudioBuffer::~CAudioBuffer()
52{
53 delete [] m_pBuffer;
54}
55
56const float* CAudioBuffer::Get() const
57{
58 return m_pBuffer;
59}
60
61void CAudioBuffer::Set(const float* psBuffer, int iSize)
62{
63 if (iSize<0)
64 return;
65 memcpy(m_pBuffer, psBuffer, iSize * sizeof(float));
66 for (int i = iSize; i < m_iLen; ++i) m_pBuffer[i] = 0;
67}
68
69bool CVisualisation::Create(int x, int y, int w, int h, void *device)
70{
71 m_pInfo = new VIS_PROPS;
72 #ifdef HAS_DX
73 m_pInfo->device = g_Windowing.Get3DDevice();
74#else
75 m_pInfo->device = NULL;
76#endif
77 m_pInfo->x = x;
78 m_pInfo->y = y;
79 m_pInfo->width = w;
80 m_pInfo->height = h;
81 m_pInfo->pixelRatio = g_graphicsContext.GetResInfo().fPixelRatio;
82
83 m_pInfo->name = strdup(Name().c_str());
84 m_pInfo->presets = strdup(CSpecialProtocol::TranslatePath(Path()).c_str());
85 m_pInfo->profile = strdup(CSpecialProtocol::TranslatePath(Profile()).c_str());
86 m_pInfo->submodule = NULL;
87
88 if (CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Create() == ADDON_STATUS_OK)
89 {
90 // Start the visualisation
91 std::string strFile = URIUtils::GetFileName(g_application.CurrentFile());
92 CLog::Log(LOGDEBUG, "Visualisation::Start()\n");
93 try
94 {
95 m_pStruct->Start(m_iChannels, m_iSamplesPerSec, m_iBitsPerSample, strFile.c_str());
96 }
97 catch (std::exception e)
98 {
99 HandleException(e, "m_pStruct->Start() (CVisualisation::Create)");
100 return false;
101 }
102
103 GetPresets();
104
105 if (GetSubModules())
106 m_pInfo->submodule = strdup(CSpecialProtocol::TranslatePath(m_submodules.front()).c_str());
107 else
108 m_pInfo->submodule = NULL;
109
110 CreateBuffers();
111
112 CAEFactory::RegisterAudioCallback(this);
113
114 return true;
115 }
116 return false;
117}
118
119void CVisualisation::Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName)
120{
121 // notify visz. that new song has been started
122 // pass it the nr of audio channels, sample rate, bits/sample and offcourse the songname
123 if (Initialized())
124 {
125 try
126 {
127 m_pStruct->Start(iChannels, iSamplesPerSec, iBitsPerSample, strSongName.c_str());
128 }
129 catch (std::exception e)
130 {
131 HandleException(e, "m_pStruct->Start (CVisualisation::Start)");
132 }
133 }
134}
135
136void CVisualisation::AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
137{
138 // pass audio data to visz.
139 // audio data: is short audiodata [channel][iAudioDataLength] containing the raw audio data
140 // iAudioDataLength = length of audiodata array
141 // pFreqData = fft-ed audio data
142 // iFreqDataLength = length of pFreqData
143 if (Initialized())
144 {
145 try
146 {
147 m_pStruct->AudioData(pAudioData, iAudioDataLength, pFreqData, iFreqDataLength);
148 }
149 catch (std::exception e)
150 {
151 HandleException(e, "m_pStruct->AudioData (CVisualisation::AudioData)");
152 }
153 }
154}
155
156void CVisualisation::Render()
157{
158 // ask visz. to render itself
159 g_graphicsContext.BeginPaint();
160 if (Initialized())
161 {
162 try
163 {
164 m_pStruct->Render();
165 }
166 catch (std::exception e)
167 {
168 HandleException(e, "m_pStruct->Render (CVisualisation::Render)");
169 }
170 }
171 g_graphicsContext.EndPaint();
172}
173
174void CVisualisation::Stop()
175{
176 CAEFactory::UnregisterAudioCallback();
177 if (Initialized())
178 {
179 CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Stop();
180 }
181}
182
183void CVisualisation::GetInfo(VIS_INFO *info)
184{
185 if (Initialized())
186 {
187 try
188 {
189 m_pStruct->GetInfo(info);
190 }
191 catch (std::exception e)
192 {
193 HandleException(e, "m_pStruct->GetInfo (CVisualisation::GetInfo)");
194 }
195 }
196}
197
198bool CVisualisation::OnAction(VIS_ACTION action, void *param)
199{
200 if (!Initialized())
201 return false;
202
203 // see if vis wants to handle the input
204 // returns false if vis doesnt want the input
205 // returns true if vis handled the input
206 try
207 {
208 if (action != VIS_ACTION_NONE && m_pStruct->OnAction)
209 {
210 // if this is a VIS_ACTION_UPDATE_TRACK action, copy relevant
211 // tags from CMusicInfoTag to VisTag
212 if ( action == VIS_ACTION_UPDATE_TRACK && param )
213 {
214 const CMusicInfoTag* tag = (const CMusicInfoTag*)param;
215 std::string artist(StringUtils::Join(tag->GetArtist(), g_advancedSettings.m_musicItemSeparator));
216 std::string albumArtist(StringUtils::Join(tag->GetAlbumArtist(), g_advancedSettings.m_musicItemSeparator));
217 std::string genre(StringUtils::Join(tag->GetGenre(), g_advancedSettings.m_musicItemSeparator));
218
219 VisTrack track;
220 track.title = tag->GetTitle().c_str();
221 track.artist = artist.c_str();
222 track.album = tag->GetAlbum().c_str();
223 track.albumArtist = albumArtist.c_str();
224 track.genre = genre.c_str();
225 track.comment = tag->GetComment().c_str();
226 track.lyrics = tag->GetLyrics().c_str();
227 track.trackNumber = tag->GetTrackNumber();
228 track.discNumber = tag->GetDiscNumber();
229 track.duration = tag->GetDuration();
230 track.year = tag->GetYear();
231 track.rating = tag->GetRating();
232
233 return m_pStruct->OnAction(action, &track);
234 }
235 return m_pStruct->OnAction((int)action, param);
236 }
237 }
238 catch (std::exception e)
239 {
240 HandleException(e, "m_pStruct->OnAction (CVisualisation::OnAction)");
241 }
242 return false;
243}
244
245void CVisualisation::OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample)
246{
247 if (!m_pStruct)
248 return ;
249 CLog::Log(LOGDEBUG, "OnInitialize() started");
250
251 m_iChannels = iChannels;
252 m_iSamplesPerSec = iSamplesPerSec;
253 m_iBitsPerSample = iBitsPerSample;
254 UpdateTrack();
255
256 CLog::Log(LOGDEBUG, "OnInitialize() done");
257}
258
259void CVisualisation::OnAudioData(const float* pAudioData, int iAudioDataLength)
260{
261 if (!m_pStruct)
262 return ;
263
264 // FIXME: iAudioDataLength should never be less than 0
265 if (iAudioDataLength<0)
266 return;
267
268 // Save our audio data in the buffers
269 unique_ptr<CAudioBuffer> pBuffer ( new CAudioBuffer(AUDIO_BUFFER_SIZE) );
270 pBuffer->Set(pAudioData, iAudioDataLength);
271 m_vecBuffers.push_back( pBuffer.release() );
272
273 if ( (int)m_vecBuffers.size() < m_iNumBuffers) return ;
274
275 unique_ptr<CAudioBuffer> ptrAudioBuffer ( m_vecBuffers.front() );
276 m_vecBuffers.pop_front();
277 // Fourier transform the data if the vis wants it...
278 if (m_bWantsFreq)
279 {
280 const float *psAudioData = ptrAudioBuffer->Get();
281 memcpy(m_fFreq, psAudioData, AUDIO_BUFFER_SIZE * sizeof(float));
282
283 // FFT the data
284 twochanwithwindow(m_fFreq, AUDIO_BUFFER_SIZE);
285
286 // Normalize the data
287 float fMinData = (float)AUDIO_BUFFER_SIZE * AUDIO_BUFFER_SIZE * 3 / 8 * 0.5 * 0.5; // 3/8 for the Hann window, 0.5 as minimum amplitude
288 float fInvMinData = 1.0f/fMinData;
289 for (int i = 0; i < AUDIO_BUFFER_SIZE + 2; i++)
290 {
291 m_fFreq[i] *= fInvMinData;
292 }
293
294 // Transfer data to our visualisation
295 AudioData(psAudioData, AUDIO_BUFFER_SIZE, m_fFreq, AUDIO_BUFFER_SIZE);
296 }
297 else
298 { // Transfer data to our visualisation
299 AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, NULL, 0);
300 }
301 return ;
302}
303
304void CVisualisation::CreateBuffers()
305{
306 ClearBuffers();
307
308 // Get the number of buffers from the current vis
309 VIS_INFO info;
310 m_pStruct->GetInfo(&info);
311 m_iNumBuffers = info.iSyncDelay + 1;
312 m_bWantsFreq = (info.bWantsFreq != 0);
313 if (m_iNumBuffers > MAX_AUDIO_BUFFERS)
314 m_iNumBuffers = MAX_AUDIO_BUFFERS;
315 if (m_iNumBuffers < 1)
316 m_iNumBuffers = 1;
317}
318
319void CVisualisation::ClearBuffers()
320{
321 m_bWantsFreq = false;
322 m_iNumBuffers = 0;
323
324 while (!m_vecBuffers.empty())
325 {
326 CAudioBuffer* pAudioBuffer = m_vecBuffers.front();
327 delete pAudioBuffer;
328 m_vecBuffers.pop_front();
329 }
330 for (int j = 0; j < AUDIO_BUFFER_SIZE*2; j++)
331 {
332 m_fFreq[j] = 0.0f;
333 }
334}
335
336bool CVisualisation::UpdateTrack()
337{
338 bool handled = false;
339 if (Initialized())
340 {
341 // get the current album art filename
342 m_AlbumThumb = CSpecialProtocol::TranslatePath(g_infoManager.GetImage(MUSICPLAYER_COVER, WINDOW_INVALID));
343
344 // get the current track tag
345 const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag();
346
347 if (m_AlbumThumb == "DefaultAlbumCover.png")
348 m_AlbumThumb = "";
349 else
350 CLog::Log(LOGDEBUG,"Updating visualisation albumart: %s", m_AlbumThumb.c_str());
351
352 // inform the visualisation of the current album art
353 if (OnAction( VIS_ACTION_UPDATE_ALBUMART, (void*)( m_AlbumThumb.c_str() ) ) )
354 handled = true;
355
356 // inform the visualisation of the current track's tag information
357 if ( tag && OnAction( VIS_ACTION_UPDATE_TRACK, (void*)tag ) )
358 handled = true;
359 }
360 return handled;
361}
362
363bool CVisualisation::GetPresetList(std::vector<std::string> &vecpresets)
364{
365 vecpresets = m_presets;
366 return !m_presets.empty();
367}
368
369bool CVisualisation::GetPresets()
370{
371 m_presets.clear();
372 char **presets = NULL;
373 unsigned int entries = 0;
374 try
375 {
376 entries = m_pStruct->GetPresets(&presets);
377 }
378 catch (std::exception e)
379 {
380 HandleException(e, "m_pStruct->OnAction (CVisualisation::GetPresets)");
381 return false;
382 }
383 if (presets && entries > 0)
384 {
385 for (unsigned i=0; i < entries; i++)
386 {
387 if (presets[i])
388 {
389 m_presets.push_back(presets[i]);
390 }
391 }
392 }
393 return (!m_presets.empty());
394}
395
396bool CVisualisation::GetSubModuleList(std::vector<std::string> &vecmodules)
397{
398 vecmodules = m_submodules;
399 return !m_submodules.empty();
400}
401
402bool CVisualisation::GetSubModules()
403{
404 m_submodules.clear();
405 char **modules = NULL;
406 unsigned int entries = 0;
407 try
408 {
409 entries = m_pStruct->GetSubModules(&modules);
410 }
411 catch (...)
412 {
413 CLog::Log(LOGERROR, "Exception in Visualisation::GetSubModules()");
414 return false;
415 }
416 if (modules && entries > 0)
417 {
418 for (unsigned i=0; i < entries; i++)
419 {
420 if (modules[i])
421 {
422 m_submodules.push_back(modules[i]);
423 }
424 }
425 }
426 return (!m_submodules.empty());
427}
428
429std::string CVisualisation::GetFriendlyName(const std::string& strVisz,
430 const std::string& strSubModule)
431{
432 // should be of the format "moduleName (visName)"
433 return strSubModule + " (" + strVisz + ")";
434}
435
436bool CVisualisation::IsLocked()
437{
438 if (!m_presets.empty())
439 {
440 if (!m_pStruct)
441 return false;
442
443 return m_pStruct->IsLocked();
444 }
445 return false;
446}
447
448void CVisualisation::Destroy()
449{
450 // Free what was allocated in method CVisualisation::Create
451 if (m_pInfo)
452 {
453 free((void *) m_pInfo->name);
454 free((void *) m_pInfo->presets);
455 free((void *) m_pInfo->profile);
456 free((void *) m_pInfo->submodule);
457
458 delete m_pInfo;
459 m_pInfo = NULL;
460 }
461
462 CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Destroy();
463}
464
465unsigned CVisualisation::GetPreset()
466{
467 unsigned index = 0;
468 try
469 {
470 index = m_pStruct->GetPreset();
471 }
472 catch(...)
473 {
474 return 0;
475 }
476 return index;
477}
478
479std::string CVisualisation::GetPresetName()
480{
481 if (!m_presets.empty())
482 return m_presets[GetPreset()];
483 else
484 return "";
485}
486