mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
725 lines
18 KiB
C++
725 lines
18 KiB
C++
/*
|
|
* Copyright (C) 2005-2013 Team XBMC
|
|
* http://xbmc.org
|
|
*
|
|
* This Program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with XBMC; see the file COPYING. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "system.h"
|
|
#include "utils/log.h"
|
|
#include "CdgParser.h"
|
|
#include "Application.h"
|
|
#include "Util.h"
|
|
#include "utils/URIUtils.h"
|
|
#include "AudioContext.h"
|
|
#include "GUIInfoManager.h"
|
|
#include "music/tags/MusicInfoTag.h"
|
|
#include "GUIWindowManager.h"
|
|
#include "settings/Settings.h"
|
|
|
|
using namespace MUSIC_INFO;
|
|
using namespace XFILE;
|
|
|
|
//CdgLoader
|
|
CCdgLoader::CCdgLoader()
|
|
{
|
|
m_strFileName.Empty();
|
|
m_CdgFileState = FILE_NOT_LOADED;
|
|
m_pBuffer = NULL;
|
|
m_uiFileLength = 0;
|
|
m_uiLoadedBytes = 0;
|
|
m_uiStreamChunk = STREAM_CHUNK;
|
|
}
|
|
CCdgLoader::~CCdgLoader()
|
|
{
|
|
StopStream();
|
|
}
|
|
|
|
void CCdgLoader::StreamFile(CStdString strfilename)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
m_strFileName = strfilename;
|
|
URIUtils::RemoveExtension(m_strFileName);
|
|
m_strFileName += ".cdg";
|
|
CThread::Create(false);
|
|
}
|
|
|
|
void CCdgLoader::StopStream()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
CThread::StopThread();
|
|
m_uiLoadedBytes = 0;
|
|
m_CdgFileState = FILE_NOT_LOADED;
|
|
if (m_pBuffer)
|
|
SAFE_DELETE_ARRAY(m_pBuffer);
|
|
}
|
|
|
|
SubCode* CCdgLoader::GetCurSubCode()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
SubCode* pFirst = GetFirstLoaded();
|
|
SubCode* pLast = GetLastLoaded();
|
|
if (!pFirst || !pLast || !m_pSubCode) return NULL;
|
|
if (m_pSubCode < pFirst || m_pSubCode > pLast) return NULL;
|
|
return m_pSubCode;
|
|
}
|
|
bool CCdgLoader::SetNextSubCode()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
SubCode* pFirst = GetFirstLoaded();
|
|
SubCode* pLast = GetLastLoaded();
|
|
if (!pFirst || !pLast || !m_pSubCode) return false;
|
|
if (m_pSubCode < pFirst || m_pSubCode >= pLast) return false;
|
|
m_pSubCode++;
|
|
return true;
|
|
}
|
|
errCode CCdgLoader::GetFileState()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
return m_CdgFileState;
|
|
}
|
|
CStdString CCdgLoader::GetFileName()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
return m_strFileName;
|
|
}
|
|
SubCode* CCdgLoader::GetFirstLoaded()
|
|
{
|
|
if (!m_uiLoadedBytes)
|
|
return NULL;
|
|
return (SubCode*) m_pBuffer;
|
|
}
|
|
SubCode* CCdgLoader::GetLastLoaded()
|
|
{
|
|
if (m_uiLoadedBytes < sizeof(SubCode) || m_uiLoadedBytes > m_uiFileLength )
|
|
return NULL;
|
|
return ((SubCode*) (m_pBuffer)) + m_uiLoadedBytes / sizeof(SubCode) - 1;
|
|
}
|
|
void CCdgLoader::OnStartup()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!CFile::Exists(m_strFileName))
|
|
{
|
|
m_CdgFileState = FILE_ERR_NOT_FOUND;
|
|
return ;
|
|
}
|
|
if (!m_File.Open(m_strFileName, TRUE))
|
|
{
|
|
m_CdgFileState = FILE_ERR_OPENING;
|
|
return ;
|
|
}
|
|
m_uiFileLength = (int)m_File.GetLength(); // ASSUMES FILELENGTH IS LESS THAN 2^32 bytes!!!
|
|
if (!m_uiFileLength) return ;
|
|
m_File.Seek(0, SEEK_SET);
|
|
if (m_pBuffer)
|
|
SAFE_DELETE_ARRAY(m_pBuffer);
|
|
m_pBuffer = new BYTE[m_uiFileLength];
|
|
if (!m_pBuffer)
|
|
{
|
|
m_CdgFileState = FILE_ERR_NO_MEM;
|
|
return ;
|
|
}
|
|
m_uiLoadedBytes = 0;
|
|
m_pSubCode = (SubCode*) m_pBuffer;
|
|
m_CdgFileState = FILE_LOADING;
|
|
}
|
|
|
|
void CCdgLoader::Process()
|
|
{
|
|
if (m_CdgFileState != FILE_LOADING && m_CdgFileState != FILE_SKIP) return ;
|
|
|
|
if (m_uiFileLength < m_uiStreamChunk)
|
|
m_uiLoadedBytes = m_File.Read(m_pBuffer, m_uiFileLength);
|
|
else
|
|
{
|
|
UINT uiNumReadings = m_uiFileLength / m_uiStreamChunk;
|
|
UINT uiRemainder = m_uiFileLength % m_uiStreamChunk;
|
|
UINT uiCurReading = 0;
|
|
while (!CThread::m_bStop && uiCurReading < uiNumReadings)
|
|
{
|
|
m_uiLoadedBytes += m_File.Read(m_pBuffer + m_uiLoadedBytes, m_uiStreamChunk);
|
|
uiCurReading++;
|
|
}
|
|
if (uiRemainder && m_uiLoadedBytes + uiRemainder == m_uiFileLength)
|
|
m_uiLoadedBytes += m_File.Read(m_pBuffer + m_uiLoadedBytes, uiRemainder);
|
|
}
|
|
}
|
|
|
|
void CCdgLoader::OnExit()
|
|
{
|
|
m_File.Close();
|
|
if (m_uiFileLength && m_uiLoadedBytes == m_uiFileLength)
|
|
m_CdgFileState = FILE_LOADED;
|
|
}
|
|
//CdgReader
|
|
CCdgReader::CCdgReader()
|
|
{
|
|
m_pLoader = NULL;
|
|
m_fStartingTime = 0.0f;
|
|
m_fAVDelay = 0.0f;
|
|
m_uiNumReadSubCodes = 0;
|
|
m_Cdg.ClearDisplay();
|
|
}
|
|
CCdgReader::~CCdgReader()
|
|
{
|
|
StopThread();
|
|
}
|
|
|
|
|
|
bool CCdgReader::Attach(CCdgLoader* pLoader)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!m_pLoader)
|
|
m_pLoader = pLoader;
|
|
if (!m_pLoader) return false;
|
|
return true;
|
|
}
|
|
void CCdgReader::DetachLoader()
|
|
{
|
|
StopThread();
|
|
CSingleLock lock (m_CritSection);
|
|
m_pLoader = NULL;
|
|
}
|
|
bool CCdgReader::Start(float fStartTime)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!m_pLoader) return false;
|
|
m_fStartingTime = fStartTime;
|
|
SetAVDelay(g_advancedSettings.m_karaokeSyncDelay);
|
|
m_uiNumReadSubCodes = 0;
|
|
m_Cdg.ClearDisplay();
|
|
m_FileState = FILE_LOADED;
|
|
CThread::Create(false);
|
|
return true;
|
|
}
|
|
|
|
void CCdgReader::SetAVDelay(float fDelay)
|
|
{
|
|
m_fAVDelay = fDelay;
|
|
#ifdef _DEBUG
|
|
m_fAVDelay -= DEBUG_AVDELAY_MOD;
|
|
#endif
|
|
}
|
|
float CCdgReader::GetAVDelay()
|
|
{
|
|
return m_fAVDelay;
|
|
}
|
|
errCode CCdgReader::GetFileState()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
|
|
if (m_FileState == FILE_SKIP)
|
|
return m_FileState;
|
|
|
|
if (!m_pLoader) return FILE_NOT_LOADED;
|
|
return m_pLoader->GetFileState();
|
|
}
|
|
CCdg* CCdgReader::GetCdg()
|
|
{
|
|
return (CCdg*) &m_Cdg;
|
|
}
|
|
|
|
CStdString CCdgReader::GetFileName()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pLoader)
|
|
return m_pLoader->GetFileName();
|
|
return "";
|
|
}
|
|
void CCdgReader::ReadUpToTime(float secs)
|
|
{
|
|
if (secs < 0) return ;
|
|
if (!(m_pLoader->GetCurSubCode())) return ;
|
|
|
|
UINT uiFinalOffset = (UINT) (secs * PARSING_FREQ);
|
|
if ( m_uiNumReadSubCodes >= uiFinalOffset) return ;
|
|
UINT i;
|
|
for (i = m_uiNumReadSubCodes; i <= uiFinalOffset; i++)
|
|
{
|
|
m_Cdg.ReadSubCode(m_pLoader->GetCurSubCode());
|
|
if (m_pLoader->SetNextSubCode())
|
|
m_uiNumReadSubCodes++;
|
|
}
|
|
}
|
|
|
|
void CCdgReader::SkipUpToTime(float secs)
|
|
{
|
|
if (secs < 0) return ;
|
|
m_FileState= FILE_SKIP;
|
|
|
|
UINT uiFinalOffset = (UINT) (secs * PARSING_FREQ);
|
|
// is this needed?
|
|
if ( m_uiNumReadSubCodes > uiFinalOffset) return ;
|
|
for (UINT i = m_uiNumReadSubCodes; i <= uiFinalOffset; i++)
|
|
{
|
|
//m_Cdg.ReadSubCode(m_pLoader->GetCurSubCode());
|
|
if (m_pLoader->SetNextSubCode())
|
|
m_uiNumReadSubCodes++;
|
|
}
|
|
m_FileState = FILE_LOADING;
|
|
}
|
|
|
|
void CCdgReader::OnStartup()
|
|
{}
|
|
|
|
void CCdgReader::Process()
|
|
{
|
|
double fCurTime = 0.0f;
|
|
bool bIsFirstPass = true;
|
|
double fNewTime=0.f;
|
|
CStdString strExt;
|
|
URIUtils::GetExtension(m_pLoader->GetFileName(),strExt);
|
|
strExt = m_pLoader->GetFileName().substr(0,m_pLoader->GetFileName().size()-strExt.size());
|
|
|
|
while (!CThread::m_bStop)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
double fDiff;
|
|
const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag();
|
|
if (!tag || tag->GetURL().substr(0,strExt.size()) != strExt)
|
|
{
|
|
Sleep(15);
|
|
if (CThread::m_bStop)
|
|
return;
|
|
|
|
URIUtils::GetExtension(m_pLoader->GetFileName(),strExt);
|
|
strExt = m_pLoader->GetFileName().substr(0,m_pLoader->GetFileName().size()-strExt.size());
|
|
|
|
fDiff = 0.f;
|
|
}
|
|
else
|
|
{
|
|
fNewTime=g_application.GetTime();
|
|
fDiff = fNewTime-fCurTime-m_fAVDelay;
|
|
}
|
|
if (fDiff < -0.3f)
|
|
{
|
|
CStdString strFile = m_pLoader->GetFileName();
|
|
m_pLoader->StopStream();
|
|
while (m_pLoader->GetCurSubCode()) {}
|
|
m_pLoader->StreamFile(strFile);
|
|
m_uiNumReadSubCodes = 0;
|
|
m_Cdg.ClearDisplay();
|
|
fNewTime = g_application.GetTime();
|
|
SkipUpToTime((float)fNewTime-m_fAVDelay);
|
|
}
|
|
else
|
|
ReadUpToTime((float)fNewTime-m_fAVDelay);
|
|
|
|
fCurTime = fNewTime;
|
|
lock.Leave();
|
|
Sleep(15);
|
|
}
|
|
}
|
|
|
|
void CCdgReader::OnExit()
|
|
{}
|
|
|
|
|
|
//CdgRenderer
|
|
CCdgRenderer::CCdgRenderer()
|
|
{
|
|
m_pd3dDevice = NULL;
|
|
m_pCdgTexture = NULL;
|
|
m_pReader = NULL;
|
|
m_pCdg = NULL;
|
|
m_bRender = false;
|
|
m_bgAlpha = 0x00000000;
|
|
m_fgAlpha = 0xFF000000;
|
|
}
|
|
|
|
|
|
CCdgRenderer::~CCdgRenderer()
|
|
{
|
|
ReleaseGraphics();
|
|
}
|
|
|
|
bool CCdgRenderer::Attach(CCdgReader* pReader)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!m_pReader)
|
|
m_pReader = pReader;
|
|
if (!m_pReader) return false;
|
|
if (!m_pCdg)
|
|
m_pCdg = m_pReader->GetCdg();
|
|
if (!m_pCdg) return false;
|
|
return true;
|
|
}
|
|
void CCdgRenderer::DetachReader()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
m_pReader = NULL;
|
|
m_pCdg = NULL;
|
|
}
|
|
|
|
void CCdgRenderer::Render()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!m_pReader) return ;
|
|
m_FileState = m_pReader->GetFileState();
|
|
if (m_FileState == FILE_NOT_LOADED || m_FileState == FILE_SKIP) return ;
|
|
if (m_FileState == FILE_LOADED || m_FileState == FILE_LOADING )
|
|
{
|
|
if (!m_bRender) return ;
|
|
UpdateTexture();
|
|
DrawTexture();
|
|
return ;
|
|
}
|
|
else
|
|
{
|
|
CStdString strMessage, strFileName;
|
|
strFileName = URIUtils::GetFileName(m_pReader->GetFileName());
|
|
switch (m_FileState)
|
|
{
|
|
case FILE_ERR_NOT_FOUND:
|
|
strMessage.Format("%s not found", strFileName.c_str());
|
|
break;
|
|
case FILE_ERR_OPENING:
|
|
strMessage.Format("Error opening %s", strFileName.c_str());
|
|
break;
|
|
case FILE_ERR_LOADING:
|
|
strMessage.Format("Error loading %s", strFileName.c_str());
|
|
break;
|
|
case FILE_ERR_NO_MEM:
|
|
strMessage = "Out of memory";
|
|
break;
|
|
}
|
|
// don't render the message to the screen, just log it
|
|
// Hmmm. Can't seem to be able to log
|
|
// CLog::Log(LOGWARNING, "Karaoke CDG Renderer: %s", strMessage.c_str());
|
|
/* CGUIFont* pFont = g_fontManager.GetFont("font14");
|
|
if(pFont)
|
|
pFont->DrawText(60,60, 0xffffffff, strMessage);*/
|
|
}
|
|
}
|
|
|
|
bool CCdgRenderer::InitGraphics()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!m_pd3dDevice)
|
|
m_pd3dDevice = g_graphicsContext.Get3DDevice();
|
|
if (!m_pd3dDevice) return false;
|
|
|
|
// set the colours
|
|
m_bgAlpha = 0;
|
|
if (g_guiSettings.GetString("musicplayer.visualisation").Equals("None"))
|
|
m_bgAlpha = 0xff000000;
|
|
m_fgAlpha = 0xff000000;
|
|
|
|
if (!m_pCdgTexture)
|
|
m_pd3dDevice->CreateTexture(WIDTH, HEIGHT, 0, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_MANAGED, &m_pCdgTexture);
|
|
if (!m_pCdgTexture) return false;
|
|
m_bRender = true;
|
|
return true;
|
|
}
|
|
|
|
void CCdgRenderer::ReleaseGraphics()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
SAFE_RELEASE(m_pCdgTexture);
|
|
m_bRender = false;
|
|
}
|
|
|
|
void CCdgRenderer::DrawTexture()
|
|
{
|
|
m_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
|
|
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
|
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
|
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
|
|
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
|
|
m_pd3dDevice->SetTexture(0, m_pCdgTexture);
|
|
|
|
m_pd3dDevice->Begin(D3DPT_QUADLIST);
|
|
|
|
RESOLUTION res = g_graphicsContext.GetVideoResolution();
|
|
m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)BORDERWIDTH, (float) BORDERHEIGHT);
|
|
m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)g_settings.m_ResInfo[res].Overscan.left, (float) g_settings.m_ResInfo[res].Overscan.top, 0, 0 );
|
|
|
|
m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)(WIDTH - BORDERWIDTH), (float) BORDERHEIGHT);
|
|
m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)g_settings.m_ResInfo[res].Overscan.right, (float) g_settings.m_ResInfo[res].Overscan.top, 0, 0 );
|
|
|
|
m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)(WIDTH - BORDERWIDTH), (float)(HEIGHT - BORDERHEIGHT));
|
|
m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)g_settings.m_ResInfo[res].Overscan.right, (float) g_settings.m_ResInfo[res].Overscan.bottom, 0, 0);
|
|
|
|
m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, (float)BORDERWIDTH, (float)(HEIGHT - BORDERHEIGHT));
|
|
m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, (float)g_settings.m_ResInfo[res].Overscan.left, (float) g_settings.m_ResInfo[res].Overscan.bottom, 0, 0 );
|
|
|
|
m_pd3dDevice->End();
|
|
}
|
|
|
|
void CCdgRenderer::UpdateTexture()
|
|
{
|
|
D3DLOCKED_RECT LockedRect;
|
|
m_pCdgTexture->LockRect(0, &LockedRect, NULL, 0L);
|
|
for (UINT j = 0; j < HEIGHT; j++ )
|
|
{
|
|
DWORD *texel = (DWORD *)((BYTE *)LockedRect.pBits + j * LockedRect.Pitch);
|
|
for (UINT i = 0; i < WIDTH; i++ )
|
|
{
|
|
BYTE ClutOffset = m_pCdg->GetClutOffset(j + m_pCdg->GetVOffset() , i + m_pCdg->GetHOffset());
|
|
TEX_COLOR TexColor = ConvertColor(m_pCdg->GetColor(ClutOffset));
|
|
if (TexColor >> 24) //Only override transp. for opaque alpha
|
|
{
|
|
TexColor &= 0x00FFFFFF;
|
|
if (ClutOffset == m_pCdg->GetBackgroundColor())
|
|
TexColor |= m_bgAlpha;
|
|
else
|
|
TexColor |= m_fgAlpha;
|
|
}
|
|
*texel++ = TexColor;
|
|
}
|
|
}
|
|
m_pCdgTexture->UnlockRect(0);
|
|
}
|
|
|
|
TEX_COLOR CCdgRenderer::ConvertColor(CDG_COLOR CdgColor)
|
|
{
|
|
TEX_COLOR red, green, blue, alpha;
|
|
blue = (TEX_COLOR)((CdgColor & 0x000F) * 17);
|
|
green = ((TEX_COLOR)(((CdgColor & 0x00F0) >> 4) * 17)) << 8;
|
|
red = ((TEX_COLOR)(((CdgColor & 0x0F00) >> 8) * 17)) << 16;
|
|
alpha = ((TEX_COLOR)(((CdgColor & 0xF000) >> 12) * 17)) << 24;
|
|
return alpha | red | green | blue;
|
|
}
|
|
|
|
void CCdgRenderer::SetBGalpha(TEX_COLOR alpha)
|
|
{
|
|
m_bgAlpha = alpha;
|
|
}
|
|
|
|
//CdgParser
|
|
CCdgParser::CCdgParser()
|
|
{
|
|
m_pReader = NULL;
|
|
m_pLoader = NULL;
|
|
m_pRenderer = NULL;
|
|
m_pVoiceManager = NULL;
|
|
m_bIsRunning = false;
|
|
}
|
|
CCdgParser::~CCdgParser()
|
|
{
|
|
FreeGraphics();
|
|
Free();
|
|
}
|
|
|
|
bool CCdgParser::AllocGraphics()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!AllocRenderer()) return false;
|
|
m_pRenderer->InitGraphics();
|
|
if (m_pReader)
|
|
m_pRenderer->Attach(m_pReader);
|
|
return true;
|
|
}
|
|
|
|
void CCdgParser::FreeGraphics()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pRenderer)
|
|
SAFE_DELETE(m_pRenderer);
|
|
}
|
|
|
|
bool CCdgParser::Start(CStdString strSongPath)
|
|
{
|
|
if (!StartLoader(strSongPath)) return false;
|
|
if (!StartReader()) return false;
|
|
|
|
/* make sure we have fullscreen viz */
|
|
/* hmm won't this switch to fullscreen after each track?? */
|
|
if (g_windowManager.GetActiveWindow() != WINDOW_VISUALISATION)
|
|
g_windowManager.ActivateWindow(WINDOW_VISUALISATION);
|
|
|
|
// Karaoke patch (114097) ...
|
|
if ( g_guiSettings.GetBool("karaoke.voiceenabled") )
|
|
{
|
|
CDG_VOICE_MANAGER_CONFIG VoiceConfig;
|
|
VoiceConfig.dwVoicePacketTime = 20; // 20ms (can't be lower than this)
|
|
VoiceConfig.dwMaxStoredPackets = 2;
|
|
VoiceConfig.pDSound = g_audioContext.GetDirectSoundDevice();
|
|
VoiceConfig.pCallbackContext = this;
|
|
VoiceConfig.pfnVoiceDeviceCallback = NULL;
|
|
VoiceConfig.pfnVoiceDataCallback = NULL;
|
|
StartVoice(&VoiceConfig);
|
|
}
|
|
// ... Karaoke patch (114097)
|
|
m_bIsRunning = true;
|
|
return true;
|
|
}
|
|
|
|
void CCdgParser::Stop()
|
|
{
|
|
StopReader();
|
|
StopLoader();
|
|
StopVoice();
|
|
m_bIsRunning = false;
|
|
}
|
|
|
|
void CCdgParser::Free()
|
|
{
|
|
FreeReader();
|
|
FreeLoader();
|
|
}
|
|
|
|
void CCdgParser::SetAVDelay(float fDelay)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pReader)
|
|
m_pReader->SetAVDelay(fDelay);
|
|
}
|
|
|
|
void CCdgParser::SetBGTransparent(bool bTransparent /* = true */)
|
|
{
|
|
if (m_pRenderer)
|
|
{
|
|
TEX_COLOR alpha = 0;
|
|
if (!bTransparent)
|
|
alpha = 0xff000000;
|
|
m_pRenderer->SetBGalpha(alpha);
|
|
}
|
|
}
|
|
|
|
float CCdgParser::GetAVDelay()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pReader)
|
|
return m_pReader->GetAVDelay();
|
|
return g_advancedSettings.m_karaokeSyncDelay;
|
|
}
|
|
|
|
void CCdgParser::Render()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pRenderer)
|
|
m_pRenderer->Render();
|
|
}
|
|
|
|
bool CCdgParser::AllocLoader()
|
|
{
|
|
if (!m_pLoader)
|
|
m_pLoader = new CCdgLoader;
|
|
if (!m_pLoader) return false;
|
|
return true;
|
|
}
|
|
bool CCdgParser::AllocReader()
|
|
{
|
|
if (!m_pReader)
|
|
m_pReader = new CCdgReader;
|
|
if (!m_pReader) return false;
|
|
return true;
|
|
}
|
|
bool CCdgParser::AllocRenderer()
|
|
{
|
|
if (!m_pRenderer)
|
|
m_pRenderer = new CCdgRenderer;
|
|
if (!m_pRenderer) return false;
|
|
return true;
|
|
}
|
|
bool CCdgParser::StartLoader(CStdString strSongPath)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!AllocLoader()) return false;
|
|
|
|
URIUtils::RemoveExtension(strSongPath);
|
|
strSongPath += ".cdg";
|
|
if (CFile::Exists(strSongPath))
|
|
{
|
|
m_pLoader->StreamFile(strSongPath);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
void CCdgParser::StopLoader()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pLoader)
|
|
m_pLoader->StopStream();
|
|
}
|
|
void CCdgParser::FreeLoader()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pReader)
|
|
m_pReader->DetachLoader();
|
|
if (m_pLoader)
|
|
SAFE_DELETE(m_pLoader);
|
|
}
|
|
bool CCdgParser::StartReader()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!AllocReader()) return false;
|
|
if (m_pLoader)
|
|
m_pReader->Attach(m_pLoader);
|
|
m_pReader->Start((float)g_application.GetTime());
|
|
return true;
|
|
}
|
|
void CCdgParser::StopReader()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pReader)
|
|
m_pReader->StopThread();
|
|
}
|
|
void CCdgParser::FreeReader()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pRenderer)
|
|
m_pRenderer->DetachReader();
|
|
if (m_pReader)
|
|
SAFE_DELETE(m_pReader);
|
|
}
|
|
// Karaoke patch (114097) ...
|
|
bool CCdgParser::AllocVoice()
|
|
{
|
|
if (!m_pVoiceManager)
|
|
m_pVoiceManager = new CCdgVoiceManager;
|
|
if (!m_pVoiceManager) return false;
|
|
return true;
|
|
}
|
|
bool CCdgParser::StartVoice(CDG_VOICE_MANAGER_CONFIG* pConfig)
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (!AllocVoice()) return false;
|
|
if (m_pVoiceManager)
|
|
m_pVoiceManager->Initialize(pConfig);
|
|
return true;
|
|
}
|
|
void CCdgParser::StopVoice()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pVoiceManager)
|
|
m_pVoiceManager->Shutdown();
|
|
}
|
|
void CCdgParser:: FreeVoice()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pVoiceManager)
|
|
SAFE_DELETE(m_pVoiceManager);
|
|
}
|
|
void CCdgParser:: ProcessVoice()
|
|
{
|
|
CSingleLock lock (m_CritSection);
|
|
if (m_pVoiceManager)
|
|
m_pVoiceManager->ProcessVoice();
|
|
}
|
|
// ... Karaoke patch (114097)
|