欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

playlist.cpp

这是一个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.84 2000/01/16 20:07:41 ijr 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;

#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"

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;
};


// 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();
                break;
            }

            case kPlaylistSortKey_Album:
            {
                result = m1.Album() < m2.Album();
                break;
            }

            case kPlaylistSortKey_Title:
            {
                result = m1.Title() < m2.Title();
                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();
                break;
            }

            case kPlaylistSortKey_Time:
            {
                result = m1.Time() < m2.Time();
                break;
            }

            case kPlaylistSortKey_Location:
            {
                result = item1->URL() < item2->URL();
                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;
}

// return an integral random number in the range 0 - (n - 1)
static int my_rand(int n)
{
    srand( (unsigned)time( NULL ) );

    return rand() % n;
}

// 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_context->prefs->GetPlaylistShuffle(&m_shuffle);
    m_context->prefs->GetPlaylistRepeat((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;
    //uint32 count = 0;

    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;
            }
        }
    }

    size = m_playlistFormats.size();

    for(index = 0; index < size; index++)
    {
        delete m_playlistFormats[index]->GetRef();
        delete m_playlistFormats[index];
    }

    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_context->prefs->SetPlaylistShuffle(m_shuffle);
    m_context->prefs->SetPlaylistRepeat(m_repeatMode);
}


// Playlist actions
Error PlaylistManager::SetCurrentItem(PlaylistItem* item)
{
    return SetCurrentIndex(IndexOf(item));
}

const 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)
{
    m_current = index;
    if (index != kInvalidIndex) 
        m_context->target->AcceptEvent(new PlaylistCurrentItemInfoEvent(GetCurrentItem(), this));
}

uint32 PlaylistManager::GetCurrentIndex()
{
    uint32 result = kInvalidIndex;

    if(m_masterList.size())
    {
        if(m_shuffle)
            result = IndexOf(m_shuffleList[m_current]);
        else
            result = m_current;
    }

    return result;
}


Error PlaylistManager::GotoNextItem(bool userAction)
{
    m_mutex.Acquire();

    Error result = kError_NoErr;
    uint32 count = m_masterList.size();
    uint32 index = m_current;
    
    if(count)
    {
        if(!(kPlaylistMode_RepeatOne == m_repeatMode) || userAction)
        {
            index++;

            if( (index >= count) && 
                (m_repeatMode == kPlaylistMode_RepeatAll || userAction))
            {
                index = 0;

                if(m_shuffle)
                {
                    pointer_to_unary_function<int, int> lRand = 
                                   pointer_to_unary_function<int, int>(my_rand);
                    random_shuffle(m_shuffleList.begin(), m_shuffleList.end(),
                                   lRand);
                }
            }
            else if(index >= count)
            {
                index = m_current;
            }
        }

        InternalSetCurrentIndex(index);
    }
    else
    {
        m_current = kInvalidIndex;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -