📄 audioinput.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 <qsocketnotifier.h>#include "audioinput.h"#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>#include <errno.h>// The OSS device to record from.#define AUDIO_RECORD_SOURCE SOUND_MIXER_MIC#endif// Sound formats, for use by AudioFormatHandler::create().#ifndef AFMT_U8#define AFMT_U8 0x00000008#define AFMT_S16_LE 0x00000010#define AFMT_S16_BE 0x00000020#define AFMT_S8 0x00000040#define AFMT_U16_LE 0x00000080#define AFMT_U16_BE 0x00000100#endif// Conversion handler for an audio input format. Format handlers// are responsible for converting from the device's encoding to// normalized 16-bit host byte order samples.class AudioFormatHandler{public: virtual ~AudioFormatHandler() { } // Get the read size for a specific number of raw sound samples. virtual unsigned int readSize( unsigned int length ) = 0; // Convert a buffer of audio data into raw 16-bit sound samples. // "length" is the number of bytes read from the device. Returns // the number of raw sound samples. virtual int convert( short *buffer, int length ) = 0; // Create the appropriate conversion handler for a device format. static AudioFormatHandler *create( int format );};// Convert signed 16-bit samples to normalized raw samples. This doesn't// need to do anything, as the incoming data is already normalized.class S16AudioFormatHandler : public AudioFormatHandler{public: unsigned int readSize( unsigned int length ) { return length * 2; } int convert( short *, int length ) { return length / 2; }};// Convert signed 16-bit samples to normalized raw samples by byte-swapping.class S16SwapAudioFormatHandler : public AudioFormatHandler{public: unsigned int readSize( unsigned int length ) { return length * 2; } int convert( short *buffer, int length );};int S16SwapAudioFormatHandler::convert( short *buffer, int length ){ int result = length / 2; while ( length >= 2 ) { *buffer = (short)((*buffer << 8) | ((*buffer >> 8) & 0xFF)); ++buffer; length -= 2; } return result;}// Convert unsigned 16-bit samples to normalized raw samples.class U16AudioFormatHandler : public AudioFormatHandler{public: unsigned int readSize( unsigned int length ) { return length * 2; } int convert( short *buffer, int length );};int U16AudioFormatHandler::convert( short *buffer, int length ){ int result = length / 2; while ( length >= 2 ) { *buffer += (short)0x8000; ++buffer; length -= 2; } return result;}// Convert unsigned 16-bit samples to normalized raw samples and byte-swap.class U16SwapAudioFormatHandler : public AudioFormatHandler{public: unsigned int readSize( unsigned int length ) { return length * 2; } int convert( short *buffer, int length );};int U16SwapAudioFormatHandler::convert( short *buffer, int length ){ int result = length / 2; while ( length >= 2 ) { *buffer = (short)(((*buffer << 8) | ((*buffer >> 8) & 0xFF)) + 0x8000); ++buffer; length -= 2; } return result;}// Convert unsigned 8-bit samples to normalized raw samples.class U8AudioFormatHandler : public AudioFormatHandler{public: unsigned int readSize( unsigned int length ) { return length; } int convert( short *buffer, int length );};int U8AudioFormatHandler::convert( short *buffer, int length ){ int result = length; unsigned char *buf = (((unsigned char *)buffer) + length); buffer += length; while ( length > 0 ) { *(--buffer) = (short)((((int)(*(--buf))) - 128) << 8); --length; } return result;}// Convert signed 8-bit samples to normalized raw samples.class S8AudioFormatHandler : public AudioFormatHandler{public: unsigned int readSize( unsigned int length ) { return length; } int convert( short *buffer, int length );};int S8AudioFormatHandler::convert( short *buffer, int length ){ int result = length; unsigned char *buf = (((unsigned char *)buffer) + length); buffer += length; while ( length > 0 ) { *(--buffer) = (short)(((int)(*(--buf))) << 8); --length; } return result;}AudioFormatHandler *AudioFormatHandler::create( int format ){ // Determine if the host is little-endian or big-endian. union { short v1; char v2[2]; } un; un.v1 = 0x0102; bool littleEndian = ( un.v2[0] == 0x02 ); // Construct an appropriate handler from the incoming format. switch ( format ) { case AFMT_U8: return new U8AudioFormatHandler; case AFMT_S16_LE: if ( littleEndian ) return new S16AudioFormatHandler; else return new S16SwapAudioFormatHandler; case AFMT_S16_BE: if ( littleEndian ) return new S16SwapAudioFormatHandler; else return new S16AudioFormatHandler; case AFMT_S8: return new S8AudioFormatHandler; case AFMT_U16_LE: if ( littleEndian ) return new U16AudioFormatHandler; else return new U16SwapAudioFormatHandler; case AFMT_U16_BE: if ( littleEndian ) return new U16SwapAudioFormatHandler; else return new U16AudioFormatHandler; default: qDebug( "unknown audio input format - assuming signed 16-bit" ); return new S16AudioFormatHandler; }}// Perform channel doubling to convert mono samples into stereo.class MToSAudioFormatHandler : public AudioFormatHandler{public: MToSAudioFormatHandler( AudioFormatHandler *_linked ) { linked = _linked; } ~MToSAudioFormatHandler() { delete linked; } unsigned int readSize( unsigned int length ) { return linked->readSize( length ); } int convert( short *buffer, int length );private: AudioFormatHandler *linked;};int MToSAudioFormatHandler::convert( short *buffer, int length ){ // Convert the raw samples into their normalized 16-bit form. int samples = linked->convert( buffer, length ); // Perform doubling on the the samples. int posn = samples * 2; while ( posn > 0 ) { posn -= 2; buffer[posn] = buffer[posn + 1] = buffer[posn / 2]; } return samples * 2;}// Perform channel averaging to convert stereo samples into mono.class SToMAudioFormatHandler : public AudioFormatHandler{public: SToMAudioFormatHandler( AudioFormatHandler *_linked ) { linked = _linked; } ~SToMAudioFormatHandler() { delete linked; } unsigned int readSize( unsigned int length ) { return linked->readSize( length ); } int convert( short *buffer, int length );private: AudioFormatHandler *linked;};int SToMAudioFormatHandler::convert( short *buffer, int length ){ // Convert the raw samples into their normalized 16-bit form. int samples = linked->convert( buffer, length ); // Perform averaging on the the samples. int posn = 0; int limit = samples / 2; while ( posn < limit ) { buffer[posn] = (short)(((int)(buffer[posn * 2])) + ((int)(buffer[posn * 2 + 1])) / 2); ++posn; } return limit;}// Resample an audio stream to a different frequency.class ResampleAudioFormatHandler : public AudioFormatHandler{public: ResampleAudioFormatHandler( AudioFormatHandler *_linked, int _from, int _to, int _channels, int bufferSize ); ~ResampleAudioFormatHandler() { delete linked; delete[] temp; } unsigned int readSize( unsigned int length ) { return linked->readSize( length ); } int convert( short *buffer, int length );private: AudioFormatHandler *linked; int from, to, channels; long samplesDue; long rollingLeft; long rollingRight; int numInRolling; short *temp;};ResampleAudioFormatHandler::ResampleAudioFormatHandler ( AudioFormatHandler *_linked, int _from, int _to, int _channels, int bufferSize ){ linked = _linked; from = _from; to = _to; channels = _channels; samplesDue = 0; rollingLeft = 0; rollingRight = 0; numInRolling = 0; temp = new short [bufferSize];}int ResampleAudioFormatHandler::convert( short *buffer, int length ){ // Convert the raw samples into their normalized 16-bit form. int samples = linked->convert( buffer, length ); if ( !samples ) return 0; // Resample the data. We should probably do some kind of curve // fit algorithm, but that can be *very* expensive CPU-wise. memcpy( temp, buffer, samples * sizeof(short) ); int inposn = 0; int outposn = 0; short left, right; long due = samplesDue; long rollLeft = rollingLeft; long rollRight = rollingRight; int num = numInRolling; if ( from < to ) { // Replicate samples to convert to a higher sample rate. if ( channels == 1 ) { while ( inposn < samples ) { due += to; left = temp[inposn++]; while ( due >= from ) { buffer[outposn++] = left; due -= from; } } } else { while ( inposn < samples ) { due += to; left = temp[inposn++]; right = temp[inposn++]; while ( due >= from ) { buffer[outposn++] = left; buffer[outposn++] = right; due -= from; } } } } else { // Average samples to convert to a lower sample rate. // This may lose a small number (from / to) of samples // off the end of the stream. if ( channels == 1 ) { while ( inposn < samples ) { left = temp[inposn++]; rollLeft += (long)left; due += to; ++num; if ( due >= from ) { buffer[outposn++] = (short)(rollLeft / num); rollLeft = 0; num = 0; due -= from; } } } else { while ( inposn < samples ) { left = temp[inposn++]; right = temp[inposn++]; rollLeft += (long)left; rollLeft += (long)right; due += to; ++num; if ( due >= from ) { buffer[outposn++] = (short)(rollLeft / num); buffer[outposn++] = (short)(rollRight / num);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -