⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 playlist.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*____________________________________________________________________________
	
	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 + -