2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
21 #include "TimidityCodec.h"
23 #include "../DllLoader/LibraryLoader.h"
24 #include "../DllLoader/SoLoader.h"
25 #include "../DllLoader/DllLoader.h"
27 #include "utils/log.h"
28 #include "filesystem/SpecialProtocol.h"
30 #include "../DllLoader/Win32DllLoader.h"
33 static const char * DEFAULT_SOUNDFONT_FILE = "special://masterprofile/timidity/soundfont.sf2";
35 TimidityCodec::TimidityCodec()
42 memset(&m_dll, 0, sizeof(m_dll));
45 TimidityCodec::~TimidityCodec()
50 bool TimidityCodec::Init(const CStdString &strFile, unsigned int filecache)
52 // We do not need to init/load Timidity more than once
54 // Note the above comment makes no sense as TimidityCodec is not a singleton.
55 // In fact, MID_CODEC can ONLY be opened and used by one instance (lot's of statics).
56 // So to work around this problem with MID_CODEC, we need to make sure that
57 // each instance of TimidityCodec has it's own instance of MID_CODEC. Do this by
58 // coping DLL_PATH_MID_CODEC into special://temp and using a unique name. Then
59 // loading this unique named MID_CODEC as the library.
60 // This forces the shared lib loader to load a per-instance copy of MID_CODEC.
64 m_loader_name = CUtil::GetNextFilename("special://temp/libtimidity-%03d.so", 999);
65 XFILE::CFile::Cache(DLL_PATH_MID_CODEC, m_loader_name);
67 m_loader = new SoLoader(m_loader_name.c_str());
69 m_loader_name = CUtil::GetNextFilename("special://temp/libtimidity-%03d.dll", 999);
70 XFILE::CFile::Cache(DLL_PATH_MID_CODEC, m_loader_name);
72 m_loader = new Win32DllLoader(m_loader_name);
76 XFILE::CFile::Delete(m_loader_name);
80 if (!m_loader->Load())
84 XFILE::CFile::Delete(m_loader_name);
88 m_loader->ResolveExport("DLL_Init",(void**)&m_dll.Init);
89 m_loader->ResolveExport("DLL_LoadMID",(void**)&m_dll.LoadMID);
90 m_loader->ResolveExport("DLL_FreeMID",(void**)&m_dll.FreeMID);
91 m_loader->ResolveExport("DLL_FillBuffer",(void**)&m_dll.FillBuffer);
92 m_loader->ResolveExport("DLL_GetLength",(void**)&m_dll.GetLength);
93 m_loader->ResolveExport("DLL_Cleanup",(void**)&m_dll.Cleanup);
94 m_loader->ResolveExport("DLL_ErrorMsg",(void**)&m_dll.ErrorMsg);
95 m_loader->ResolveExport("DLL_Seek",(void**)&m_dll.Seek);
97 if ( m_dll.Init( DEFAULT_SOUNDFONT_FILE ) == 0 )
99 CLog::Log(LOGERROR,"TimidityCodec: cannot init codec: %s", m_dll.ErrorMsg() );
100 CLog::Log(LOGERROR,"Failed to initialize MIDI codec. Please make sure you configured MIDI playback according to http://wiki.xbmc.org/?title=HOW-TO:_Setup_XBMC_for_karaoke" );
105 // Free the song if already loaded
107 m_dll.FreeMID( m_mid );
109 CStdString file = strFile;
113 CStdString file = CUtil::GetNextFilename("special://temp/midi%03d.mid",999);
114 XFILE::CFile::Cache(strFile,file);
118 m_mid = m_dll.LoadMID(CSpecialProtocol::TranslatePath(url.Get()).c_str());
121 CLog::Log(LOGERROR,"TimidityCodec: error opening file %s: %s",strFile.c_str(), m_dll.ErrorMsg());
126 m_SampleRate = 48000;
127 m_BitsPerSample = 16;
128 m_DataFormat = AE_FMT_S16NE;
129 m_TotalTime = (int64_t)m_dll.GetLength(m_mid);
134 void TimidityCodec::DeInit()
137 m_dll.FreeMID(m_mid);
143 XFILE::CFile::Delete(m_loader_name);
150 int64_t TimidityCodec::Seek(int64_t iSeekTime)
152 int64_t result = (int64_t)m_dll.Seek(m_mid,(unsigned long)iSeekTime);
153 m_iDataPos = result/1000*48000*4;
158 int TimidityCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
160 if (m_iDataPos == -1)
165 if (m_iDataPos >= m_TotalTime/1000*48000*4)
168 if ((*actualsize=m_dll.FillBuffer(m_mid,(char*)pBuffer,size))> 0)
170 m_iDataPos += *actualsize;
177 bool TimidityCodec::CanInit()
179 return XFILE::CFile::Exists("special://xbmc/system/players/paplayer/timidity/timidity.cfg")
180 || XFILE::CFile::Exists( DEFAULT_SOUNDFONT_FILE );
183 bool TimidityCodec::IsSupportedFormat(const CStdString& strExt)
185 if (strExt == "mid" || strExt == "kar")