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

📄 audiodevice.cpp

📁 改写的qtopia录音放音程序
💻 CPP
字号:
/************************************************************************ Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.**** This file is part of the Qtopia Environment.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include <stdlib.h>#include <qtopia/qpeapplication.h>#include <qtopia/config.h>#include <qsocketnotifier.h>#include "audiodevice.h"#if ( defined Q_WS_QWS || defined(_WS_QWS_) ) && !defined(QT_NO_COP)#include "qpe/qcopenvelope_qws.h"#endif#ifdef Q_WS_WIN#include <windows.h>#include <mmsystem.h>#include <mmreg.h>#endif#if defined(Q_WS_X11) || defined(Q_WS_QWS)#include <fcntl.h>#include <sys/ioctl.h>#include <sys/soundcard.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#endif#if defined(Q_OS_WIN32)static const int expectedBytesPerMilliSecond = 2 * 2 * 44000 / 1000;static const int timerResolutionMilliSeconds = 30;static const int sound_fragment_bytes = timerResolutionMilliSeconds * expectedBytesPerMilliSecond;#else# if defined(QT_QWS_IPAQ)static const int sound_fragment_shift = 14;# elsestatic const int sound_fragment_shift = 16;# endifstatic const int sound_fragment_bytes = (1<<sound_fragment_shift);#endifclass AudioDevicePrivate {public:    int handle;    unsigned int frequency;    unsigned int channels;    unsigned int bytesPerSample;    unsigned int bufferSize;#ifndef Q_OS_WIN32    bool can_GETOSPACE;    char* unwrittenBuffer;    unsigned int unwritten;    QSocketNotifier *notifier;#endif    static int dspFd;    static bool muted;    static unsigned int leftVolume;    static unsigned int rightVolume;};#ifdef Q_WS_QWS// This is for keeping the device open in-between playing files when// the device makes clicks and it starts to drive you insane! :)// Best to have the device not open when not using it though//#define KEEP_DEVICE_OPEN#endifint AudioDevicePrivate::dspFd = 0;bool AudioDevicePrivate::muted = FALSE;unsigned int AudioDevicePrivate::leftVolume = 0;unsigned int AudioDevicePrivate::rightVolume = 0;void AudioDevice::getVolume( unsigned int& leftVolume, unsigned int& rightVolume, bool &muted ) {    muted = AudioDevicePrivate::muted;    unsigned int volume;#ifdef Q_OS_WIN32    HWAVEOUT handle;    WAVEFORMATEX formatData;    formatData.cbSize = sizeof(WAVEFORMATEX);    formatData.wFormatTag = WAVE_FORMAT_PCM;    formatData.nAvgBytesPerSec = 4 * 44000;    formatData.nBlockAlign = 4;    formatData.nChannels = 2;    formatData.nSamplesPerSec = 44000;    formatData.wBitsPerSample = 16;    waveOutOpen(&handle, WAVE_MAPPER, &formatData, 0L, 0L, CALLBACK_NULL);    if ( waveOutGetVolume( handle, (LPDWORD)&volume ) )	qDebug( "get volume of audio device failed" );    waveOutClose( handle );    leftVolume = volume & 0xFFFF;    rightVolume = volume >> 16;#else    int mixerHandle = open( "/dev/mixer", O_RDWR );    if ( mixerHandle >= 0 ) {        ioctl( mixerHandle, MIXER_READ(0), &volume );        close( mixerHandle );    } else	qDebug( "get volume of audio device failed" );    leftVolume  = ((volume & 0x00FF) << 16) / 100;    rightVolume = ((volume & 0xFF00) <<  8) / 100;#endif}void AudioDevice::setVolume( unsigned int leftVolume, unsigned int rightVolume, bool muted ) {    AudioDevicePrivate::muted = muted;    if ( muted ) {	AudioDevicePrivate::leftVolume = leftVolume;	AudioDevicePrivate::rightVolume = rightVolume;	leftVolume = 0;	rightVolume = 0;    } else {        leftVolume  = ( (int) leftVolume < 0 ) ? 0 : ((  leftVolume > 0xFFFF ) ? 0xFFFF :  leftVolume );	rightVolume = ( (int)rightVolume < 0 ) ? 0 : (( rightVolume > 0xFFFF ) ? 0xFFFF : rightVolume );    }#ifdef Q_OS_WIN32    HWAVEOUT handle;    WAVEFORMATEX formatData;    formatData.cbSize = sizeof(WAVEFORMATEX);    formatData.wFormatTag = WAVE_FORMAT_PCM;    formatData.nAvgBytesPerSec = 4 * 44000;    formatData.nBlockAlign = 4;    formatData.nChannels = 2;    formatData.nSamplesPerSec = 44000;    formatData.wBitsPerSample = 16;    waveOutOpen(&handle, WAVE_MAPPER, &formatData, 0L, 0L, CALLBACK_NULL);    unsigned int volume = (rightVolume << 16) | leftVolume;    if ( waveOutSetVolume( handle, volume ) )	qDebug( "set volume of audio device failed" );    waveOutClose( handle );#else    // Volume can be from 0 to 100 which is 101 distinct values    unsigned int rV = (rightVolume * 101) / 65535;# if 0    unsigned int lV = (leftVolume  * 101) >> 16;    unsigned int volume = ((rV << 8) & 0xFF00) | (lV & 0x00FF);    int mixerHandle = 0;    if ( ( mixerHandle = open( "/dev/mixer", O_RDWR ) ) >= 0 ) {        ioctl( mixerHandle, MIXER_WRITE(0), &volume );        close( mixerHandle );    } else	qDebug( "set volume of audio device failed" );# else    // This is the way this has to be done now I guess, doesn't allow for    // independant right and left channel setting, or setting for different outputs    Config cfg("Sound");    cfg.setGroup("System");    cfg.writeEntry("Volume",(int)rV);# endif#endif//    qDebug( "setting volume to: 0x%x", volume ); #if ( defined Q_WS_QWS || defined(_WS_QWS_) ) && !defined(QT_NO_COP)    // Send notification that the volume has changed    QCopEnvelope( "QPE/System", "volumeChange(bool)" ) << muted; #endif}AudioDevice::AudioDevice( unsigned int f, unsigned int chs, unsigned int bps ) {    d = new AudioDevicePrivate;    d->frequency = f;    d->channels = chs;    d->bytesPerSample = bps;    connect( qApp, SIGNAL( volumeChanged(bool) ), this, SLOT( volumeChanged(bool) ) );#ifdef Q_OS_WIN32    UINT	    result;    WAVEFORMATEX    formatData;    formatData.cbSize = sizeof(WAVEFORMATEX);/*    // Other possible formats windows supports    formatData.wFormatTag = WAVE_FORMAT_MPEG;    formatData.wFormatTag = WAVE_FORMAT_MPEGLAYER3;    formatData.wFormatTag = WAVE_FORMAT_ADPCM;*/    formatData.wFormatTag = WAVE_FORMAT_PCM;    formatData.nAvgBytesPerSec = bps * chs * f;    formatData.nBlockAlign = bps * chs;    formatData.nChannels = chs;    formatData.nSamplesPerSec = f;    formatData.wBitsPerSample = bps * 8;    // Open a waveform device for output// BEGIN no tr    if (result = waveOutOpen((LPHWAVEOUT)&d->handle, WAVE_MAPPER, &formatData, 0L, 0L, CALLBACK_NULL)) {	QString errorMsg = "error opening audio device.\nReason: %i - "; // No tr	switch (result) {	    case MMSYSERR_ALLOCATED:	errorMsg += "Specified resource is already allocated."; break; // No tr	    case MMSYSERR_BADDEVICEID:	errorMsg += "Specified device identifier is out of range."; break; // No tr	    case MMSYSERR_NODRIVER:	errorMsg += "No device driver is present."; break; // No tr	    case MMSYSERR_NOMEM:	errorMsg += "Unable to allocate or lock memory."; break; // No tr	    case WAVERR_BADFORMAT:	errorMsg += "Attempted to open with an unsupported waveform-audio format."; break; // No tr	    case WAVERR_SYNC:		errorMsg += "The device is synchronous but waveOutOpen was called without using the WAVE_ALLOWSYNC flag."; break; // No tr	    default:			errorMsg += "Undefined error"; break; // No tr	}	qDebug( errorMsg, result );    }// END no tr    d->bufferSize = sound_fragment_bytes;#else    int fragments = 0x10000 * 8 + sound_fragment_shift;    int format = AFMT_S16_NE;    int capabilities = 0;#ifdef KEEP_DEVICE_OPEN    if ( AudioDevicePrivate::dspFd == 0 ) {#endif    if ( ( d->handle = ::open( "/dev/dsp", O_WRONLY ) ) < 0 ) {	qDebug( "error opening audio device /dev/dsp, sending data to /dev/null instead" );	d->handle = ::open( "/dev/null", O_WRONLY );    }#ifdef KEEP_DEVICE_OPEN 	AudioDevicePrivate::dspFd = d->handle;    } else {        d->handle = AudioDevicePrivate::dspFd;    }#endif    ioctl( d->handle, SNDCTL_DSP_GETCAPS, &capabilities );    ioctl( d->handle, SNDCTL_DSP_SETFRAGMENT, &fragments );    ioctl( d->handle, SNDCTL_DSP_SETFMT, &format );    ioctl( d->handle, SNDCTL_DSP_SPEED, &d->frequency );    if ( ioctl( d->handle, SNDCTL_DSP_CHANNELS, &d->channels ) == -1 ) {	d->channels = ( d->channels == 1 ) ? 2 : d->channels;	ioctl( d->handle, SNDCTL_DSP_CHANNELS, &d->channels );    }    d->bufferSize = sound_fragment_bytes;    d->unwrittenBuffer = new char[d->bufferSize];    d->unwritten = 0;    d->can_GETOSPACE = TRUE; // until we find otherwise     //if ( chs != d->channels )		    qDebug( "Wanted %d, got %d channels", chs, d->channels );    //if ( f != d->frequency )		    qDebug( "wanted %dHz, got %dHz", f, d->frequency );    //if ( capabilities & DSP_CAP_BATCH )   qDebug( "Sound card has local buffer" );    //if ( capabilities & DSP_CAP_REALTIME )qDebug( "Sound card has realtime sync" );    //if ( capabilities & DSP_CAP_TRIGGER ) qDebug( "Sound card has precise trigger" );    //if ( capabilities & DSP_CAP_MMAP )    qDebug( "Sound card can mmap" );    // Register to receive notification of when the device is ready to write.    d->notifier = new QSocketNotifier( d->dspFd, QSocketNotifier::Write );    QObject::connect( d->notifier, SIGNAL(activated(int)),		      this, SIGNAL(completedIO()) );#endif}    AudioDevice::~AudioDevice() {#ifdef Q_OS_WIN32    waveOutClose( (HWAVEOUT)d->handle );#else# ifndef KEEP_DEVICE_OPEN     delete d->notifier;    close( d->handle );			// Now it should be safe to shut the handle# endif    delete [] d->unwrittenBuffer;    delete d;#endif}void AudioDevice::volumeChanged( bool muted ){    AudioDevicePrivate::muted = muted;}void AudioDevice::write( char *buffer, unsigned int length ){#ifdef Q_OS_WIN32    // returns immediately and (to be implemented) emits completedIO() when finished writing    WAVEHDR *lpWaveHdr = (WAVEHDR *)malloc( sizeof(WAVEHDR) );    // maybe the buffer should be copied so that this fool proof, but its a performance hit    lpWaveHdr->lpData = buffer;    lpWaveHdr->dwBufferLength = length;    lpWaveHdr->dwFlags = 0L;    lpWaveHdr->dwLoops = 0L;    waveOutPrepareHeader( (HWAVEOUT)d->handle, lpWaveHdr, sizeof(WAVEHDR) );    // waveOutWrite returns immediately. the data is sent in the background.     if ( waveOutWrite( (HWAVEOUT)d->handle, lpWaveHdr, sizeof(WAVEHDR) ) )	qDebug( "failed to write block to audio device" );    // emit completedIO();#else    int t = ::write( d->handle, buffer, length );    if ( t<0 ) t = 0;    if ( t != (int)length) {	qDebug("Ahhh!! memcpys 1");	memcpy(d->unwrittenBuffer,buffer+t,length-t);	d->unwritten = length-t;    }#endif}unsigned int AudioDevice::channels() const{    return d->channels;}unsigned int AudioDevice::frequency() const{    return d->frequency;}unsigned int AudioDevice::bytesPerSample() const{    return d->bytesPerSample;}unsigned int AudioDevice::bufferSize() const{    return d->bufferSize;}unsigned int AudioDevice::canWrite() const{#ifdef Q_OS_WIN32    return bufferSize(); // Any better?#else    audio_buf_info info;    if ( d->can_GETOSPACE && ioctl(d->handle,SNDCTL_DSP_GETOSPACE,&info) ) {	d->can_GETOSPACE = FALSE;	fcntl( d->handle, F_SETFL, O_NONBLOCK );    }    if ( d->can_GETOSPACE ) {	int t = info.fragments * sound_fragment_bytes;	return QMIN(t,(int)bufferSize());    } else {	if ( d->unwritten ) {	    int t = ::write( d->handle, d->unwrittenBuffer, d->unwritten );	    if ( t<0 ) t = 0;	    if ( (unsigned)t!=d->unwritten ) {		memcpy(d->unwrittenBuffer,d->unwrittenBuffer+t,d->unwritten-t);		d->unwritten -= t;	    } else {		d->unwritten = 0;	    }	}	if ( d->unwritten )	    return 0;	else	    return d->bufferSize;    }#endif}int AudioDevice::bytesWritten() {#ifdef Q_OS_WIN32    MMTIME pmmt = { TIME_BYTES, 0 };    if ( ( waveOutGetPosition( (HWAVEOUT)d->handle, &pmmt, sizeof(MMTIME) ) != MMSYSERR_NOERROR ) || ( pmmt.wType != TIME_BYTES ) ) {	qDebug( "failed to get audio device position" );	return -1;    }    return pmmt.u.cb;#else    int buffered = 0;    if ( ioctl( d->handle, SNDCTL_DSP_GETODELAY, &buffered ) ) {	qDebug( "failed to get audio device position" );	return -1;    }    return buffered;#endif}

⌨️ 快捷键说明

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