📄 playlist.cpp
字号:
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Portions Copyright (C) 1998-1999 EMusic.com
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 of the License, 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: playlist.cpp,v 1.116 2001/03/07 06:07:00 elrod Exp $
____________________________________________________________________________*/
// The debugger can't handle symbols more than 255 characters long.
// STL often creates symbols longer than that.
// When symbols are longer than 255 characters, the warning is disabled.
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include <assert.h>
#include <time.h>
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
using namespace std;
#ifdef __QNX__
#include <strings.h>
#endif
#include "config.h"
#include "playlist.h"
#include "errors.h"
#include "mutex.h"
#include "thread.h"
#include "metadata.h"
#include "registrar.h"
#include "event.h"
#include "eventdata.h"
#include "musiccatalog.h"
#include "apsplaylist.h"
class UndoAdd : public UndoItem {
public:
UndoAdd(PlaylistManager* plm, const string& url, uint32 index);
virtual ~UndoAdd();
virtual void Undo();
virtual void Redo();
private:
PlaylistManager* m_plm;
string m_url;
uint32 m_index;
};
class UndoAddMulti : public UndoItem {
public:
UndoAddMulti(PlaylistManager* plm, vector<string>& urls, uint32 index);
virtual ~UndoAddMulti();
virtual void Undo();
virtual void Redo();
private:
PlaylistManager* m_plm;
vector<string> m_urls;
uint32 m_index;
};
class UndoRemove : public UndoItem {
public:
UndoRemove(PlaylistManager* plm, const string& url, uint32 index);
virtual ~UndoRemove();
virtual void Undo();
virtual void Redo();
private:
PlaylistManager* m_plm;
string m_url;
uint32 m_index;
};
class UndoMove : public UndoItem {
public:
UndoMove(PlaylistManager* plm, uint32 oldIndex, uint32 newIndex);
virtual ~UndoMove();
virtual void Undo();
virtual void Redo();
private:
PlaylistManager* m_plm;
uint32 m_newIndex, m_oldIndex;
};
#ifndef lstrcmpi
#define lstrcmpi strcasecmp
#endif
// Function object used for sorting PlaylistItems in PlaylistManager
bool PlaylistItemSort::operator() (PlaylistItem* item1,
PlaylistItem* item2) const
{
bool result = true;
assert(item1);
assert(item2);
if(item1 && item2)
{
MetaData m1 = item1->GetMetaData();
MetaData m2 = item2->GetMetaData();
switch(m_sortKey)
{
case kPlaylistSortKey_Artist:
{
//result = m1.Artist() < m2.Artist();
result = (lstrcmpi(m1.Artist().c_str(), m2.Artist().c_str()) < 0);
//result = (lstrcmpi(m1.Comment().c_str(), m2.Comment().c_str()) < 0);
break;
}
case kPlaylistSortKey_Album:
{
//result = m1.Album() < m2.Album();
result = (lstrcmpi(m1.Album().c_str(), m2.Album().c_str()) < 0);
break;
}
case kPlaylistSortKey_Title:
{
//result = m1.Title() < m2.Title();
result = (lstrcmpi(m1.Title().c_str(), m2.Title().c_str()) < 0);
break;
}
case kPlaylistSortKey_Comment:
{
result = (lstrcmpi(m1.Comment().c_str(), m2.Comment().c_str()) < 0);
break;
}
case kPlaylistSortKey_Year:
{
result = m1.Year() < m2.Year();
break;
}
case kPlaylistSortKey_Track:
{
result = m1.Track() < m2.Track();
break;
}
case kPlaylistSortKey_Genre:
{
//result = m1.Genre() < m2.Genre();
result = (lstrcmpi(m1.Genre().c_str(), m2.Genre().c_str()) < 0);
break;
}
case kPlaylistSortKey_Time:
{
result = m1.Time() < m2.Time();
break;
}
case kPlaylistSortKey_Location:
{
result = item1->URL() < item2->URL();
break;
}
case kPlaylistSortKey_FileName:
{
string file1, file2;
string::size_type pos;
pos = item1->URL().find_last_of('/');
file1 = item1->URL().substr(pos + 1);
pos = item2->URL().find_last_of('/');
file2 = item2->URL().substr(pos + 1);
result = (lstrcmpi(file1.c_str(), file2.c_str()) < 0);
break;
}
default:
{
cerr << "Whoa! Why are we here?" << endl;
break;
}
}
}
/*if(m_sortType == kPlaylistSortType_Descending)
{
result = !result;
}*/
return result;
}
// Function object used for ordering MetaDataFormats in PlaylistManager
bool MetaDataSort::operator() (MetaDataFormat* item1,
MetaDataFormat* item2) const
{
bool result = true;
assert(item1);
assert(item2);
if(item1 && item2)
{
result = item1->Order() < item2->Order();
}
return result;
}
// Implementation of the PlaylistManager Class
PlaylistManager::PlaylistManager(FAContext* context)
{
m_context = context;
m_activeList = &m_masterList;
m_playlistKey = kPlaylistKey_MasterPlaylist;
m_current = kInvalidIndex;
m_shuffle = false;
m_repeatMode = kPlaylistMode_RepeatNone;
m_sortKey = kPlaylistSortKey_Random;
m_sortType = kPlaylistSortType_Ascending;
m_time = 0;
m_context->prefs->GetPrefBoolean(kPlaylistShufflePref, &m_shuffle);
m_context->prefs->GetPrefInt32(kPlaylistRepeatPref, (int32*)&m_repeatMode);
Registrar registrar;
registrar.SetSubDir("plugins");
registrar.SetSearchString("*.plf");
registrar.InitializeRegistry(&m_playlistRegistry, context->prefs);
registrar.SetSearchString("*.mdf");
registrar.InitializeRegistry(&m_metadataRegistry, context->prefs);
registrar.SetSearchString("*.ppp");
registrar.InitializeRegistry(&m_portableRegistry, context->prefs);
RegistryItem* module = NULL;
MetaDataFormat* mdf = NULL;
int32 i = 0;
while((module = m_metadataRegistry.GetItem(i++)))
{
mdf = (MetaDataFormat*) module->InitFunction()(m_context);
if(mdf)
{
m_metadataFormats.push_back(mdf);
}
}
sort(m_metadataFormats.begin(), m_metadataFormats.end(), MetaDataSort());
i = 0;
PlaylistFormat* plf = NULL;
while((module = m_playlistRegistry.GetItem(i++)))
{
plf = (PlaylistFormat*) module->InitFunction()(m_context);
if(plf)
{
PlaylistFormatInfo plfi;
uint32 index = 0;
// error != kError_NoMoreFormats
while(IsntError(plf->GetSupportedFormats(&plfi, index++)))
{
plfi.SetRef(plf);
m_playlistFormats.push_back(new PlaylistFormatInfo(plfi));
}
}
}
i = 0;
PortableDevice* pd = NULL;
while((module = m_portableRegistry.GetItem(i++)))
{
pd = (PortableDevice*) module->InitFunction()(m_context);
if(pd)
{
DeviceInfo di;
uint32 index = 0;
// error != kError_NoMoreDevices
while(IsntError(pd->GetSupportedDevices(&di, index++)))
{
di.SetRef(pd);
di.SetPluginName(module->Name());
m_portablePlayers.push_back(new DeviceInfo(di));
}
}
}
}
PlaylistManager::~PlaylistManager()
{
uint32 index = 0;
uint32 size = 0;
PlaylistItem* item = NULL;
vector<MetaDataFormat *>::iterator i;
vector<PlaylistFormatInfo *>::iterator j;
//uint32 count = 0;
m_mutex.Acquire();
size = m_masterList.size();
for(index = 0; index < size; index++)
{
item = m_masterList[index];
if(item)
{
// if the metadata thread is still accessing this item
// we don't wanna delete the item out from under it.
// instead we set a flag and let the metadata thread
// clean up when it returns.
if(item->GetState() == kPlaylistItemState_RetrievingMetaData)
{
item->SetState(kPlaylistItemState_Delete);
}
else
{
delete item;
}
}
}
size = m_externalList.size();
for(index = 0; index < size; index++)
{
item = m_externalList[index];
if(item)
{
// if the metadata thread is still accessing this item
// we don't wanna delete the item out from under it.
// instead we set a flag and let the metadata thread
// clean up when it returns.
if(item->GetState() == kPlaylistItemState_RetrievingMetaData)
{
item->SetState(kPlaylistItemState_Delete);
}
else
{
delete item;
}
}
}
size = m_portableList.size();
for(index = 0; index < size; index++)
{
item = m_portableList[index];
if(item)
{
// if the metadata thread is still accessing this item
// we don't wanna delete the item out from under it.
// instead we set a flag and let the metadata thread
// clean up when it returns.
if(item->GetState() == kPlaylistItemState_RetrievingMetaData)
{
item->SetState(kPlaylistItemState_Delete);
}
else
{
delete item;
}
}
}
for(j = m_playlistFormats.begin(); j != m_playlistFormats.end(); j++)
delete (*j);
size = m_portablePlayers.size();
for(index = 0; index < size; index++)
{
delete m_portablePlayers[index]->GetRef();
delete m_portablePlayers[index];
}
for(i = m_metadataFormats.begin(); i != m_metadataFormats.end(); i++)
delete (*i);
m_mutex.Release();
m_context->prefs->SetPrefBoolean(kPlaylistShufflePref, m_shuffle);
m_context->prefs->SetPrefInt32(kPlaylistRepeatPref, m_repeatMode);
}
void PlaylistManager::ShuffleIt(vector<PlaylistItem *> *toBeShuffled)
{
if (!toBeShuffled)
toBeShuffled = &m_shuffleList;
int max = toBeShuffled->size();
vector<PlaylistItem *> tempShuffled;
srand((unsigned int)time(NULL));
int i;
vector<bool> usedList;
for (i = 0; i < max; i++)
{
usedList.push_back(false);
}
bool used = true;
int index = 0;
int lastindex = 0;
for (i = 0; i < max; i++)
{
while (used)
{
index = (int)((double)rand() / (RAND_MAX + 1.0) * max);
if (usedList[index] == false)
used = false;
if (max - i > 50 && abs(index - lastindex) < 10)
used = true;
}
usedList[index] = true;
PlaylistItem *dupe = (*toBeShuffled)[index];
tempShuffled.push_back(dupe);
used = true;
lastindex = index;
}
toBeShuffled->erase(toBeShuffled->begin(), toBeShuffled->end());
vector<PlaylistItem *>::iterator iter = tempShuffled.begin();
for (; iter != tempShuffled.end(); iter++)
toBeShuffled->push_back(*iter);
}
Error PlaylistManager::SetCurrentItem(PlaylistItem* item)
{
return SetCurrentIndex(IndexOf(item));
}
PlaylistItem* PlaylistManager::GetCurrentItem()
{
PlaylistItem* result = NULL;
m_mutex.Acquire();
if(m_masterList.size())
{
if(m_shuffle)
result = m_shuffleList[m_current];
else
result = m_masterList[m_current];
}
m_mutex.Release();
return result;
}
Error PlaylistManager::SetCurrentIndex(uint32 index)
{
Error result = kError_InvalidParam;
m_mutex.Acquire();
index = CheckIndex(index);
if(index != kInvalidIndex)
{
if(m_shuffle)
index = InternalIndexOf(&m_shuffleList, ItemAt(index));
InternalSetCurrentIndex(index);
result = kError_NoErr;
}
m_mutex.Release();
return result;
}
void PlaylistManager::InternalSetCurrentIndex(uint32 index)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -