diff options
Diffstat (limited to 'demos/mobile/quickhit/ga_src')
-rw-r--r-- | demos/mobile/quickhit/ga_src/GEAudioBuffer.cpp | 391 | ||||
-rw-r--r-- | demos/mobile/quickhit/ga_src/GEAudioBuffer.h | 137 | ||||
-rw-r--r-- | demos/mobile/quickhit/ga_src/GEAudioOut.cpp | 144 | ||||
-rw-r--r-- | demos/mobile/quickhit/ga_src/GEAudioOut.h | 89 | ||||
-rw-r--r-- | demos/mobile/quickhit/ga_src/GEInterfaces.cpp | 177 | ||||
-rw-r--r-- | demos/mobile/quickhit/ga_src/GEInterfaces.h | 88 |
6 files changed, 1026 insertions, 0 deletions
diff --git a/demos/mobile/quickhit/ga_src/GEAudioBuffer.cpp b/demos/mobile/quickhit/ga_src/GEAudioBuffer.cpp new file mode 100644 index 0000000..7da9219 --- /dev/null +++ b/demos/mobile/quickhit/ga_src/GEAudioBuffer.cpp @@ -0,0 +1,391 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <math.h> +#include "GEAudioBuffer.h" + +using namespace GE; + + +struct SWavHeader { + char chunkID[4]; + unsigned int chunkSize; + char format[4]; + + unsigned char subchunk1id[4]; + unsigned int subchunk1size; + unsigned short audioFormat; + unsigned short nofChannels; + unsigned int sampleRate; + unsigned int byteRate; + + unsigned short blockAlign; + unsigned short bitsPerSample; + + unsigned char subchunk2id[4]; + unsigned int subchunk2size; + +}; + +CAudioBuffer::CAudioBuffer() { + m_data = 0; + m_dataLength = 0; + m_sampleFunction = 0; +}; + + +CAudioBuffer::~CAudioBuffer() { + reallocate(0); +} + +void CAudioBuffer::reallocate( int length ) { + if (m_data) delete [] ((char*)m_data); + m_dataLength = length; + if (m_dataLength>0) { + m_data = new char[ m_dataLength ]; + } else m_data = 0; +}; + + +CAudioBuffer* CAudioBuffer::loadWav( QString fileName ) { + QFile *wavFile = new QFile( fileName ); + + + if (wavFile->open(QIODevice::ReadOnly)) { + SWavHeader header; + + wavFile->read( header.chunkID, 4 ); + if (header.chunkID[0]!='R' || header.chunkID[1]!='I' || header.chunkID[2]!='F' || header.chunkID[3]!='F') return 0; // incorrect header + + wavFile->read( (char*)&header.chunkSize,4 ); + wavFile->read( (char*)&header.format,4 ); + + if (header.format[0]!='W' || header.format[1]!='A' || header.format[2]!='V' || header.format[3]!='E') return 0; // incorrect header + + wavFile->read( (char*)&header.subchunk1id,4 ); + if (header.subchunk1id[0]!='f' || header.subchunk1id[1]!='m' || header.subchunk1id[2]!='t' || header.subchunk1id[3]!=' ') return 0; // incorrect header + + wavFile->read( (char*)&header.subchunk1size,4 ); + wavFile->read( (char*)&header.audioFormat,2 ); + wavFile->read( (char*)&header.nofChannels,2 ); + wavFile->read( (char*)&header.sampleRate,4 ); + wavFile->read( (char*)&header.byteRate,4 ); + wavFile->read( (char*)&header.blockAlign,2 ); + wavFile->read( (char*)&header.bitsPerSample,2 ); + + qDebug() << fileName << " opened"; + + while (1) { + if (wavFile->read( (char*)&header.subchunk2id,4 ) != 4) return 0; + if (wavFile->read( (char*)&header.subchunk2size,4 ) != 4) return 0; + //int deb_size = header.subchunk2size; + //char tes[4]; + //memcpy(tes, header.subchunk2id, 4 ); + //if (header.subchunk2id[0]!='d' || header.subchunk2id[1]!='a' || header.subchunk2id[2]!='t' || header.subchunk2id[3]!='a') return 0; // incorrect header + if (header.subchunk2id[0]=='d' && header.subchunk2id[1]=='a' && header.subchunk2id[2]=='t' && header.subchunk2id[3]=='a') break; // found the data, chunk + // this was not the data-chunk. skip it + if (header.subchunk2size<1) return 0; // error in file + char *unused = new char[header.subchunk2size]; + wavFile->read( unused, header.subchunk2size ); + delete [] unused; + } + + + + // the data follows. + if (header.subchunk2size<1) return 0; + + CAudioBuffer *rval = new CAudioBuffer; + rval->m_nofChannels = header.nofChannels; + rval->m_bitsPerSample = header.bitsPerSample; + rval->m_samplesPerSec = header.sampleRate; + rval->m_signedData = 0; // where to know this? + rval->reallocate( header.subchunk2size ); + + wavFile->read( (char*)rval->m_data, header.subchunk2size ); + + // choose a good sampling function. + rval->m_sampleFunction = 0; + if (rval->m_nofChannels==1) { + if (rval->m_bitsPerSample == 8) rval->m_sampleFunction = sampleFunction8bitMono; + if (rval->m_bitsPerSample == 16) rval->m_sampleFunction = sampleFunction16bitMono; + } else { + if (rval->m_bitsPerSample == 8) rval->m_sampleFunction = sampleFunction8bitStereo; + if (rval->m_bitsPerSample == 16) rval->m_sampleFunction = sampleFunction16bitStereo; + } + + return rval; + + + } else { + qDebug() << fileName << " NOT opened"; + return 0; + } + + delete wavFile; +}; + + +CAudioBuffer* CAudioBuffer::loadWav( FILE *wavFile ) { + // read the header. + SWavHeader header; + fread( header.chunkID, 4, 1, wavFile ); + if (header.chunkID[0]!='R' || header.chunkID[1]!='I' || header.chunkID[2]!='F' || header.chunkID[3]!='F') return 0; // incorrect header + + fread( &header.chunkSize, 4, 1, wavFile ); + fread( header.format, 4, 1, wavFile ); + if (header.format[0]!='W' || header.format[1]!='A' || header.format[2]!='V' || header.format[3]!='E') return 0; // incorrect header + + fread( header.subchunk1id, 4, 1, wavFile ); + if (header.subchunk1id[0]!='f' || header.subchunk1id[1]!='m' || header.subchunk1id[2]!='t' || header.subchunk1id[3]!=' ') return 0; // incorrect header + + fread( &header.subchunk1size, 4, 1, wavFile ); + fread( &header.audioFormat, 2, 1, wavFile ); + fread( &header.nofChannels, 2, 1, wavFile ); + fread( &header.sampleRate, 4, 1, wavFile ); + fread( &header.byteRate, 4, 1, wavFile ); + + fread( &header.blockAlign, 2, 1, wavFile ); + fread( &header.bitsPerSample, 2, 1, wavFile ); + + fread( header.subchunk2id, 4, 1, wavFile ); + if (header.subchunk2id[0]!='d' || header.subchunk2id[1]!='a' || header.subchunk2id[2]!='t' || header.subchunk2id[3]!='a') return 0; // incorrect header + fread( &header.subchunk2size, 4, 1, wavFile ); + + + // the data follows. + if (header.subchunk2size<1) return 0; + + CAudioBuffer *rval = new CAudioBuffer; + rval->m_nofChannels = header.nofChannels; + rval->m_bitsPerSample = header.bitsPerSample; + rval->m_samplesPerSec = header.sampleRate; + rval->m_signedData = 0; // where to know this? + rval->reallocate( header.subchunk2size ); + + fread( rval->m_data, 1, header.subchunk2size, wavFile ); + + + + // choose a good sampling function. + rval->m_sampleFunction = 0; + if (rval->m_nofChannels==1) { + if (rval->m_bitsPerSample == 8) rval->m_sampleFunction = sampleFunction8bitMono; + if (rval->m_bitsPerSample == 16) rval->m_sampleFunction = sampleFunction16bitMono; + } else { + if (rval->m_bitsPerSample == 8) rval->m_sampleFunction = sampleFunction8bitStereo; + if (rval->m_bitsPerSample == 16) rval->m_sampleFunction = sampleFunction16bitStereo; + } + + return rval; +}; + + + +AUDIO_SAMPLE_TYPE CAudioBuffer::sampleFunction8bitMono( CAudioBuffer *abuffer, int pos, int channel ) { + return (AUDIO_SAMPLE_TYPE)(((unsigned char*)(abuffer->m_data))[pos]-128)<<8; +}; + +AUDIO_SAMPLE_TYPE CAudioBuffer::sampleFunction16bitMono( CAudioBuffer *abuffer, int pos, int channel ) { + return (AUDIO_SAMPLE_TYPE)(((short*)(abuffer->m_data))[pos]); +}; + +AUDIO_SAMPLE_TYPE CAudioBuffer::sampleFunction8bitStereo( CAudioBuffer *abuffer, int pos, int channel ) { + return ((AUDIO_SAMPLE_TYPE)(((char*)(abuffer->m_data))[pos*abuffer->m_nofChannels + channel])<<8); +}; + + +AUDIO_SAMPLE_TYPE CAudioBuffer::sampleFunction16bitStereo( CAudioBuffer *abuffer, int pos, int channel ) { + return (AUDIO_SAMPLE_TYPE)(((short*)(abuffer->m_data))[pos*abuffer->m_nofChannels + channel]); +}; + +CAudioBufferPlayInstance *CAudioBuffer::playWithMixer( CAudioMixer &mixer ) { + CAudioBufferPlayInstance *i = (CAudioBufferPlayInstance*)mixer.addAudioSource( new CAudioBufferPlayInstance( this )); + return i; +}; + + +CAudioBufferPlayInstance::CAudioBufferPlayInstance() { + m_fixedPos = 0; + m_fixedInc = 0; + m_buffer = 0; + m_fixedLeftVolume = 4096; + m_fixedRightVolume = 4096; + m_destroyWhenFinished = true; + m_finished = false; +}; + +CAudioBufferPlayInstance::CAudioBufferPlayInstance( CAudioBuffer *startPlaying ) { + m_fixedPos = 0; + m_fixedInc = 0; + m_fixedLeftVolume = 4096; + m_fixedRightVolume = 4096; + m_destroyWhenFinished = true; + m_finished = false; + playBuffer( startPlaying, 1.0f, 1.0f ); +}; + +void CAudioBufferPlayInstance::playBuffer( CAudioBuffer *startPlaying, float volume, float speed, int loopTimes ) { + m_buffer = startPlaying; + m_fixedLeftVolume = (int)(4096.0f*volume); + m_fixedRightVolume = m_fixedLeftVolume; + m_fixedPos = 0; + //m_fixedInc = ( startPlaying->getSamplesPerSec() * (int)(4096.0f*speed)) / AUDIO_FREQUENCY; + setSpeed( speed ); + m_loopTimes = loopTimes; + +}; + +CAudioBufferPlayInstance::~CAudioBufferPlayInstance() { + +}; + + +void CAudioBufferPlayInstance::stop() { + m_buffer = 0; + m_finished = true; +}; + +void CAudioBufferPlayInstance::setSpeed( float speed ) { + if (!m_buffer) return; + m_fixedInc = (int)( ((float)m_buffer->getSamplesPerSec() * 4096.0f*speed) / (float)AUDIO_FREQUENCY ); +}; + +void CAudioBufferPlayInstance::setLeftVolume( float vol ) { + m_fixedLeftVolume = (int)(4096.0f*vol); +}; + +void CAudioBufferPlayInstance::setRightVolume( float vol ) { + m_fixedRightVolume = (int)(4096.0f*vol); +}; + +bool CAudioBufferPlayInstance::canBeDestroyed() { + if (m_finished==true && + m_destroyWhenFinished==true) return true; else return false; +}; + + + +// Does not do any bound-checking. Must be checked before called. +int CAudioBufferPlayInstance::mixBlock( AUDIO_SAMPLE_TYPE *target, int samplesToMix ) { + SAMPLE_FUNCTION_TYPE sampleFunction = m_buffer->getSampleFunction(); + if (!sampleFunction) return 0; // unsupported sampletype + AUDIO_SAMPLE_TYPE *t_target = target+samplesToMix*2; + int sourcepos; + //int tempCounter = 0; + + if (m_buffer->getNofChannels() == 2) { // stereo + while (target!=t_target) { + sourcepos = m_fixedPos>>12; + target[0] = (((((sampleFunction)( m_buffer, sourcepos, 0) * (4096-(m_fixedPos&4095)) + (sampleFunction)( m_buffer, sourcepos+1, 0) * (m_fixedPos&4095) ) >> 12) * m_fixedLeftVolume) >> 12); + target[1] = (((((sampleFunction)( m_buffer, sourcepos, 1) * (4096-(m_fixedPos&4095)) + (sampleFunction)( m_buffer, sourcepos+1, 1) * (m_fixedPos&4095) ) >> 12) * m_fixedRightVolume) >> 12); + m_fixedPos+=m_fixedInc; + target+=2; + //tempCounter++; + }; + } else { // mono + int temp; + while (target!=t_target) { + sourcepos = m_fixedPos>>12; + temp = (((sampleFunction)( m_buffer, sourcepos, 0 ) * (4096-(m_fixedPos&4095)) + (sampleFunction)( m_buffer, sourcepos+1, 0 ) * (m_fixedPos&4095) ) >> 12); + target[0] = ((temp*m_fixedLeftVolume)>>12); + target[1] = ((temp*m_fixedRightVolume)>>12); + m_fixedPos+=m_fixedInc; + target+=2; + //tempCounter++; + }; + + }; + + return samplesToMix; +}; + + + +int CAudioBufferPlayInstance::pullAudio( AUDIO_SAMPLE_TYPE *target, int bufferLength ) { + if (!m_buffer) return 0; // no sample associated to mix.. + + int channelLength = ((m_buffer->getDataLength()) / (m_buffer->getNofChannels()*m_buffer->getBytesPerSample()))-2; + + int samplesToWrite = bufferLength/2; + int amount; + int totalMixed = 0; + + + while (samplesToWrite>0) { + int samplesLeft = channelLength - (m_fixedPos>>12); + int maxMixAmount = (int)(((long long int)(samplesLeft)<<12) / m_fixedInc ); // This is how much we can mix at least + //int maxMixAmount = (int)((float)samplesLeft / ((float)m_fixedInc/4096.0f)); + //if (maxMixAmount<1) maxMixAmount = 1; // NOTE, THIS MIGHT CAUSE PROBLEMS. NEEDS CHECKING + if (maxMixAmount>samplesToWrite) { + maxMixAmount=samplesToWrite; + } + + if (maxMixAmount > 0) { + amount=mixBlock(target+totalMixed * 2, maxMixAmount); + + if (amount == 0) + { + // Error! + break; + } + + totalMixed+=amount; + } else { + amount = 0; + m_fixedPos = channelLength<<12; + } + + // sample is ended,.. check the looping variables and see what to do. + if ((m_fixedPos>>12)>=channelLength) { + m_fixedPos -= (channelLength<<12); + if (m_loopTimes>0) m_loopTimes--; + if (m_loopTimes==0) { + stop(); + return totalMixed; + } + } + + samplesToWrite-=amount; + if (samplesToWrite<1) break; + }; + return totalMixed*2; +}; diff --git a/demos/mobile/quickhit/ga_src/GEAudioBuffer.h b/demos/mobile/quickhit/ga_src/GEAudioBuffer.h new file mode 100644 index 0000000..5fe5f00 --- /dev/null +++ b/demos/mobile/quickhit/ga_src/GEAudioBuffer.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __GE_IGA_AUDIOBUFFER__ +#define __GE_IGA_AUDIOBUFFER__ + +#include <QFile> +#include "GEInterfaces.h" + + +namespace GE { + + class CAudioBufferPlayInstance; + class CAudioBuffer; // forward declaration + typedef AUDIO_SAMPLE_TYPE(*SAMPLE_FUNCTION_TYPE)(CAudioBuffer *abuffer, int pos, int channel); + + class CAudioBuffer { // container for a sound + public: + CAudioBuffer(); + virtual ~CAudioBuffer(); + + static CAudioBuffer* loadWav( QString fileName ); + static CAudioBuffer* loadWav( FILE *wavFile ); // support for stdio + void reallocate( int length ); + + + inline void* getRawData() { return m_data; } + inline int getDataLength() { return m_dataLength; } + + inline int getBytesPerSample() { return (m_bitsPerSample>>3); } + inline int getBitsPerSample() { return m_bitsPerSample; } + inline int getSamplesPerSec() { return m_samplesPerSec; } + inline short getNofChannels() { return m_nofChannels; } + inline SAMPLE_FUNCTION_TYPE getSampleFunction() { return m_sampleFunction; } + + + // static implementations of sample functions + static AUDIO_SAMPLE_TYPE sampleFunction8bitMono( CAudioBuffer *abuffer, int pos, int channel ); + static AUDIO_SAMPLE_TYPE sampleFunction16bitMono( CAudioBuffer *abuffer, int pos, int channel ); + static AUDIO_SAMPLE_TYPE sampleFunction8bitStereo( CAudioBuffer *abuffer, int pos, int channel ); + static AUDIO_SAMPLE_TYPE sampleFunction16bitStereo( CAudioBuffer *abuffer, int pos, int channel ); + + CAudioBufferPlayInstance *playWithMixer( GE::CAudioMixer &mixer ); + + protected: + SAMPLE_FUNCTION_TYPE m_sampleFunction; + short m_nofChannels; + void *m_data; + int m_dataLength; // in bytes + short m_bitsPerSample; + bool m_signedData; + int m_samplesPerSec; + }; + + + + class CAudioBufferPlayInstance : public IAudioSource { + public: + CAudioBufferPlayInstance(); + CAudioBufferPlayInstance( CAudioBuffer *start_playing ); + virtual ~CAudioBufferPlayInstance(); + void playBuffer( CAudioBuffer *startPlaying, float volume, float fixedSpeed, int loopTimes = 0 ); // looptimes -1 = loop forever + + void setSpeed( float speed ); + void setLeftVolume( float lvol ); + void setRightVolume( float rvol ); + + + inline void setLoopTimes( int ltimes ) { m_loopTimes = ltimes; } + void stop(); + + + + int pullAudio( AUDIO_SAMPLE_TYPE *target, int bufferLength ); + bool canBeDestroyed(); + + bool isPlaying() { if (m_buffer) return true; else return false; } + inline bool isFinished() { return m_finished; } + inline bool destroyWhenFinished() { return m_destroyWhenFinished; } + inline void setDestroyWhenFinished( bool set ) { m_destroyWhenFinished = set; } + + protected: + int mixBlock( AUDIO_SAMPLE_TYPE *target, int bufferLength ); + bool m_finished; + bool m_destroyWhenFinished; + int m_fixedPos; + int m_fixedInc; + + int m_fixedLeftVolume; + int m_fixedRightVolume; + int m_fixedCenter; + int m_loopTimes; + CAudioBuffer *m_buffer; + }; + +}; + + + +#endif diff --git a/demos/mobile/quickhit/ga_src/GEAudioOut.cpp b/demos/mobile/quickhit/ga_src/GEAudioOut.cpp new file mode 100644 index 0000000..73a765c --- /dev/null +++ b/demos/mobile/quickhit/ga_src/GEAudioOut.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qstring.h> +#include <QAudioOutput> + +#include "GEAudioOut.h" + +using namespace GE; +//using namespace QTM_NAMESPACE; + +/* +#ifndef Q_OS_WIN32 +QTM_USE_NAMESPACE +#endif +*/ + +const int CHANNELS = 2; +const QString CODEC = "audio/pcm"; +const QAudioFormat::Endian BYTEORDER = QAudioFormat::LittleEndian; +const QAudioFormat::SampleType SAMTYPE = QAudioFormat::SignedInt; + + + +AudioOut::AudioOut( QObject *parent, GE::IAudioSource *source ) : QThread(parent) { // qobject + m_source = source; + QAudioFormat format; + format.setFrequency(AUDIO_FREQUENCY); + format.setChannels(CHANNELS); + format.setSampleSize(AUDIO_SAMPLE_BITS); + format.setCodec(CODEC); + format.setByteOrder(BYTEORDER); + format.setSampleType(SAMTYPE); + + QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); + if (!info.isFormatSupported(format)) + format = info.nearestFormat(format); + + + m_audioOutput = new QAudioOutput(info,format); + +#ifdef Q_WS_MAEMO_5 + m_audioOutput->setBufferSize(20000); + m_sendBufferSize = 5000; +#else + m_audioOutput->setBufferSize(16000); + m_sendBufferSize = 4000; +#endif + + m_outTarget = m_audioOutput->start(); + + + m_sendBuffer = new AUDIO_SAMPLE_TYPE[ m_sendBufferSize ]; + m_samplesMixed = 0; + + m_runstate=0; + +#ifndef Q_OS_SYMBIAN + start(); +#else + m_audioOutput->setNotifyInterval(5); + connect(m_audioOutput,SIGNAL(notify()),SLOT(audioNotify())); +#endif + +}; + + +AudioOut::~AudioOut() { + if (m_runstate==0) m_runstate = 1; + if (QThread::isRunning() == false) m_runstate = 2; + while (m_runstate!=2) { msleep(50); } // wait until the thread is finished + m_audioOutput->stop(); + delete m_audioOutput; + delete [] m_sendBuffer; +}; + + +void AudioOut::audioNotify() { + tick(); +}; + +void AudioOut::tick() { + // fill data to buffer as much as free space is available.. + int samplesToWrite = m_audioOutput->bytesFree() / (CHANNELS*AUDIO_SAMPLE_BITS/8); + samplesToWrite*=2; + + if (samplesToWrite > m_sendBufferSize) samplesToWrite = m_sendBufferSize; + if (samplesToWrite<=0) return; + int mixedSamples = m_source->pullAudio( m_sendBuffer, samplesToWrite ); + m_outTarget->write( (char*)m_sendBuffer, mixedSamples*2 ); + +}; + + +void AudioOut::run() { + if (!m_source) { m_runstate=2; return; } + int sleepTime = m_sendBufferSize * 340 / AUDIO_FREQUENCY; + if (sleepTime<2) sleepTime = 2; + + while (m_runstate==0) { + tick(); + msleep(sleepTime); + }; + m_runstate = 2; +}; + + diff --git a/demos/mobile/quickhit/ga_src/GEAudioOut.h b/demos/mobile/quickhit/ga_src/GEAudioOut.h new file mode 100644 index 0000000..dc1f744 --- /dev/null +++ b/demos/mobile/quickhit/ga_src/GEAudioOut.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __GE_QTAUDIOOUT__ +#define __GE_QTAUDIOOUT__ + +#include <QtCore/qobject.h> +#include <QtCore/qfile.h> +#include <QtMultimedia> +#include <QtCore/qtimer.h> +#include <QtCore/qstring.h> +#include <QThread> + +#include "GEInterfaces.h" + + +class QAudioOutput; + +namespace GE { + + + + class AudioOut : public QThread { + Q_OBJECT + + public: + AudioOut(QObject *parent, GE::IAudioSource *source); + virtual ~AudioOut(); + + + + private slots: + void audioNotify(); // for internal notify "solution" + + + protected: + void tick(); + virtual void run(); // this is for the threaded mode only + + + qint64 m_samplesMixed; + + QAudioOutput *m_audioOutput; + QIODevice *m_outTarget; + GE::IAudioSource *m_source; + int m_runstate; + AUDIO_SAMPLE_TYPE *m_sendBuffer; + int m_sendBufferSize; + }; +} + +#endif diff --git a/demos/mobile/quickhit/ga_src/GEInterfaces.cpp b/demos/mobile/quickhit/ga_src/GEInterfaces.cpp new file mode 100644 index 0000000..a71f738 --- /dev/null +++ b/demos/mobile/quickhit/ga_src/GEInterfaces.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <memory.h> +#include "GEInterfaces.h" + + +using namespace GE; + +/** + * CAudioSource + * common functionality + * + */ +IAudioSource::IAudioSource() { + m_next = 0; +}; + +IAudioSource::~IAudioSource() { + + +}; + +/** + * CAudioMixer + * + */ +CAudioMixer::CAudioMixer() { + m_sourceList = 0; + m_mixingBuffer = 0; + m_mixingBufferLength = 0; + m_fixedGeneralVolume = 4096; +}; + + +CAudioMixer::~CAudioMixer() { + destroyList(); + if (m_mixingBuffer) { + delete [] m_mixingBuffer; + m_mixingBuffer = 0; + }; +}; + +void CAudioMixer::destroyList() { + m_mutex.lock(); + IAudioSource *l = m_sourceList; + while (l) { + IAudioSource *n = l->m_next; + delete l; + l = n; + }; + m_sourceList = 0; + m_mutex.unlock(); +}; + + +IAudioSource* CAudioMixer::addAudioSource( IAudioSource *source ) { + m_mutex.lock(); + source->m_next = 0; + if (m_sourceList) { + IAudioSource *l = m_sourceList; + while (l->m_next) l = l->m_next; + l->m_next = source; + } else m_sourceList = source; + m_mutex.unlock(); + return source; + +}; + + +bool CAudioMixer::removeAudioSource( IAudioSource *source ) { + return true; +}; + +void CAudioMixer::setGeneralVolume( float vol ) { + m_fixedGeneralVolume = (4096.0f*vol); +}; + +int CAudioMixer::pullAudio( AUDIO_SAMPLE_TYPE *target, int bufferLength ) { + + if (!m_sourceList) return 0; + + m_mutex.lock(); + + + if (m_mixingBufferLength<bufferLength) { + if (m_mixingBuffer) delete [] m_mixingBuffer; + m_mixingBufferLength = bufferLength; + m_mixingBuffer = new AUDIO_SAMPLE_TYPE[ m_mixingBufferLength ]; + }; + + memset( target, 0, sizeof( AUDIO_SAMPLE_TYPE ) * bufferLength ); + + AUDIO_SAMPLE_TYPE *t; + AUDIO_SAMPLE_TYPE *t_target; + AUDIO_SAMPLE_TYPE *s; + + IAudioSource *prev = 0; + IAudioSource *l = m_sourceList; + while (l) { + IAudioSource *next = l->m_next; + + // process l + int mixed = l->pullAudio( m_mixingBuffer, bufferLength ); + if (mixed>0) { + // mix to main.. + t = target; + t_target = t+mixed; + s = m_mixingBuffer; + while (t!=t_target) { + *t +=(((*s)*m_fixedGeneralVolume)>>12); + t++; + s++; + }; + }; + + + + // autodestroy + if (l->canBeDestroyed() == true) { // NOTE, IS UNDER TESTING,... MIGHT CAUSE UNPREDICTABLE CRASHING WITH SOME USE CASES!!! + if (!prev) + m_sourceList = next; + else prev->m_next = next; + delete l; + l = 0; + }; + + + + + prev = l; + l = next; + }; + m_mutex.unlock(); + return bufferLength; +}; + + + + diff --git a/demos/mobile/quickhit/ga_src/GEInterfaces.h b/demos/mobile/quickhit/ga_src/GEInterfaces.h new file mode 100644 index 0000000..7abd984 --- /dev/null +++ b/demos/mobile/quickhit/ga_src/GEInterfaces.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __GE_IGA_INTERFACES__ +#define __GE_IGA_INTERFACES__ + +#include <QMutex> + +namespace GE { + +#define AUDIO_FREQUENCY 22050 +#define AUDIO_SAMPLE_TYPE short +#define AUDIO_SAMPLE_BITS 16 + + class IAudioSource { + public: + IAudioSource(); + virtual ~IAudioSource(); + + virtual int pullAudio( AUDIO_SAMPLE_TYPE *target, int bufferLength ) = 0; + virtual bool canBeDestroyed() { return false; } + + IAudioSource *m_next; // for listing, do not touch if you dont know what you are doing. + }; + + + class CAudioMixer : public IAudioSource { + public: + CAudioMixer(); + virtual ~CAudioMixer(); + void destroyList(); // destroy all the sources in the list + + + IAudioSource* addAudioSource( IAudioSource *s ); // add new audio source to the list + bool removeAudioSource( IAudioSource *s ); // remove an audio source from the list + int pullAudio( AUDIO_SAMPLE_TYPE *target, int bufferLength ); + void setGeneralVolume( float vol ); + + + protected: + QMutex m_mutex; + int m_fixedGeneralVolume; + AUDIO_SAMPLE_TYPE *m_mixingBuffer; + int m_mixingBufferLength; + IAudioSource *m_sourceList; + }; + +}; + + +#endif |