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

📄 mci_obuf.cpp

📁 一个自己编制的基于pocketPC的mp3播放器
💻 CPP
字号:
/* mci_obuf.cpp

	Output buffer class for Win32 multimedia system written by
   Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu

   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. */

/* Writing to Windows multimedia system with such a small
	buffer won't do, so we increase buffer size, and ignore
	most of the writes. Also we need to have a queue of 3 wave
	headers for smooth playback. The last header and the oldest
	header play while the current one is being filled in.

	Note that this does not support 8-bit soundcards yet! I don't
	know what the data format is to that */

/* Changes since last version: changed GMEM_MOVEABLE to GMEM_FIXED
	which is a bit faster, according to the suggestions of Paul Forgey.
	clear_buffer() added for seeking. Changes int16 parameter to int32
	for minor speed improvement. Last edit: 06/29/96. */

/* More changes: eliminated GlobalLock on the fixed memory, which
   is unnecessary.

   Added a function clear_buffer(), which clears the audio data
   when a seek is made by the user.

   Also added a function set_stop_flag() which
   sets a flag when playback is interrupted by the user. Then
   no attempt is made to unprepare headers after waveReset() is
   called by the main thread.

   Last edit: 10/12/96. */

/* Replaced usage of the PCMWAVEFORMAT structure with the more up
   to date WAVEFORMATEX structure.

   According to the suggestions of Sergey Kuzmin, replaced
   GlobalAlloc and GlobalFree with new and delete, which should
   eliminate memory leaks.

   Last edit: 12/31/96. */
#include "stdafx.h"
#ifdef  __WIN32__
#define STRICT
#include <windows.h>

#ifndef WIN32GUI
#include <iostream.h>
#endif

#include "all.h"
#include "header.h"
#include "args.h"
#include "obuffer.h"
#include "mci_obuf.h"

HANDLE MCISemaphore;

#pragma argsused
void CALLBACK MCICallBack(HWAVEOUT hwo, UINT uMsg,
                          DWORD dwInstance,
                          DWORD dwParam1,
                          DWORD dwParam2)
{
	switch(uMsg)
	{
		case WOM_DONE:
		{
			LPWAVEHDR lpWaveHdr = (LPWAVEHDR) dwParam1;
			waveOutUnprepareHeader(hwo, lpWaveHdr, sizeof(WAVEHDR));
			ReleaseSemaphore(MCISemaphore, 1, NULL);
		}
      break;
	}
}

MCIbuffer::MCIbuffer(uint32 number_of_channels,
							MPEG_Args *maplay_args)
{
  channels  = number_of_channels;
  data_size = channels * BUFFERSIZE;

  if (maplay_args->MPEGheader->version() == MPEG2_LSF)
  		data_size >>= 1;

  if (maplay_args->MPEGheader->layer() == 1)
  		data_size /= 3;

  hdr_size      = sizeof(WAVEHDR);
  lpwavehdr_arr = new LPWAVEHDR[3];
  phwo          = maplay_args->phwo;
  fillup        = 0;

  lpwf = (tWAVEFORMATEX *) new WAVEFORMATEX;

  lpwf->wBitsPerSample  = 16;  // No 8-bit support yet
  lpwf->wFormatTag      = WAVE_FORMAT_PCM;
  lpwf->nChannels       = (WORD) channels;
  lpwf->nSamplesPerSec  = (DWORD) maplay_args->MPEGheader->frequency();
  lpwf->nAvgBytesPerSec = (DWORD) channels *
  											 maplay_args->MPEGheader->frequency() << 1;
  lpwf->nBlockAlign     = (WORD) (channels << 1);
  lpwf->cbSize          = 0;

  if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
					   (DWORD) MCICallBack, NULL,
                  WAVE_ALLOWSYNC | CALLBACK_FUNCTION)
      != MMSYSERR_NOERROR)
  {
#ifdef WIN32GUI
     	MessageBox(maplay_args->hWnd, _T("Could not open wave device."),
_T("Audio playback error"), MB_ICONSTOP | MB_OK);
		ExitProcess(-1);
#else
		cerr << endl << "Could not open wave device." << endl;
#endif
		return;
  }

  buffer_count = 0;

  uint32 i;

  for(i=0; i<3; i++) {
	  lpwavehdr_arr[i] = (LPWAVEHDR) new WAVEHDR;

     LPWAVEHDR temp = lpwavehdr_arr[i];

	  if(!temp) return;

	  temp->lpData = (LPSTR) new char[data_size];

	  if(!temp->lpData) return;
	  temp->dwBufferLength  = data_size;
	  temp->dwBytesRecorded = 0;
	  temp->dwUser          = 0;  // If played, dwUser = 1
	  temp->dwLoops         = 0;
	  temp->dwFlags         = NULL;
  }

  for(i=0; i<channels; i++)
	   bufferp[i] = i * channels;

  user_stop = 0;

  MCISemaphore = CreateSemaphore(NULL, 0, 1024, _T("MCISemaphore"));
}

