33#include "../../utility/PEBLPath.h"
34#include "../../utility/PError.h"
35#include "../../libs/PEBLEnvironment.h"
39#include "../../base/Evaluator-es.h"
41#include "../../base/Evaluator.h"
44#include "../../base/PList.h"
45#include "../../base/PComplexData.h"
61void AudioInCallbackFill(
void * udata, Uint8 * stream,
int len);
62void AudioInCallbackLoop(
void * udata, Uint8 * stream,
int len);
74PlatformAudioIn::PlatformAudioIn()
82 mAudioFormat = AUDIO_S16;
90PlatformAudioIn::~PlatformAudioIn()
92 std::cerr <<
"~PlatformAudioIn: Destructor called\n";
97 std::cerr <<
"~PlatformAudioIn: Closing audio device " << mAudioDevice <<
"\n";
98 SDL_CloseAudioDevice(mAudioDevice);
103 if(mWave.get() && mWave.get() == gAudioBuffer)
105 std::cerr <<
"~PlatformAudioIn: Clearing gAudioBuffer\n";
109 std::cerr <<
"~PlatformAudioIn: Destructor complete\n";
119bool PlatformAudioIn::Initialize(
int type)
123 SDL_AudioSpec want, have;
126 want.freq = mSampleRate;
127 want.format = mAudioFormat;
129 want.samples = mSamples;
130 want.userdata = &have;
135 want.callback = AudioInCallbackFill;
139 want.callback = AudioInCallbackLoop;
143 int numDevices = SDL_GetNumAudioDevices(SDL_TRUE);
155 for(
int i = 0; i < numDevices; i++) {
156 const char* name = SDL_GetAudioDeviceName(i, SDL_TRUE);
157 if(name && strstr(name,
"Digital Microphone")) {
165 const char* deviceName = SDL_GetAudioDeviceName(deviceIndex, SDL_TRUE);
175 mAudioDevice = SDL_OpenAudioDevice(deviceName, SDL_TRUE, &want, &have, 0);
176 if(mAudioDevice == 0)
178 std::string errorMsg = std::string(
"Cannot open audio input device: ") + SDL_GetError();
190 mSampleRate = have.freq;
191 mAudioFormat = have.format;
226 gAudioBuffer = mWave.get();
228 mSampleRate= mWave->
spec.freq;
229 mAudioFormat=mWave->spec.format;
230 if((buffer->spec.format == AUDIO_U8) |
231 (buffer->spec.format == AUDIO_S8) )
235 else if((buffer->spec.format == AUDIO_S16 )|
236 (buffer->spec.format == AUDIO_U16))
240 mWave->bytesPerSample = mBytesPerSample;
241 mSamples = buffer->audiolen/mBytesPerSample;
250bool PlatformAudioIn::CreateBuffer(
int size)
259 std::cerr <<
"CreateBuffer: Created AudioInfo object at " << (
void*)mWave.get() <<
"\n";
262 SDL_AudioSpec *spec = (SDL_AudioSpec *) malloc(
sizeof(SDL_AudioSpec));
264 spec->format=AUDIO_S16;
268 spec->callback=
NULL;
271 Uint32 length = spec->freq * size/1000;
275 Uint32 bufferSize = mBytesPerSample*length;
276 mWave->audio = (Uint8*)malloc(bufferSize);
277 std::cerr <<
"CreateBuffer: Allocated " << bufferSize <<
" bytes at " << (
void*)mWave->audio <<
"\n";
287 mWave->bytesPerSample= mBytesPerSample;
288 mWave->audiolen = mBytesPerSample*length;
290 mWave->recordpos = 0;
295 gAudioBuffer = mWave.get();
296 std::cerr <<
"CreateBuffer: Set gAudioBuffer to " << (
void*)gAudioBuffer <<
"\n";
298 cerr <<
"---------------------------\n";
299 cerr <<
"Creating buffer: \n";
300 cerr <<
"Bytespersample: " << mBytesPerSample << endl;
301 cerr <<
"Size (samples): " << size << endl;
302 cerr <<
"Size (bytes): " << mWave->
audiolen << endl;
303 cerr <<
"freq "<<mWave->spec.freq <<endl;
304 cerr <<
"length: " <<mWave->audiolen<< endl;
305 cerr <<
"---------------------------\n";
312bool PlatformAudioIn::RecordToBuffer()
314 if(mAudioDevice == 0)
321 SDL_PauseAudioDevice(mAudioDevice, 0);
332bool PlatformAudioIn::PauseAudioMonitor()
334 if(mAudioDevice == 0)
339 SDL_PauseAudioDevice(mAudioDevice, 1);
344bool PlatformAudioIn::CloseAudio()
346 if(mAudioDevice == 0)
351 std::cerr <<
"CloseAudio: Starting cleanup (device=" << mAudioDevice <<
")\n";
355 SDL_LockAudioDevice(mAudioDevice);
358 SDL_PauseAudioDevice(mAudioDevice, 1);
362 if(mWave.get() && mWave.get() == gAudioBuffer)
364 std::cerr <<
"CloseAudio: Clearing gAudioBuffer\n";
369 SDL_UnlockAudioDevice(mAudioDevice);
373 std::cerr <<
"CloseAudio: Waiting for callbacks to drain...\n";
377 std::cerr <<
"CloseAudio: Closing SDL device\n";
378 SDL_CloseAudioDevice(mAudioDevice);
386 std::cerr <<
"CloseAudio: Releasing AudioInfo counted_ptr (destructor will free buffer when refcount=0)\n";
390 std::cerr <<
"CloseAudio: Complete\n";
403Variant PlatformAudioIn::VoiceKey(
double threshold,
unsigned int sustain)
413 unsigned int chunksize = mSampleRate/binspersec;
414 double msperchunk = (double)mSampleRate/chunksize/1000;
417 unsigned int sustainSamples = sustain/msperchunk;
432 cerr <<
"------------------------\n";
433 cerr <<
"Computing buffer time\n";
434 cerr <<
"audiolen: " << mWave->audiolen << endl;
435 cerr <<
"bytespersample " << mWave->bytesPerSample << endl;
436 cerr <<
"bytes: " << mBytesPerSample << endl;
438 cerr <<
"chunksize: " << chunksize << endl;
441 int buffertime = double(mWave->audiolen)/mBytesPerSample/chunksize;
443 std::vector<double> powerbins = std::vector<double>(buffertime);
447 unsigned int triptime = 0;
448 unsigned int offtime = 0;
449 unsigned int tickID=0;
450 unsigned int sampleID=0;
455 memset(mWave->audio,0,mWave->audiolen);
460 cerr <<
"recording\n";
462 cerr <<
"chunksize: " << chunksize << endl;
463 cerr <<
"msperchunk: " << msperchunk << endl;
464 cerr <<
"sustain: " << sustain << endl;
465 cerr <<
"sustainsamples: " << sustainSamples << endl;
466 cerr <<
"power bins: " << buffertime << endl;
488 while((gAudioBuffer->
recordpos/mBytesPerSample) > chunksize+sampleID)
494 if(tickID >= buffertime)
496 std::cerr <<
"Voice key: Buffer full without detection (tickID=" << tickID
497 <<
" >= buffertime=" << buffertime <<
")\n";
504 ComputeStats((Sint16*)(gAudioBuffer->
audio+sampleID*mBytesPerSample),chunksize,
505 energy,power,signs,directions,rmssd);
507 powerbins[tickID] = energy;
513 cerr << SDL_GetTicks();
517 for(k = 0; k< 10*power;k++)cerr<<
" "<<std::flush;
520 for(
int j=k; j<10; j++) cerr <<
" ";
526 for(k = 0; k< 10*energy;k++)cerr<<
" "<<std::flush;
528 for(
int j=k; j<10; j++) cerr <<
" ";
533 for(k = 0; k< 10.0*signs/chunksize;k++)cerr<<
" "<<std::flush;
535 for(
int j=k; j<10; j++) cerr <<
" ";
540 for(k = 0; k< 10.0*directions/chunksize;k++)cerr<<
" "<<std::flush;
542 for(
int j=k; j<10; j++) cerr <<
" ";
554 int incoming = (powerbins[tickID]>threshold);
555 int outgoing = (tickID < sustainSamples)? 0:powerbins[tickID-sustainSamples]>threshold;
556 abovecount += incoming - outgoing;
558 if(((
double)abovecount)/sustainSamples > .55 &trip==
false)
561 triptime = tickID -(sustainSamples*.55);
570 if((
double)abovecount/sustainSamples < .2)
576 offtime = tickID- (sustainSamples*.8);
586 sampleID += chunksize;
589 if(sampleID+chunksize >= gAudioBuffer->
audiolen/mBytesPerSample)
605 std::cerr <<
"VoiceKey: Creating return value (triptime=" << (triptime * msperchunk)
606 <<
", offtime=" << (offtime * msperchunk) <<
", trip=" << trip <<
")\n";
608 std::cerr <<
"VoiceKey: About to create PList...\n";
610 std::cerr <<
"VoiceKey: PList created at " << (
void*)newlist <<
"\n";
612 std::cerr <<
"VoiceKey: Pushing back values...\n";
618 std::cerr <<
"VoiceKey: Creating counted_ptr<PEBLObjectBase>...\n";
620 std::cerr <<
"VoiceKey: counted_ptr created\n";
622 std::cerr <<
"VoiceKey: Creating PComplexData...\n";
624 std::cerr <<
"VoiceKey: PComplexData created\n";
629 std::cerr <<
"VoiceKey: Returning Variant\n";
634void PlatformAudioIn::SaveBufferToWave(
Variant filename)
639 int bitsPerSample = mBytesPerSample*8;
642 int subchunk1size = 16;
643 int numChannels = mWave->spec.channels;
644 int subchunk2size = mWave->recordpos;
645 int chunksize = 36+subchunk2size;
650 int sampleRate = mWave->spec.freq;
651 int byteRate = mWave->spec.freq*numChannels*bitsPerSample/8;
652 int blockAlign = numChannels*bitsPerSample/8;
655 std::fstream myFile (filename.
GetString().c_str(), ios::out | ios::binary);
658 myFile.seekp (0, ios::beg);
659 myFile.write (
"RIFF", 4);
660 myFile.write ((
char*) &chunksize, 4);
661 myFile.write (
"WAVE", 4);
662 myFile.write (
"fmt ", 4);
663 myFile.write ((
char*) &subchunk1size, 4);
664 myFile.write ((
char*) &audioFormat, 2);
665 myFile.write ((
char*) &numChannels, 2);
666 myFile.write ((
char*) &sampleRate, 4);
667 myFile.write ((
char*) &byteRate, 4);
668 myFile.write ((
char*) &blockAlign, 2);
669 myFile.write ((
char*) &bitsPerSample, 2);
671 myFile.write (
"data", 4);
672 myFile.write ((
char*) &subchunk2size, 4);
674 myFile.write ((
char*)(mWave->audio), mWave->recordpos);
679void AudioInCallbackFill(
void * udata, Uint8 * stream,
int len)
681 static int callbackCount = 0;
688 Uint8 * sData = stream;
700 int bytestocopy = (len< remaininbuffer ? len: remaininbuffer);
731 if(callbackCount == 1) {
732 std::cerr <<
"WARNING: AudioCallback called but gAudioBuffer is NULL!\n";
742void AudioInCallbackLoop(
void * udata, Uint8 * stream,
int len)
744 static int callbackCount = 0;
747 Uint8 * sData = stream;
752 for(
int i = 0; i < len; i++)
756 gAudioBuffer->
audio[writePos] = sData[i];
765 if(callbackCount % 500 == 1) {
766 std::cerr <<
"AudioCallbackLoop #" << callbackCount
767 <<
": total_bytes=" << gAudioBuffer->
recordpos
774 if(callbackCount == 1) {
775 std::cerr <<
"WARNING: AudioCallbackLoop called but gAudioBuffer is NULL!\n";
788Variant PlatformAudioIn::GetRecentAudioStats(
int milliseconds)
790 if(!mWave.get() || !mWave->audio) {
805 if(mAudioDevice > 0) {
806 SDL_LockAudioDevice(mAudioDevice);
810 Uint32 bytesWanted = (milliseconds / 1000.0) * mSampleRate * mBytesPerSample;
813 if(bytesWanted > mWave->audiolen) {
814 bytesWanted = mWave->audiolen;
818 Uint32 totalBytesWritten = mWave->recordpos;
821 if(totalBytesWritten < bytesWanted) {
822 bytesWanted = totalBytesWritten;
825 if(bytesWanted == 0) {
827 if(mAudioDevice > 0) {
828 SDL_UnlockAudioDevice(mAudioDevice);
841 Uint32 endPos = totalBytesWritten % mWave->audiolen;
845 if(endPos >= bytesWanted) {
847 startPos = endPos - bytesWanted;
850 startPos = mWave->audiolen - (bytesWanted - endPos);
854 Sint16 * tempBuffer = (Sint16*)malloc(bytesWanted);
857 if(mAudioDevice > 0) {
858 SDL_UnlockAudioDevice(mAudioDevice);
872 Uint32 pos = startPos;
873 for(Uint32 i = 0; i < bytesWanted; i++) {
874 ((Uint8*)tempBuffer)[i] = mWave->audio[pos];
875 pos = (pos + 1) % mWave->audiolen;
880 if(mAudioDevice > 0) {
881 SDL_UnlockAudioDevice(mAudioDevice);
885 double energy, power, rmssd;
886 int signs, directions;
888 int numSamples = bytesWanted / mBytesPerSample;
889 ComputeStats(tempBuffer, numSamples, power, energy, signs, directions, rmssd);
908double PlatformAudioIn::Power (Sint16 * data,
int length)
912 for(
int i=0;i <length; i+=mBytesPerSample)
914 double tmp = (double)abs(data[i])/32768 ;
921 double power =(sum)/length;
930void PlatformAudioIn::ComputeStats (Sint16 * data,
int length,
954 double prevdelta = 0;
956 for(
int i=0;i <length; i+=mBytesPerSample)
960 scaled = ((double)data[i])/32768;
962 abssum += abs(scaled);
963 sqsum += scaled*scaled;
964 signsum += (scaled * prev)<0;
966 delta = scaled - prev;
967 dirsum += (delta * prevdelta) < 0;
969 rmssdsum += pow(delta - prevdelta,2);
980 int samples = length/mBytesPerSample;
982 energy = abssum/samples;
983 power = sqrt(sqsum/samples);
984 rmssd = sqrt(rmssdsum/samples);
985 signchanges = signsum;
void PushBack(const Variant &v)
std::string GetString() const
Variant RecordToBuffer(Variant v)
void SignalWarning(const std::string &message)
void SignalFatalError(const std::string &message)