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

📄 wavoutpmo.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
字号:
/*____________________________________________________________________________

  FreeAmp - The Free MP3 Player

  Portions Copyright (C) 1998-1999 EMusic.com
  Portions Copyright (C) 2000 Michael Rich

  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: wavoutpmo.cpp,v 1.7 2000/06/22 18:53:10 elrod Exp $
____________________________________________________________________________*/

/* system headers */
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

/* project headers */
#include "config.h"
#include "wavoutpmo.h"
#include "eventdata.h"
#include "preferences.h"
#include "facontext.h"
#include "log.h"
#include "debug.h"
#include "wav.h"

#define DB Debug_v("%s:%d", __FILE__, __LINE__);

extern "C"
{
  PhysicalMediaOutput* Initialize(FAContext *context)
  {
      return new WavOutPMO(context);
  }
}

WavOutPMO::
WavOutPMO(FAContext *context):
     PhysicalMediaOutput(context)
{
    m_pBufferThread       = NULL;
    m_iTotalBytesWritten  = 0;
    m_iLastTime           = -1000;

    if (!m_pBufferThread)
    {
       m_pBufferThread = Thread::CreateThread();
       assert(m_pBufferThread);
       m_pBufferThread->Create(WavOutPMO::StartWorkerThread, this);
    }

    m_initialized = false;
    m_Writer = new WaveWriter;
}

WavOutPMO::
~WavOutPMO()
{
  m_bExit = true;
  m_pSleepSem->Signal();
  m_pPauseSem->Signal();

  if (m_pBufferThread)
  {
     m_pBufferThread->Join();
     delete m_pBufferThread;
     m_pBufferThread = NULL;
  }
}

void
WavOutPMO::
GetVolume(int32 &left, int32 &right)
{
    left = right = -1;
}

void
WavOutPMO::
SetVolume(int32 left, int32 right)
{
    ;
}

Error
WavOutPMO::
Init(OutputInfo* info)
{
   uint32 len;
    
   m_samples_per_second  = info->samples_per_second;
   m_data_size           = info->max_buffer_size;
   m_iBytesPerSample = info->number_of_channels * (info->bits_per_sample >> 3);

   WAVEFORMATEX format;

   format.wBitsPerSample   = 16;
   format.wFormatTag       = WAVE_FORMAT_PCM;
   format.nChannels        = info->number_of_channels;
   format.nSamplesPerSec   = m_samples_per_second;
   format.nAvgBytesPerSec  = info->number_of_channels *
                              info->samples_per_second * 2;
   format.nBlockAlign      = 4;
   format.cbSize           = 0;

   char path[MAX_PATH];
   char base[MAX_PATH];
   char url[MAX_PATH];
   char *pPtr;

   // using the current file, split it apart, and rebuilt
   // it, appending an ! to the filename, and changing the extention
   // to wav
   strcpy(url, m_pPmi->Url());
   pPtr = strrchr(url, DIR_MARKER);
   if (pPtr)
   {
      strcpy(path, pPtr+1);
      pPtr = strrchr(path, '.');
      if (pPtr)
         *pPtr = 0;
      strcat(path, ".wav"); 
   }
   else
      strcpy(path, "unknown.wav");

   len = _MAX_PATH;
   m_pContext->prefs->GetPrefString(kWAVOutputPathPref, base, &len);
   strcat(base, DIR_MARKER_STR);
   strcat(base, path);

   m_Writer->Create(base, &format);

   m_initialized = true;

   return kError_NoErr;
}

void 
WavOutPMO::
Pause()
{
   PhysicalMediaOutput::Pause();
}

void
WavOutPMO::
Resume()
{
   PhysicalMediaOutput::Resume();
}

Error
WavOutPMO::
Reset(bool user_stop)
{
   m_Writer->Close();
   return kError_NoErr;
}

void 
WavOutPMO::
Clear()
{
   m_Writer->Close();
   PhysicalMediaOutput::Clear();
}

void
WavOutPMO::
Quit()
{
   m_Writer->Close();
}

void
WavOutPMO::
HandleTimeInfoEvent(PMOTimeInfoEvent *pEvent)
{
  MediaTimeInfoEvent* pmtpi;
  int32               hours, minutes, seconds;
  int                 iTotalTime = 0;

  if (m_samples_per_second <= 0)
     return;

  iTotalTime  = (m_iTotalBytesWritten) / 
                (m_iBytesPerSample * m_samples_per_second);

  hours       = iTotalTime / 3600;
  minutes     = (iTotalTime - hours) / 60;
  seconds     = iTotalTime - hours * 3600 - minutes * 60;

  if (minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59)
     return;

  if (iTotalTime < m_iLastTime + 10)
     return;

  pmtpi = new MediaTimeInfoEvent(hours, minutes, seconds, 0,
                                (float)iTotalTime, 0);
  m_pTarget->AcceptEvent(pmtpi);
  m_iLastTime = iTotalTime;
}

void
WavOutPMO::
StartWorkerThread(void *pVoidBuffer)
{
  ((WavOutPMO*)pVoidBuffer)->WorkerThread();
}

void
WavOutPMO::
WorkerThread(void)
{
   void*   pBuffer;
   Error   eErr;
   Event*  pEvent;

   // Don't do anything until resume is called.
   m_pPauseSem->Wait();

   for(; !m_bExit;)
   {
      if (m_bPause)
      {
          m_pPauseSem->Wait();
          continue;
      }

      // Loop until we get an Init event from the LMC
      if (!m_initialized)
      {
          pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

          if (pEvent == NULL)
          {
              m_pLmc->Wake();
              WasteTime();

              continue;
          }

          if (pEvent->Type() == PMO_Init)
          {
              if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo())))
              {
                  DB
                  delete pEvent;
                  break;
              }
        }
          delete pEvent;

          continue;
      }

      // Set up reading a block from the buffer. If not enough bytes are
      // available, sleep for a little while and try again.
      for(;;)
      {
        if (m_bPause || m_bExit)
           break;
        
          eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, m_data_size);
          if (eErr == kError_NoDataAvail)
          {
              m_pLmc->Wake();
    
              WasteTime();
              continue;
          }

          // Is there an event pending that we need to take care of
          // before we play this block of samples?
          if (eErr == kError_EventPending)
          {
              pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();
           if (pEvent == NULL)
              continue;

              if (pEvent->Type() == PMO_Init)
                  Init(((PMOInitEvent *)pEvent)->GetInfo());
    
              if (pEvent->Type() == PMO_Reset)
                  Reset(true);
    
              if (pEvent->Type() == PMO_Info) 
                  HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent);
    
              if (pEvent->Type() == PMO_Quit) 
              {
              Quit();
                  delete pEvent;
                  m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
              
                  return;
              }
 
              delete pEvent;
    
              continue;
          }
          
          if (IsError(eErr))
          {
              ReportError("Internal error occured.");
              m_pContext->log->Error("Cannot read from buffer in PMO "
                                    "worker tread: %d\n", eErr);
              return;
          }
          break;
      }
     if (m_bPause || m_bExit)
       continue;

      if (m_Writer->Write((char *)pBuffer, m_data_size) == 0)
      {
         ReportError("Write failed. Disk full?");
         return;
      }
      
      m_iTotalBytesWritten += m_data_size;
      m_pInputBuffer->EndRead(m_data_size);
      
     m_pLmc->Wake();
      UpdateBufferStatus();
  }
}

⌨️ 快捷键说明

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