void MCIbuffer::append(uint32 channel, int16 value)
{
  // Need to break up the 32-bit integer into 2 8-bit bytes.
  // (ignore the first two bytes - either 0x0000 or 0xffff)
  // Note that Intel byte order is backwards!!!

  LPSTR temp = lpwavehdr_arr[2]->lpData;

  temp[bufferp[channel]]   = (char) (value & 0xff);
  temp[bufferp[channel]+1] = (char) (value >> 8);

  bufferp[channel] += channels << 1;

  return;
}

#pragma argsused
void MCIbuffer::write_buffer(int32 fd)
{
	// Actually write only when buffer is actually full.
	if ((++buffer_count & BIT_SELECT) == 0) {

		buffer_count = 0;

		// Wait for 2 completed headers
		if (fillup > 1) {

			// Prepare & write newest header
			waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
			waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);

			// Header has now been sent
			lpwavehdr_arr[2]->dwUser = 1;

			wave_swap();

			// Unprepare oldest header
			if (lpwavehdr_arr[2]->dwUser) {
			   WaitForSingleObject(MCISemaphore, 10000);
			}

		} else {

			if (++fillup == 2) {

					// Write the previously calculated 2 headers
					waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
					waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);

					// Header has now been sent
					lpwavehdr_arr[0]->dwUser = 1;

					wave_swap();

					waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
					waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);

					// Header has now been sent
					lpwavehdr_arr[0]->dwUser = 1;

			} else {
				wave_swap();
         }
		}

		for(uint32 i=0; i<channels; i++)
		  bufferp[i] = i * channels;
	}
	return;
}

void MCIbuffer::wave_swap()
{
	LPWAVEHDR temp   = lpwavehdr_arr[2];
   lpwavehdr_arr[2] = lpwavehdr_arr[1];
   lpwavehdr_arr[1] = lpwavehdr_arr[0];
	lpwavehdr_arr[0] = temp;

	return;
}

#ifdef SEEK_STOP
void MCIbuffer::clear_buffer()
// Clear all the data in the buffers
{

	waveOutReset(*phwo);

   unsigned int i;

	for(i=0; i<3; i++) {

		LPWAVEHDR temp = lpwavehdr_arr[i];

		if ((temp->dwUser) && (i < 2))
			WaitForSingleObject(MCISemaphore, 10000);

		temp->dwUser = 0;

		for(unsigned int j=0; j<data_size; j++)
			temp->lpData[j] = (char) 0;
	}

//  	waveOutReset(*phwo);

	// Reset buffer pointers
	for(i=0; i<channels; i++)
		bufferp[i] = i * channels;

	// Force the buffers to fillup before playing.
	fillup = buffer_count = 0;

}

void MCIbuffer::set_stop_flag()
// Set the flag to avoid unpreparing non-existent headers
{
	user_stop = 1;
   return;
}
#endif


MCIbuffer::~MCIbuffer()
{
   if (user_stop) {

     waveOutReset(*phwo);

   } else {

   	if (fillup == 1) {

	   	// Write the last header calculated (at the top of the array).
		   waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
     		waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);

         // Header has been written.
		   lpwavehdr_arr[0]->dwUser = 1;
      }

      if (buffer_count) {

      	// Write the last wave header (probably not be written due to buffer
         //	size increase.)

         for(unsigned int i = bufferp[channels-1]; i < data_size; i++)
    			 lpwavehdr_arr[2]->lpData[i] = (char) 0;

		   waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
    		waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);

		   // Header has been written.
         lpwavehdr_arr[2]->dwUser = 1;
         wave_swap();
  	   }
   }

	// Unprepare and free the header memory.
	for (int j=2; j>=0; j--) {
  		if (lpwavehdr_arr[j]->dwUser && !user_stop)
			WaitForSingleObject(MCISemaphore, 10000);

      delete [] lpwavehdr_arr[j]->lpData;
      delete lpwavehdr_arr[j];
	}

   delete [] lpwavehdr_arr;
	delete lpwf;

	while(waveOutClose(*phwo) == WAVERR_STILLPLAYING)
		Sleep(SLEEPTIME);

   CloseHandle(MCISemaphore);

	return;
}

Obuffer *create_obuffer(MPEG_Args *maplay_args)
{
	Obuffer *buffer;

	enum e_mode mode = maplay_args->MPEGheader->mode();
   enum e_channels which_channels = maplay_args->which_c;

	if ((mode == single_channel) || (which_channels != both))
		buffer = new MCIbuffer(1, maplay_args);	// mono
   else
		buffer = new MCIbuffer(2, maplay_args);	// stereo

   return(buffer);
}

#endif // __WIN32__

⌨️ 快捷键说明

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