From b73ae037186602c45850c83b927fddb7632ae279 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Mon, 14 Apr 2008 22:48:54 +0000 Subject: [PATCH] fix newlines --- stepmania/src/PitchDetectionTest.cpp | 772 +-- stepmania/src/PitchDetectionTest.h | 124 +- stepmania/src/PitchDetectionTestUtil.cpp | 6706 +++++++++++----------- stepmania/src/PitchDetectionTestUtil.h | 150 +- 4 files changed, 3876 insertions(+), 3876 deletions(-) diff --git a/stepmania/src/PitchDetectionTest.cpp b/stepmania/src/PitchDetectionTest.cpp index f25ef9f44f..08ec6f9e74 100644 --- a/stepmania/src/PitchDetectionTest.cpp +++ b/stepmania/src/PitchDetectionTest.cpp @@ -1,386 +1,386 @@ -#include "global.h" -#include "PitchDetectionTest.h" -#include "PitchDetectionTestUtil.h" -#include "srpd.h" -#include "EST_filter.h" -#include "RageLog.h" -#include "RageUtil.h" -#include "NoteTypes.h" -#include - -MicrophoneStatus PitchDetectionTest::s_ms; -Microphone *PitchDetectionTest::s_pMicrophone = NULL; - -#define MAX_BUFFERS 3 - -// http://tomscarff.tripod.com/midi_analyser/midi_note_frequency.htm -// http://musicdsp.org/showone.php?id=125 -const float MIDI_A4_FREQUENCY = 440.0; -const int MIDI_A4_NUMBER = 69; -const int MIDI_C4_NUMBER = 60; // middle C -const RString NOTE_NAME[MIDI_NOTES_PER_OCTAVE] = {"A ","A#","B ","C ","C#","D ","D#","E ","F ","F#","G ","G#"}; - -float MidiNoteToFreq( int iMidiNote ) -{ - return MIDI_A4_FREQUENCY * powf( 2.0, ((float)iMidiNote - MIDI_A4_NUMBER) / MIDI_NOTES_PER_OCTAVE ); -} - -float log2f( float n ) -{ - // logb (x) = (loga(x)) / (loga(B)) - return logf(n) / logf(2); -} - -bool FreqToMidiNote( float fFreq, float &fMidiNoteOut ) -{ - if( fFreq < 20 ) // well below A0 (MidiNote = 1) - return false; - fMidiNoteOut = MIDI_NOTES_PER_OCTAVE * log2f( fFreq / MIDI_A4_FREQUENCY) + MIDI_A4_NUMBER; - return fMidiNoteOut >= 1; -} - -#undef bool - -bool PitchDetectionTest::MidiNoteToString( int iMidiNote, RString &sMidiNoteOut ) -{ - if( iMidiNote < 1 ) - return false; - int iDiff = iMidiNote - MIDI_A4_NUMBER; - wrap( iDiff, MIDI_NOTES_PER_OCTAVE ); - sMidiNoteOut = NOTE_NAME[iDiff]; - return true; -} - -bool MidiNoteToOctave( int iMidiNote, int &iOctaveOut ) -{ - if( iMidiNote < 1 ) - return false; - // middle C is start of octave 4. - int iOctave = (int)floorf( ((float)iMidiNote - MIDI_C4_NUMBER) / MIDI_NOTES_PER_OCTAVE ); - iOctaveOut = iOctave + 4; - return true; -} - -bool MidiNoteToStringAndOctave( int iMidiNote, RString &sMidiNoteOut ) -{ - if( !PitchDetectionTest::MidiNoteToString(iMidiNote, sMidiNoteOut) ) - return false; - int iOctave; - if( !MidiNoteToOctave(iMidiNote, iOctave) ) - return false; - sMidiNoteOut += ssprintf("%d",iOctave); - return true; -} - -float PitchDetectionTest::WrapToNearestOctave( float fMidiNote, float fTargetMidiNote ) -{ - float fDiff = fMidiNote - fTargetMidiNote; - fDiff += MIDI_NOTES_PER_OCTAVE / 2; - wrap( fDiff, (float)MIDI_NOTES_PER_OCTAVE ); - fDiff -= MIDI_NOTES_PER_OCTAVE / 2; - float fRet = fTargetMidiNote + fDiff; - return fRet; -} - - -void CALLBACK waveInProc(HWAVEIN hwi,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2); - -class MicrophoneImpl -{ -public: - HWAVEIN m_hWaveIn; - WAVEFORMATEX m_stWFEX; - WAVEHDR m_stWHDR[MAX_BUFFERS]; - DetectPitch m_dp; - HMMIO m_hOPFile; - MMIOINFO m_stmmIF; - MMCKINFO m_stckOut,m_stckOutRIFF; - - static MicrophoneImpl *s_pMicrophoneImpl; // one and only for the callback function to use - - - void Init() - { - m_hWaveIn=NULL; - ZeroMemory(&m_stWFEX,sizeof(WAVEFORMATEX)); - ZeroMemory(m_stWHDR,MAX_BUFFERS*sizeof(WAVEHDR)); - s_pMicrophoneImpl = this; - } - - void FillDevices() - { - WAVEINCAPS stWIC={0}; - - UINT nDevices=waveInGetNumDevs(); - - for(UINT nC1=0;nC1Trace( stWIC.szPname ); - else - FAIL_M("bad"); - } - } - - void StartRecording() - { - OpenDevice(); - - m_dp.Init( SAMPLES_PER_SEC ); - - PrepareBuffers(); - MMRESULT mRes=waveInStart(m_hWaveIn); - if(mRes!=0) - FAIL_M("bad"); - } - - void StopRecording() - { - CloseDevice(); - } - - void OpenDevice() - { - MMRESULT mRes=0; - - m_stWFEX.nSamplesPerSec=SAMPLES_PER_SEC; - m_stWFEX.nChannels=1; - m_stWFEX.wBitsPerSample = 16; - m_stWFEX.wFormatTag=WAVE_FORMAT_PCM; - m_stWFEX.nBlockAlign=m_stWFEX.nChannels*m_stWFEX.wBitsPerSample/8; - m_stWFEX.nAvgBytesPerSec=m_stWFEX.nSamplesPerSec*m_stWFEX.nBlockAlign; - m_stWFEX.cbSize=sizeof(WAVEFORMATEX); - int device = 0; - - WAVEINCAPS stWIC={0}; - ZeroMemory(&stWIC,sizeof(WAVEINCAPS)); - mRes=waveInGetDevCaps(device,&stWIC,sizeof(WAVEINCAPS)); - if(mRes==0) - LOG->Trace( stWIC.szPname ); - else - FAIL_M("bad"); - - - mRes=waveInOpen(&m_hWaveIn,device,&m_stWFEX,(DWORD_PTR)waveInProc,(DWORD_PTR)this,CALLBACK_FUNCTION); - if(mRes!=MMSYSERR_NOERROR) - FAIL_M("bad"); - - - - const char *csT1 = "C:\\cvs\\stepmania\\speech-test.wav"; - ZeroMemory(&m_stmmIF,sizeof(MMIOINFO)); - DeleteFile((PCHAR)(LPCTSTR)csT1); - m_hOPFile=mmioOpen((PCHAR)(LPCTSTR)csT1,&m_stmmIF,MMIO_WRITE | MMIO_CREATE); - if(m_hOPFile==NULL) - FAIL_M("Can not open file..."); - - ZeroMemory(&m_stckOutRIFF,sizeof(MMCKINFO)); - m_stckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); - mRes=mmioCreateChunk(m_hOPFile, &m_stckOutRIFF, MMIO_CREATERIFF); - if(mRes!=MMSYSERR_NOERROR) - { - FAIL_M("bad"); - } - ZeroMemory(&m_stckOut,sizeof(MMCKINFO)); - m_stckOut.ckid = mmioFOURCC('f', 'm', 't', ' '); - m_stckOut.cksize = sizeof(m_stWFEX); - mRes=mmioCreateChunk(m_hOPFile, &m_stckOut, 0); - if(mRes!=MMSYSERR_NOERROR) - { - FAIL_M("bad"); - } - int nT1=mmioWrite(m_hOPFile, (HPSTR) &m_stWFEX, sizeof(m_stWFEX)); - if(nT1!=sizeof(m_stWFEX)) - { - FAIL_M("bad"); - } - mRes=mmioAscend(m_hOPFile, &m_stckOut, 0); - if(mRes!=MMSYSERR_NOERROR) - { - FAIL_M("bad"); - } - m_stckOut.ckid = mmioFOURCC('d', 'a', 't', 'a'); - mRes=mmioCreateChunk(m_hOPFile, &m_stckOut, 0); - if(mRes!=MMSYSERR_NOERROR) - { - FAIL_M("bad"); - } - } - - void PrepareBuffers() - { - MMRESULT mRes=0; - - for(int nT1=0;nT1Trace("%d",pHdr->dwUser); - if(WHDR_DONE==(WHDR_DONE &pHdr->dwFlags)) - { - //LOG->Trace("Got %d bytes of data", pHdr->dwBytesRecorded ); - int iSampleCount = pHdr->dwBytesRecorded / sizeof(short); - m_dp.ReadOne( (short*)pHdr->lpData, iSampleCount ); - - mmioWrite(m_hOPFile,pHdr->lpData,pHdr->dwBytesRecorded); - MMRESULT mRes = waveInAddBuffer(m_hWaveIn,pHdr,sizeof(WAVEHDR)); - if(mRes!=0) - FAIL_M("bad"); - } - } - - void CloseDevice() - { - MMRESULT mRes=0; - - if(m_hWaveIn) - { - UnPrepareBuffers(); - mRes=waveInClose(m_hWaveIn); - } - if(m_hOPFile) - { - mRes=mmioAscend(m_hOPFile, &m_stckOut, 0); - if(mRes!=MMSYSERR_NOERROR) - { - FAIL_M("bad"); - } - mRes=mmioAscend(m_hOPFile, &m_stckOutRIFF, 0); - if(mRes!=MMSYSERR_NOERROR) - { - FAIL_M("bad"); - } - mmioClose(m_hOPFile,0); - m_hOPFile=NULL; - } - m_hWaveIn=NULL; - } - - void UnPrepareBuffers() - { - MMRESULT mRes=0; - - if(m_hWaveIn) - { - mRes=waveInStop(m_hWaveIn); - for(int nT1=0;nT1<3;++nT1) - { - if(m_stWHDR[nT1].lpData) - { - mRes=waveInUnprepareHeader(m_hWaveIn,&m_stWHDR[nT1],sizeof(WAVEHDR)); - HeapFree(GetProcessHeap(),0,m_stWHDR[nT1].lpData); - ZeroMemory(&m_stWHDR[nT1],sizeof(WAVEHDR)); - } - } - } - } - - void GetStatus( MicrophoneStatus &out ) - { - return m_dp.GetStatus( out ); - } -}; - -MicrophoneImpl *MicrophoneImpl::s_pMicrophoneImpl = NULL; - -void CALLBACK waveInProc(HWAVEIN hwi,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2) -{ - switch(uMsg) - { - case WIM_CLOSE: - break; - - case WIM_DATA: - { - MicrophoneImpl::s_pMicrophoneImpl->ProcessHeader( (WAVEHDR *)dwParam1 ); - } - break; - - case WIM_OPEN: - break; - - default: - break; - } -} - - -void PitchDetectionTest::Update() -{ - s_pMicrophone->GetStatus( s_ms ); -} - -void DoPitchDetectionTest() -{ - MicrophoneImpl mr; - mr.Init(); - mr.StartRecording(); - - //srpd2(); // do f0 tracking -} - - - -Microphone::Microphone() -{ - m_pImpl = new MicrophoneImpl; - m_pImpl->Init(); - m_pImpl->StartRecording(); -} -Microphone::~Microphone() -{ - m_pImpl->StopRecording(); - SAFE_DELETE( m_pImpl ); -} - -void Microphone::GetStatus( MicrophoneStatus &out ) -{ - m_pImpl->GetStatus( out ); - if( !FreqToMidiNote(out.fFreq, out.fMidiNote) ) - out.fMidiNote = 0; - int iMidiNote = (int)roundf( out.fMidiNote ); - if( !MidiNoteToStringAndOctave( iMidiNote, out.sMidiNote ) ) - out.sMidiNote = ""; -} - - -/* - * (c) 2007 Chris Danford - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +#include "global.h" +#include "PitchDetectionTest.h" +#include "PitchDetectionTestUtil.h" +#include "srpd.h" +#include "EST_filter.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "NoteTypes.h" +#include + +MicrophoneStatus PitchDetectionTest::s_ms; +Microphone *PitchDetectionTest::s_pMicrophone = NULL; + +#define MAX_BUFFERS 3 + +// http://tomscarff.tripod.com/midi_analyser/midi_note_frequency.htm +// http://musicdsp.org/showone.php?id=125 +const float MIDI_A4_FREQUENCY = 440.0; +const int MIDI_A4_NUMBER = 69; +const int MIDI_C4_NUMBER = 60; // middle C +const RString NOTE_NAME[MIDI_NOTES_PER_OCTAVE] = {"A ","A#","B ","C ","C#","D ","D#","E ","F ","F#","G ","G#"}; + +float MidiNoteToFreq( int iMidiNote ) +{ + return MIDI_A4_FREQUENCY * powf( 2.0, ((float)iMidiNote - MIDI_A4_NUMBER) / MIDI_NOTES_PER_OCTAVE ); +} + +float log2f( float n ) +{ + // logb (x) = (loga(x)) / (loga(B)) + return logf(n) / logf(2); +} + +bool FreqToMidiNote( float fFreq, float &fMidiNoteOut ) +{ + if( fFreq < 20 ) // well below A0 (MidiNote = 1) + return false; + fMidiNoteOut = MIDI_NOTES_PER_OCTAVE * log2f( fFreq / MIDI_A4_FREQUENCY) + MIDI_A4_NUMBER; + return fMidiNoteOut >= 1; +} + +#undef bool + +bool PitchDetectionTest::MidiNoteToString( int iMidiNote, RString &sMidiNoteOut ) +{ + if( iMidiNote < 1 ) + return false; + int iDiff = iMidiNote - MIDI_A4_NUMBER; + wrap( iDiff, MIDI_NOTES_PER_OCTAVE ); + sMidiNoteOut = NOTE_NAME[iDiff]; + return true; +} + +bool MidiNoteToOctave( int iMidiNote, int &iOctaveOut ) +{ + if( iMidiNote < 1 ) + return false; + // middle C is start of octave 4. + int iOctave = (int)floorf( ((float)iMidiNote - MIDI_C4_NUMBER) / MIDI_NOTES_PER_OCTAVE ); + iOctaveOut = iOctave + 4; + return true; +} + +bool MidiNoteToStringAndOctave( int iMidiNote, RString &sMidiNoteOut ) +{ + if( !PitchDetectionTest::MidiNoteToString(iMidiNote, sMidiNoteOut) ) + return false; + int iOctave; + if( !MidiNoteToOctave(iMidiNote, iOctave) ) + return false; + sMidiNoteOut += ssprintf("%d",iOctave); + return true; +} + +float PitchDetectionTest::WrapToNearestOctave( float fMidiNote, float fTargetMidiNote ) +{ + float fDiff = fMidiNote - fTargetMidiNote; + fDiff += MIDI_NOTES_PER_OCTAVE / 2; + wrap( fDiff, (float)MIDI_NOTES_PER_OCTAVE ); + fDiff -= MIDI_NOTES_PER_OCTAVE / 2; + float fRet = fTargetMidiNote + fDiff; + return fRet; +} + + +void CALLBACK waveInProc(HWAVEIN hwi,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2); + +class MicrophoneImpl +{ +public: + HWAVEIN m_hWaveIn; + WAVEFORMATEX m_stWFEX; + WAVEHDR m_stWHDR[MAX_BUFFERS]; + DetectPitch m_dp; + HMMIO m_hOPFile; + MMIOINFO m_stmmIF; + MMCKINFO m_stckOut,m_stckOutRIFF; + + static MicrophoneImpl *s_pMicrophoneImpl; // one and only for the callback function to use + + + void Init() + { + m_hWaveIn=NULL; + ZeroMemory(&m_stWFEX,sizeof(WAVEFORMATEX)); + ZeroMemory(m_stWHDR,MAX_BUFFERS*sizeof(WAVEHDR)); + s_pMicrophoneImpl = this; + } + + void FillDevices() + { + WAVEINCAPS stWIC={0}; + + UINT nDevices=waveInGetNumDevs(); + + for(UINT nC1=0;nC1Trace( stWIC.szPname ); + else + FAIL_M("bad"); + } + } + + void StartRecording() + { + OpenDevice(); + + m_dp.Init( SAMPLES_PER_SEC ); + + PrepareBuffers(); + MMRESULT mRes=waveInStart(m_hWaveIn); + if(mRes!=0) + FAIL_M("bad"); + } + + void StopRecording() + { + CloseDevice(); + } + + void OpenDevice() + { + MMRESULT mRes=0; + + m_stWFEX.nSamplesPerSec=SAMPLES_PER_SEC; + m_stWFEX.nChannels=1; + m_stWFEX.wBitsPerSample = 16; + m_stWFEX.wFormatTag=WAVE_FORMAT_PCM; + m_stWFEX.nBlockAlign=m_stWFEX.nChannels*m_stWFEX.wBitsPerSample/8; + m_stWFEX.nAvgBytesPerSec=m_stWFEX.nSamplesPerSec*m_stWFEX.nBlockAlign; + m_stWFEX.cbSize=sizeof(WAVEFORMATEX); + int device = 0; + + WAVEINCAPS stWIC={0}; + ZeroMemory(&stWIC,sizeof(WAVEINCAPS)); + mRes=waveInGetDevCaps(device,&stWIC,sizeof(WAVEINCAPS)); + if(mRes==0) + LOG->Trace( stWIC.szPname ); + else + FAIL_M("bad"); + + + mRes=waveInOpen(&m_hWaveIn,device,&m_stWFEX,(DWORD_PTR)waveInProc,(DWORD_PTR)this,CALLBACK_FUNCTION); + if(mRes!=MMSYSERR_NOERROR) + FAIL_M("bad"); + + + + const char *csT1 = "C:\\cvs\\stepmania\\speech-test.wav"; + ZeroMemory(&m_stmmIF,sizeof(MMIOINFO)); + DeleteFile((PCHAR)(LPCTSTR)csT1); + m_hOPFile=mmioOpen((PCHAR)(LPCTSTR)csT1,&m_stmmIF,MMIO_WRITE | MMIO_CREATE); + if(m_hOPFile==NULL) + FAIL_M("Can not open file..."); + + ZeroMemory(&m_stckOutRIFF,sizeof(MMCKINFO)); + m_stckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); + mRes=mmioCreateChunk(m_hOPFile, &m_stckOutRIFF, MMIO_CREATERIFF); + if(mRes!=MMSYSERR_NOERROR) + { + FAIL_M("bad"); + } + ZeroMemory(&m_stckOut,sizeof(MMCKINFO)); + m_stckOut.ckid = mmioFOURCC('f', 'm', 't', ' '); + m_stckOut.cksize = sizeof(m_stWFEX); + mRes=mmioCreateChunk(m_hOPFile, &m_stckOut, 0); + if(mRes!=MMSYSERR_NOERROR) + { + FAIL_M("bad"); + } + int nT1=mmioWrite(m_hOPFile, (HPSTR) &m_stWFEX, sizeof(m_stWFEX)); + if(nT1!=sizeof(m_stWFEX)) + { + FAIL_M("bad"); + } + mRes=mmioAscend(m_hOPFile, &m_stckOut, 0); + if(mRes!=MMSYSERR_NOERROR) + { + FAIL_M("bad"); + } + m_stckOut.ckid = mmioFOURCC('d', 'a', 't', 'a'); + mRes=mmioCreateChunk(m_hOPFile, &m_stckOut, 0); + if(mRes!=MMSYSERR_NOERROR) + { + FAIL_M("bad"); + } + } + + void PrepareBuffers() + { + MMRESULT mRes=0; + + for(int nT1=0;nT1Trace("%d",pHdr->dwUser); + if(WHDR_DONE==(WHDR_DONE &pHdr->dwFlags)) + { + //LOG->Trace("Got %d bytes of data", pHdr->dwBytesRecorded ); + int iSampleCount = pHdr->dwBytesRecorded / sizeof(short); + m_dp.ReadOne( (short*)pHdr->lpData, iSampleCount ); + + mmioWrite(m_hOPFile,pHdr->lpData,pHdr->dwBytesRecorded); + MMRESULT mRes = waveInAddBuffer(m_hWaveIn,pHdr,sizeof(WAVEHDR)); + if(mRes!=0) + FAIL_M("bad"); + } + } + + void CloseDevice() + { + MMRESULT mRes=0; + + if(m_hWaveIn) + { + UnPrepareBuffers(); + mRes=waveInClose(m_hWaveIn); + } + if(m_hOPFile) + { + mRes=mmioAscend(m_hOPFile, &m_stckOut, 0); + if(mRes!=MMSYSERR_NOERROR) + { + FAIL_M("bad"); + } + mRes=mmioAscend(m_hOPFile, &m_stckOutRIFF, 0); + if(mRes!=MMSYSERR_NOERROR) + { + FAIL_M("bad"); + } + mmioClose(m_hOPFile,0); + m_hOPFile=NULL; + } + m_hWaveIn=NULL; + } + + void UnPrepareBuffers() + { + MMRESULT mRes=0; + + if(m_hWaveIn) + { + mRes=waveInStop(m_hWaveIn); + for(int nT1=0;nT1<3;++nT1) + { + if(m_stWHDR[nT1].lpData) + { + mRes=waveInUnprepareHeader(m_hWaveIn,&m_stWHDR[nT1],sizeof(WAVEHDR)); + HeapFree(GetProcessHeap(),0,m_stWHDR[nT1].lpData); + ZeroMemory(&m_stWHDR[nT1],sizeof(WAVEHDR)); + } + } + } + } + + void GetStatus( MicrophoneStatus &out ) + { + return m_dp.GetStatus( out ); + } +}; + +MicrophoneImpl *MicrophoneImpl::s_pMicrophoneImpl = NULL; + +void CALLBACK waveInProc(HWAVEIN hwi,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2) +{ + switch(uMsg) + { + case WIM_CLOSE: + break; + + case WIM_DATA: + { + MicrophoneImpl::s_pMicrophoneImpl->ProcessHeader( (WAVEHDR *)dwParam1 ); + } + break; + + case WIM_OPEN: + break; + + default: + break; + } +} + + +void PitchDetectionTest::Update() +{ + s_pMicrophone->GetStatus( s_ms ); +} + +void DoPitchDetectionTest() +{ + MicrophoneImpl mr; + mr.Init(); + mr.StartRecording(); + + //srpd2(); // do f0 tracking +} + + + +Microphone::Microphone() +{ + m_pImpl = new MicrophoneImpl; + m_pImpl->Init(); + m_pImpl->StartRecording(); +} +Microphone::~Microphone() +{ + m_pImpl->StopRecording(); + SAFE_DELETE( m_pImpl ); +} + +void Microphone::GetStatus( MicrophoneStatus &out ) +{ + m_pImpl->GetStatus( out ); + if( !FreqToMidiNote(out.fFreq, out.fMidiNote) ) + out.fMidiNote = 0; + int iMidiNote = (int)roundf( out.fMidiNote ); + if( !MidiNoteToStringAndOctave( iMidiNote, out.sMidiNote ) ) + out.sMidiNote = ""; +} + + +/* + * (c) 2007 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/src/PitchDetectionTest.h b/stepmania/src/PitchDetectionTest.h index 54836f669b..9a32ec3d69 100644 --- a/stepmania/src/PitchDetectionTest.h +++ b/stepmania/src/PitchDetectionTest.h @@ -1,62 +1,62 @@ -/* Microphone - */ - -#ifndef Microphone_H -#define Microphone_H - -class MicrophoneImpl; - -struct MicrophoneStatus -{ - float fFreq; - float fMaxFreq; - bool bVoiced; - float fMidiNote; - RString sMidiNote; -}; - -class Microphone -{ -public: - Microphone(); - ~Microphone(); - void GetStatus( MicrophoneStatus &out ); -protected: - MicrophoneImpl *m_pImpl; -}; - -class PitchDetectionTest -{ -public: - static MicrophoneStatus s_ms; - static Microphone *s_pMicrophone; - static void Update(); - static bool MidiNoteToString( int iMidiNote, RString &sMidiNoteOut ); - static float WrapToNearestOctave( float fMidiNote, float fTargetMidiNote ); -}; - -#endif - -/* - * (c) 2004 Chris Danford - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +/* Microphone - */ + +#ifndef Microphone_H +#define Microphone_H + +class MicrophoneImpl; + +struct MicrophoneStatus +{ + float fFreq; + float fMaxFreq; + bool bVoiced; + float fMidiNote; + RString sMidiNote; +}; + +class Microphone +{ +public: + Microphone(); + ~Microphone(); + void GetStatus( MicrophoneStatus &out ); +protected: + MicrophoneImpl *m_pImpl; +}; + +class PitchDetectionTest +{ +public: + static MicrophoneStatus s_ms; + static Microphone *s_pMicrophone; + static void Update(); + static bool MidiNoteToString( int iMidiNote, RString &sMidiNoteOut ); + static float WrapToNearestOctave( float fMidiNote, float fTargetMidiNote ); +}; + +#endif + +/* + * (c) 2004 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/src/PitchDetectionTestUtil.cpp b/stepmania/src/PitchDetectionTestUtil.cpp index 523659e57f..0abb27d6cf 100644 --- a/stepmania/src/PitchDetectionTestUtil.cpp +++ b/stepmania/src/PitchDetectionTestUtil.cpp @@ -27,3359 +27,3359 @@ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ - /*************************************************************************/ + /*************************************************************************/ /* Author : Paul Taylor */ /* Date : April 1994 */ /*************************************************************************/ - -#include "global.h" -#include "RageUtil.h" -#include "RageLog.h" -#include "RageSoundReader_WAV.h" -#include "RageSurface_Load.h" -#include "PitchDetectionTestUtil.h" -#include "EST_String.h" -#include "EST_Chunk.h" -#include "EST_Val.h" -#include "EST_Features.h" -#include "EST_Token.h" -#include "EST_Option.h" -#include "EST_Track.h" -#include "PitchDetectionTest.h" - -// EST Library: http://www.cstr.ed.ac.uk/projects/speech_tools/ -// "pda" executable options: http://festvox.org/docs/speech_tools-1.2.0/x2152.htm -// Autocorrelation explanation: http://cnx.org/content/m11714/latest/ -// PDA algorithm tradeoffs: http://www-scf.usc.edu/~chinghuc/pitch_detection_algorithms.htm -// MIDI note numbers: http://tomscarff.tripod.com/midi_analyser/midi_note_frequency.htm -// MIDI note numbers: http://www.sengpielaudio.com/calculator-notenames.htm - -EST_String::EST_String(const char *s) -{ - CHECK_STRING_ARG(s); - - size=safe_strlen(s); - - if (size != 0) - memory = chunk_allocate(size+1, s, size); - else - memory=NULL; -} - -void EST_Chunk::operator delete (void *it) -{ - -#if defined(__CHUNK_USE_WALLOC__) - wfree(it); -#else - delete it; -#endif - -} - -val_type val_unset = "unset"; -val_type val_int = "int"; -val_type val_float = "float"; -val_type val_string = "string"; - -#define VAL_REGISTER_CLASS_DCLS(NAME,CLASS) \ -extern val_type val_type_##NAME; \ -class CLASS *NAME(const EST_Val &v); \ -EST_Val est_val(const class CLASS *v); - -VAL_REGISTER_CLASS_DCLS(feats,EST_Features) - - -#define VAL_REGISTER_CLASS(NAME,CLASS) \ -val_type val_type_##NAME=#NAME; \ -class CLASS *NAME(const EST_Val &v) \ -{ \ - if (v.type() == val_type_##NAME) \ - return (class CLASS *)v.internal_ptr(); \ - else \ - exit(1); /*EST_error("val not of type val_type_"#NAME);*/ \ - return NULL; \ -} \ - \ -static void val_delete_##NAME(void *v) \ -{ \ - delete (class CLASS *)v; \ -} \ - \ -EST_Val est_val(const class CLASS *v) \ -{ \ - return EST_Val(val_type_##NAME, \ - (void *)v,val_delete_##NAME); \ -} \ - -VAL_REGISTER_CLASS(feats,EST_Features) - - -EST_Val::~EST_Val(void) -{ - if ((t != val_int) && - (t != val_float) && - (t != val_unset) && - (t != val_string)) - delete v.pval; -} - - -EST_Chunk::~EST_Chunk () -{ - if (count > 0) - { - //cerr << "deleting chunk with non-zero count\n"; - exit(1); - } - // cerr << "deleted "<< hex << (int)&memory << "," << dec << size <<"\n"; -} - -void EST_Features::set_path(const EST_String &name, const EST_Val &sval) -{ - // Builds sub features (if necessary) - - if (strchr(name,'.') == NULL) - set_val(name,sval); - else - { - EST_String nname = name; - EST_String fname = nname.before("."); - if (present(fname)) - { - const EST_Val &v = val(fname); - if (v.type() == val_type_feats) - feats(v)->set_path(nname.after("."),sval); - else - exit(1);//EST_error("Feature %s not feature valued\n", - // (const char *)fname); - } - else - { - EST_Features f; - set(fname,f); - A(fname).set_path(nname.after("."),sval); - } - } -} - - - -template -V &EST_TKVL::val(const K &rkey, int must) -{ - EST_Litem *ptr = find_pair_key(rkey); - - if (ptr == 0) - { - if (must) - EST_error("No value set for '%s'", error_name(rkey)); - - return *default_val; - } - else - return list.item(ptr).v; -} - -EST_String &EST_TKVL::val(const EST_String &rkey, int must) -{ - EST_Litem *ptr = find_pair_key(rkey); - - if (ptr == 0) - { - if (must) - exit(1);//EST_error("No value set for '%s'", error_name(rkey)); - - return *default_val; - } - else - return list.item(ptr).v; -} - - -template -int EST_TKVL::add_item(const K &rkey, const V &rval, int no_search) -{ - if (!no_search) - if (change_val(rkey, rval)) // first see if key exists - return 1; - - EST_TKVI item; - item.k = rkey; - item.v = rval; - - list.append(item); - return 1; -} - -int EST_TKVL::add_item(const EST_String &rkey, const EST_String &rval, int no_search) -{ - if (!no_search) - if (change_val(rkey, rval)) // first see if key exists - return 1; - - EST_TKVI item; - item.k = rkey; - item.v = rval; - - list.append(item); - return 1; -} - -template -const int EST_TKVL::present(const K &rkey) const -{ - if (find_pair_key(rkey) == 0) - return 0; - else - return 1; -} - -const int EST_TKVL::present(const EST_String &rkey) const -{ - if (find_pair_key(rkey) == 0) - return 0; - else - return 1; -} - - -static const EST_String Empty_String(""); - - -int EST_Option::ival(const EST_String &rkey, int must) const -{ - const EST_String &tval = val_def(rkey, Empty_String); - if (tval != "") - return atoi(tval); - - if (must) - exit(1);//cerr << "EST_Option: No value set for " << rkey << endl; - return 0; -} - -EST_String &EST_String::operator = (const char *str) -{ - CHECK_STRING_ARG(str); - int len = safe_strlen(str); - if (!len) - memory = NULL; - else if (!shareing() && len < size) - memcpy((char *)memory, str, len+1); - else if (len) - memory = chunk_allocate(len+1, str, len); - size=len; - return *this; -} - -EST_String &EST_String::operator = (const char c) -{ - memory = chunk_allocate(2, &c, 1); - size=1; - return *this; -} - -EST_String &EST_String::operator = (const EST_String &s) -{ -#if 1 - static EST_ChunkPtr hack = s.memory; - memory = NON_CONST_CHUNKPTR(s.memory); - size = s.size; -#else - *(struct EST_dumb_string *)this = *(struct EST_dumb_string *)(&s); -#endif - return *this; -} - -int operator == (const char *a, const EST_String &b) -{ - CHECK_STRING_ARG(a); - - if (!a) - return 0; - else if (b.size==0) - return *a == '\0'; - else - return (*a == b(0)) && strcmp(a, b.str())==0; -} - -const EST_Val &EST_Features::val_path(const EST_String &name, const EST_Val &d) const -{ - // For when name contains references to sub-features - - if (strchr(name,'.') == NULL) - return val(name, d); - else - { - EST_String nname = name; - EST_String fname = nname.before("."); - const EST_Val &v = val(fname, d); - if (v.type() == val_type_feats) - return feats(v)->val_path(nname.after("."), d); - else - return d; - } -} - -EST_String itoString(int n) -{ - char tmp[1000]; - - sprintf(tmp, "%d", n); - return EST_String(tmp); -} - -EST_String ftoString(float n, int pres=3, int width=0, int right_justify=0) -{ - (void)right_justify; - EST_String val; - char tmp[1000]; - char spec[10]; - strcpy(spec, "%"); - if (width != 0) - strcat(spec, itoString(width)); - strcat(spec, "."); - strcat(spec, itoString(pres)); - strcat(spec, "f"); - - sprintf(tmp, spec, n); - val = tmp; - return val; -} - - -const EST_String &EST_Val::to_str(void) const -{ - // coerce this to and save it for later - // This requires the following casting, so we can still tell the - // compiler this is a const function. If this was properly declared - // non-const vast amounts of the rest of this would also have to be - // non-const. So we do one nasty bit here for uniformity elsewhere. - // Not saving the result is also a possibility but probably too - // inefficient (maybe not with rjc's string class) - EST_String *n = (EST_String *)((void *)&sval); - if (t==val_int) - *n = itoString(v.ival); - else if (t==val_float) - { - if (v.fval == 0) - *n = "0"; // to be compatible with other's notion of fstrings - else - *n = ftoString(v.fval); - } - else if (t != val_string) - *n = EST_String("[Val ")+t+"]"; - - return sval; -} - -int EST_Features::present(const EST_String &name) const -{ - if (strchr(name,'.') == NULL) - return features->present(name); - EST_String nname = name; - if (features->present(nname.before("."))) - { - const EST_Val &v = val(nname.before(".")); - if (v.type() == val_type_feats) - return feats(v)->present(nname.after(".")); - else - return FALSE; - } - else - return FALSE; -} - -const EST_Val &EST_Features::val_path(const EST_String &name) const -{ - // For when name contains references to sub-features - - if (strchr(name,'.') == NULL) - return val(name); - else - { - EST_String nname = name; - EST_String fname = nname.before("."); - const EST_Val &v = val(fname); - if (v.type() == val_type_feats) - return feats(v)->val_path(nname.after(".")); - else - exit(1);//EST_error("Feature %s not feature valued\n", (const char *)fname); - return feature_default_value; // wont get here - } -} - -EST_Track::~EST_Track(void) -{ - // clear_features(); -} - -void EST_Track::default_channel_names() -{ - for (int i = 0; i < num_channels(); ++i) - set_channel_name("track" + itoString(i), i); -} - -EST_Track::EST_Track() -{ - default_vals(); -} - -int fastlog2(int n) { - int num_bits, power = 0; - - if ((n < 2) || (n % 2 != 0)) return(0); - num_bits = sizeof(int) * 8; /* How big are ints on this machine? */ - - while(power <= num_bits) { - n >>= 1; - power += 1; - if (n & 0x01) { - if (n > 1) return(0); - else return(power); - } - } - return(0); -} - -#define PI 3.14159265358979323846 - -static int slowFFTsub(EST_FVector &real, EST_FVector &imag, float f) -{ - // f = -1 for FFT, 1 for IFFT - // would be nicer if we used a complex number class, - // but we don't, so it isn't - - // taken from the FORTRAN old chestnut - // in various sig proc books - // FORTRAN uses 1..n arrays, so subtract 1 all over the place - - - float u_real,u_imag; - float w_real,w_imag; - float t_real,t_imag; - float tmp_real,tmp_imag; - - int M,N; - int i,j,k,l; - - M = fastlog2(real.n()); - N = (int)powf(2,(float)M); - - if (N != real.n()) - { - exit(1);//EST_warning("Illegal FFT order %d", real.n()); - return -1; - } - - for(l=1;l<=M;l++){ - - int le = (int)powf(2,(float)(M+1-l)); - int le1=le/2; - - u_real = 1.0; - u_imag = 0.0; - - w_real=cos(PI/le1); - w_imag=f * sin(PI/le1); - - for (j=1;j<=le1;j++) - { - for (i=j;i<=N-le1;i+=le) - { - int ip=i+le1; - t_real = real.a_no_check(i-1) + real.a_no_check(ip-1); - t_imag = imag.a_no_check(i-1) + imag.a_no_check(ip-1); - - tmp_real = real.a_no_check(i-1) - real.a_no_check(ip-1); - tmp_imag = imag.a_no_check(i-1) - imag.a_no_check(ip-1); - - real.a_no_check(ip-1) = tmp_real*u_real - tmp_imag*u_imag; - imag.a_no_check(ip-1) = tmp_real*u_imag + tmp_imag*u_real; - - real.a_no_check(i-1) = t_real; - imag.a_no_check(i-1) = t_imag; - } - - tmp_real = u_real*w_real - u_imag*w_imag; - tmp_imag = u_real*w_imag + u_imag*w_real; - - u_real=tmp_real; - u_imag=tmp_imag; - - } - - } - - - int NV2=N/2; - int NM1=N-1; - j=1; - - - for (i=1; i<=NM1;i++) - { - if (i < j) - { - t_real=real(j-1); - t_imag=imag(j-1); - - real[j-1] = real(i-1); - imag[j-1] = imag(i-1); - - real[i-1] = t_real; - imag[i-1] = t_imag; - - } - - k=NV2; - - while(k < j) - { - j=j-k; - k=k/2; - } - - j=j+k; - - } - - return 0; -} - -int slowIFFT(EST_FVector &real, EST_FVector &imag) -{ - int N=real.n(); - if (N <=0 ) - return -1; - - if (slowFFTsub(real,imag,1.0) != 0) - return -1; - - for(int i=1;i<=N;i++){ - real[i-1] /= (float)N; - imag[i-1] /= (float)N; - } - - return 0; -} - - -EST_FVector design_FIR_filter(const EST_FVector &frequency_response, - int filter_order) -{ - // frequency_response contains the desired filter reponse, - // on a scale 0...sampling frequency - - // check filter_order is odd - if((filter_order & 1) == 0){ - cerr << "Requested filter order must be odd" << endl; - return EST_FVector(0); - } - - // check frequency_response has dimension 2^N - int N = fastlog2(frequency_response.n()); - if(frequency_response.n() != (int)powf(2,(float)N)){ - cerr << "Desired frequency response must have dimension 2^N" << endl; - return EST_FVector(0); - } - - int i; - EST_FVector filt(frequency_response); - EST_FVector dummy(frequency_response.n()); - for(i=0;ismooth_double = FALSE; - ms->apply_hanning = TRUE; - ms->extrapolate = TRUE; - ms->first_median = 11; - ms->second_median = 1; - ms->window_length = 7; - ms->breaker = -1.0; - return (ms); -} - -int parse_ms_list(EST_Features &al, struct Ms_Op *ms) -{ - default_ms_op(ms); - - if (al.present("smooth_double")) - ms->smooth_double = al.I("smooth_double"); - if (al.present( "hanning")) - ms->apply_hanning = al.I("hanning"); - if (al.present("extrapolate")) - ms->extrapolate = al.I("extrapolate"); - if (al.present("first_length")) - ms->first_median = al.I("first_length"); - if (al.present("second_length")) - ms->second_median = al.I("second_length"); - if (al.present("window_length")) - ms->window_length = al.I("window_length"); - - return 0; -} - -#define MAX_LEN 127 - -#define TWO_PI 6.28318530717958647698 - -void mk_window_coeffs (int length, float win_coeff[]) -{ - int i; - double x; - - for (i = 0; i < length; i++) { - x = TWO_PI * (i + 1.0) / (length + 1.0); - win_coeff[i] = (1.0 - (float) cos (x)) / (length + 1.0); - } - -} - -float median (int *counter, float valin, float valbuf[], int lmed, int mmed) -{ - int i, j; - float tmp, filmed[MAX_LEN]; - - for (i = lmed - 1; i > 0; i--) - valbuf[i] = valbuf[i - 1]; - valbuf[0] = valin; - - if (*counter > 0) - { - (*counter)--; - return (0.0); - } - else - { - *counter = -1; - - for (i = 0; i < lmed; i++) - filmed[i] = valbuf[i]; - - for (j = lmed - 1; j > 0; j--) - for (i = 0; i < j; i++) - if (filmed[i] > filmed[i + 1]) - { - tmp = filmed[i + 1]; - filmed[i + 1] = filmed[i]; - filmed[i] = tmp; - } - return (filmed[mmed]); - } - -} - -float hanning (int *counter, float valin, float valhan[], float win_coeff[], - struct Ms_Op *par) -{ - int i, j, k = 0; - float valout = 0.0, weight[MAX_LEN]; - - for (i = par->window_length - 1; i > 0; i--) - valhan[i] = valhan[i - 1]; - valhan[0] = valin; - if (*counter > 0) { - (*counter)--; - return (0.0); - } - else { - *counter = -1; - for (i = 0; i < par->window_length; i++) - if (valhan[i] == par->breaker) - k++; - if (!k) - for (i = 0; i < par->window_length; i++) - valout += valhan[i] * win_coeff[i]; - else if (k <= par->window_length / 2 && par->extrapolate) { - mk_window_coeffs (par->window_length - k, weight); - for (i = 0, j = 0; i < par->window_length; i++) - if (valhan[i] != par->breaker) - valout += valhan[i] * weight[j++]; - } - else - valout = par->breaker; - return (valout); - } - -} - - -void array_smoother (float *p_array, int arraylen, struct Ms_Op *ms) -{ - int i, j, mid1, mid2 = 0, filler, nloops; - int C1, C2 = 0, C3 = 0, C4 = 0, c1, c2, c3, c4; - int delay, delx = 0, dely = 0; - int in = 0, out = 0; - float input, output; - float *inarray; - float xdel[2 * MAX_LEN - 2], ydel[2 * MAX_LEN - 2]; - float medbuf1[MAX_LEN], medbuf2[MAX_LEN]; - float hanbuf1[MAX_LEN], hanbuf2[MAX_LEN], win_coeffs[MAX_LEN]; - float medval1, medval2, hanval1, hanval2, zatn; - - inarray = new float[arraylen]; - for (i = 0; i < arraylen; ++i) - inarray[i] = p_array[i]; - - if (ms == NULL) - { - ms = new Ms_Op; - default_ms_op(ms); - } - - mk_window_coeffs (ms->window_length, win_coeffs); - /* determine the size and delay of each stage concerned */ - mid1 = ms->first_median / 2; - C1 = delay = ms->first_median - 1; - if (ms->apply_hanning) - { - C2 = ms->window_length - 1; - delay = ms->first_median + ms->window_length - 2; - } - if (ms->smooth_double) { - mid2 = ms->second_median / 2; - C3 = ms->second_median - 1; - if (!ms->apply_hanning) { - delx = ms->first_median; - dely = ms->second_median; - } - else { - C4 = ms->window_length - 1; - delx = ms->first_median + ms->window_length - 1; - dely = ms->second_median + ms->window_length - 1; - } - delay = delx + dely - 2; - } - /* prepare for smoothing */ - c1 = C1; - c2 = C2; - c3 = C3; - c4 = C4; - if (!ms->extrapolate) { - /* pad with breakers at the beginning */ - for (i = 0; i < delay / 2; i++) - p_array[out++] = ms->breaker; - filler = 0; - nloops = arraylen; - } - else { - /* extrapolate by initialising filter with dummy breakers */ - filler = delay / 2; - nloops = arraylen + delay; - } - /* smooth track element by track element */ - for (j = 0; j < nloops; j++) - { - if (j < filler || j >= nloops - filler) - input = ms->breaker; - else - input = inarray[in++]; - - /* store input value if double smoothing */ - if (ms->smooth_double) { - for (i = delx - 1; i > 0; i--) - xdel[i] = xdel[i - 1]; - xdel[0] = input; - } - /* first median smoothing */ - - medval1 = median (&c1, input, medbuf1, ms->first_median, mid1); - - if (c1 == -1) - { - output = medval1; - /* first hanning window (optional) */ - if (ms->apply_hanning) - { - hanval1 = hanning (&c2, medval1, hanbuf1, win_coeffs, ms); - if (c2 == -1) - output = hanval1; - else - continue; - } - /* procedures for double smoothing (optional) */ - if (ms->smooth_double) - { - /* compute rough component z(n) */ - if (output != ms->breaker && xdel[delx - 1] - != ms->breaker) - zatn = xdel[delx - 1] - output; - else - zatn = ms->breaker; - /* store results of first smoothing */ - for (i = dely - 1; i > 0; i--) - ydel[i] = ydel[i - 1]; - ydel[0] = output; - /* second median smoothing */ - medval2 = median (&c3, zatn, medbuf2, - ms->second_median, mid2); - if (c3 == -1) - { - output = medval2; - /* second hanning smoothing (optional) */ - if (ms->apply_hanning) { - hanval2 = hanning (&c4, medval2, hanbuf2, - win_coeffs, ms); - if (c4 == -1) - output = hanval2; - else - continue; - } - if (output != ms->breaker && ydel[dely - 1] - != ms->breaker) - output += ydel[dely - 1]; - else - output = ms->breaker; - } - else - continue; - } - /* write filtered result */ - p_array[out++] = output; - } - } - if (!ms->extrapolate) /* pad with breakers at the end */ - for (i = 0; i < delay / 2; i++) - p_array[out++] = ms->breaker; - - delete inarray; -} - -void smooth_portion(EST_Track &c, EST_Features &op) -{ - int i; - float *a; // need float * so it can be passed to array_smoother - struct Ms_Op *ms; - ms = new Ms_Op; - - default_ms_op(ms); - parse_ms_list(op, ms); - - if (op.present("point_window_size")) - ms->window_length = op.I("point_window_size"); - - a = new float[c.num_frames()]; - - for (i = 0; i < c.num_frames(); ++i) - a[i] = c.track_break(i) ? -1.0 : c.a(i); - - array_smoother(a, c.num_frames(), ms); - - for (i = 0; i < c.num_frames(); ++i) - { // occasionally NaNs result... - if (isnanf(a[i])) - { - c.set_break(i); - c.a(i) = 0.0; - } - else - { - if (a[i] < 0.0) - c.set_break(i); - else - c.set_value(i); - c.a(i) = a[i]; - } - } - - delete a; -} - -static void interp(const EST_Track &c, const EST_Track &speech, int fill, - EST_Track &interp) -{ - // Interpolate between unvoiced sections, and ensure breaks - // during silences - int i, n, p; - float m; - float n_val, p_val; - float f = c.shift(); - - interp = c; // copy track - - if (speech.num_frames() < c.num_frames()) - interp.resize(speech.num_frames(), interp.num_channels()); - - - for (i = 1; i < interp.num_frames(); ++i) - { - if ((fill == 1) || (speech.a(i) > 0.5)) - { - if (!interp.track_break(i)) - continue; // already has a value - - p = i - 1; - if ((n = interp.next_non_break(i)) == 0) - n = interp.num_frames() - 1; - n_val = interp.a(n); - p_val = interp.a(p); - if (n_val <= 0) n_val = p_val; - if (p_val <= 0) p_val = n_val; - // if they are both zero, well we'll learn to live it. - m = (n_val - p_val) / ( interp.t(n) - interp.t(p)); - - interp.a(i) = (m * f) + p_val; - interp.set_value(i); - } - else - interp.set_break(i); - } -} - -void smooth_phrase(EST_Track &fz, EST_Track &speech, EST_Features &op, - EST_Track &smi_fz) -{ - int n=0; - EST_Track sm_fz; - char nstring[10]; - - if (fz.empty()) - { - smi_fz = fz; - return; - } - sm_fz = fz; - sm_fz.set_channel_name("F0", 0); - - n = (int)(op.F("window_length") / fz.shift()); - sprintf(nstring, "%d", n); - op.set("point_window_size", nstring); - - if (!op.present("icda_no_smooth")) - smooth_portion(sm_fz, op); - - if (op.present("icda_no_interp")) - { - sm_fz = fz; - return; // no unvoiced interpolation - } - - int fill = op.present("icda_fi") ? 1 : 0; - interp(sm_fz, speech, fill, smi_fz); // fill unvoiced region - - n = (int)(op.F("second_length") / fz.shift()); - sprintf(nstring, "%d", n); - op.set("point_window_size", nstring); - - if (!op.present("icda_no_smooth")) - smooth_portion(smi_fz, op); -} - -const int EST_Val::to_int(void) const -{ - // coerce this to an int - if (t==val_float) - return (int)v.fval; - else if (t==val_string) - return atoi(sval); - else - return v.ival; // just for completeness -} - -struct SEGMENT_ -{ /* segment of speech data */ - int size, shift, length; /* in samples */ - short *data; -}; - -struct CROSS_CORR_ -{ - int size; - double *coeff; -}; - - -void end_structure_use(SEGMENT_ *p_seg, CROSS_CORR_ *p_cc) -{ - - wfree (p_seg->data); - wfree (p_cc->coeff); - return; - -} - -static bool bounds_check(const EST_Track &t, int f, int c, int set) -{ - const char *what = set? "set" : "access"; - - if (f<0 || f >= t.num_frames()) - { - cerr << "Attempt to " << what << " frame " << f << " of " << t.num_frames() << " frame track\n"; - return FALSE; - } - if (c<0 || c >= t.num_channels()) - { - cerr << "Attempt to " << what << " channel " << c << " of " << t.num_channels() << " channel track\n"; - return FALSE; - } - -return TRUE; -} - - -float &EST_Track::a(int i, int c) -{ - if (!bounds_check(*this, i,c,0)) - return *(p_values.error_return); - - return p_values.a_no_check(i,c); -} - -EST_ChunkPtr chunk_allocate(int bytes, const char *initial, int initial_len) -{ - if (initial_len >= bytes) - { - cerr<<"initialiser too long\n"; - abort(); - } - - EST_Chunk *cp = new(bytes) EST_Chunk; - - memcpy(cp->memory, initial, initial_len); - - cp->memory[initial_len] = '\0'; - - return (EST_ChunkPtr)cp; -} - -void wfree(void *p) -{ - if (p != NULL) - free(p); -} - -EST_Features::EST_Features() -{ - features = new EST_TKVL; -} - -EST_Features::~EST_Features() -{ - if (features != NULL) - { - delete features; - features=NULL; - } -} - -const EST_Val &EST_Features::val(const char *name) const -{ - // Because so many access are from char* literals we all access - // directly rather than requiring the creation of an EST_String - EST_Litem *p; - - for (p=features->list.head(); p; p=next(p)) - { - if (features->list(p).k == name) - return features->list(p).v; - } - - exit(1);//EST_error("{FND} Feature %s not defined\n", name); - return feature_default_value; -} - -EST_String EST_String::chop_internal(const char *it, int len, int from, EST_chop_direction mode) const -{ - CHECK_STRING_ARG(it); - - int start, end; - - if (it && locate(it, len, from, start, end)) - switch (mode) - { - case Chop_Before: - return EST_String(str(), size, 0, start); break; - case Chop_At: - return EST_String(str(), size, start, end-start); break; - case Chop_After: - return EST_String(str(), size, end, -1); - } - return EST_String(); - -} - -EST_Val::EST_Val(val_type type,void *p, void (*f)(void *)) -{ - t=type; - v.pval = new EST_Contents; - v.pval->set_contents(p,f); -} - -EST_Features::EST_Features(const EST_Features &f) -{ - features = new EST_TKVL; - *features = *f.features; -} - -void EST_TokenStream::close(void) -{ - // close any files (if they were used) - - switch (type) - { - case tst_none: - break; - case tst_file: - if (close_at_end) - fclose(fp); - case tst_pipe: - // close(fd); - break; - case tst_istream: - break; - case tst_string: - delete [] buffer; - buffer = 0; - break; - default: - cerr << "EST_TokenStream: unknown type" << endl; - break; - } - - type = tst_none; - peeked_charp = FALSE; - peeked_tokp = FALSE; - -} - -EST_TokenStream::~EST_TokenStream() -{ - if (type != tst_none) - close(); - delete [] tok_wspace; - delete [] tok_stuff; - delete [] tok_prepuncs; - -} - -int EST_TokenStream::open(const EST_String &filename) -{ - if (type != tst_none) - close(); - default_values(); - fp = fopen(filename,"rb"); - if (fp == NULL) - { - exit(1);//cerr << "Cannot open file " << filename << " as tokenstream" - // << endl; - return -1; - } - Origin = filename; - type = tst_file; - - return 0; -} - -const EST_String Token_Origin_FD = "existing file descriptor"; - -int EST_TokenStream::open(FILE *ofp, int close_when_finished) -{ - // absorb already open stream - if (type != tst_none) - close(); - default_values(); - fp = ofp; - if (fp == NULL) - { - cerr << "Cannot absorb NULL filestream as tokenstream" << endl; - return -1; - } - Origin = Token_Origin_FD; - type = tst_file; - - close_at_end = close_when_finished; - - return 0; -} - -EST_TokenStream::EST_TokenStream() -{ - tok_wspacelen = 64; // will grow if necessary - tok_wspace = new char[tok_wspacelen]; - tok_stufflen = 512; // will grow if necessary - tok_stuff = new char[tok_stufflen]; - tok_prepuncslen = 32; // will grow if necessary - tok_prepuncs = new char[tok_prepuncslen]; - - default_values(); -} - - - - - - - - - - - -#define Instantiate_KVL_T(KEY, VAL, TAG) \ - template class EST_TKVL; \ - template class EST_TKVI; \ - ostream &operator<<(ostream &s, EST_TKVI< KEY , VAL > const &i){ return s << i.k << "\t" << i.v << "\n"; } \ - ostream& operator << (ostream& s, EST_TKVL< KEY , VAL > const &l) {EST_Litem *p; for (p = l.list.head(); p ; p = next(p)) s << l.list(p).k << "\t" << l.list(p).v << endl; return s;} \ - Instantiate_TIterator_T(KVL_ ## TAG ## _t, KVL_ ## TAG ## _t::IPointer_k, KEY, KVL_ ## TAG ##_kitt) \ - Instantiate_TStructIterator_T(KVL_ ## TAG ## _t, KVL_ ## TAG ## _t::IPointer, KVI_ ## TAG ## _t, KVL_ ## TAG ##_itt) \ - Instantiate_TIterator_T(KVL_ ## TAG ## _t, KVL_ ## TAG ## _t::IPointer, KVI_ ## TAG ## _t, KVL_ ## TAG ##_itt) \ - Instantiate_TList(KVI_ ## TAG ## _t) - -// template ostream & operator<<(ostream &s, EST_TKVI const &i); - -#define Instantiate_KVL(KEY, VAL) \ - Instantiate_KVL_T(KEY, VAL, KEY ## VAL) - -#define Declare_KVL_TN(KEY, VAL, MaxFree, TAG) \ - typedef EST_TKVI KVI_ ## TAG ## _t; \ - typedef EST_TKVL KVL_ ## TAG ## _t; \ - \ - static VAL TAG##_kv_def_val_s; \ - static KEY TAG##_kv_def_key_s; \ - \ - template <> VAL *EST_TKVL< KEY, VAL >::default_val=&TAG##_kv_def_val_s; \ - template <> KEY *EST_TKVL< KEY, VAL >::default_key=&TAG##_kv_def_key_s; \ - \ - Declare_TList_N(KVI_ ## TAG ## _t, MaxFree) -#define Declare_KVL_T(KEY, VAL, TAG) \ - Declare_KVL_TN(KEY, VAL, 0, TAG) - -#define Declare_KVL_Base_TN(KEY, VAL, DEFV, DEFK, MaxFree, TAG) \ - typedef EST_TKVI KVI_ ## TAG ## _t; \ - typedef EST_TKVL KVL_ ## TAG ## _t; \ - \ - static VAL TAG##_kv_def_val_s=DEFV; \ - static KEY TAG##_kv_def_key_s=DEFK; \ - \ - template <> VAL *EST_TKVL< KEY, VAL >::default_val=&TAG##_kv_def_val_s; \ - template <> KEY *EST_TKVL< KEY, VAL >::default_key=&TAG##_kv_def_key_s; \ - \ - Declare_TList_N(KVI_ ## TAG ## _t, MaxFree) -#define Declare_KVL_Base_T(KEY, VAL, DEFV, DEFK, TAG) \ - Declare_KVL_Base_TN(KEY, VAL, DEFV, DEFK, 0, TAG) - -#define Declare_KVL_Class_TN(KEY, VAL, DEFV, DEFK, MaxFree, TAG) \ - typedef EST_TKVI KVI_ ## TAG ## _t; \ - typedef EST_TKVL KVL_ ## TAG ## _t; \ - \ - static VAL TAG##_kv_def_val_s(DEFV); \ - static KEY TAG##_kv_def_key_s(DEFK); \ - \ - template <> VAL *EST_TKVL< KEY, VAL >::default_val=&TAG##_kv_def_val_s; \ - template <> KEY *EST_TKVL< KEY, VAL >::default_key=&TAG##_kv_def_key_s; \ - \ - Declare_TList_N(KVI_ ## TAG ## _t, MaxFree) -#define Declare_KVL_Class_T(KEY, VAL, DEFV, DEFK,TAG) \ - Declare_KVL_Class_TN(KEY, VAL, DEFV, DEFK, 0, TAG) - -#define Declare_KVL_N(KEY, VAL, MaxFree) \ - Declare_KVL_TN(KEY, VAL, MaxFree, KEY ## VAL) -#define Declare_KVL(KEY, VAL) \ - Declare_KVL_N(KEY, VAL, 0) - -#define Declare_KVL_Base_N(KEY, VAL, DEFV, DEFK, MaxFree) \ - Declare_KVL_Base_TN(KEY, VAL, DEFV, DEFK, , MaxFree, KEY ## VAL) -#define Declare_KVL_Base(KEY, VAL, DEFV, DEFK) \ - Declare_KVL_Base_N(KEY, VAL, DEFV, DEFK, 0) - -#define Declare_KVL_Class_N(KEY, VAL, DEFV, DEFK, MaxFree) \ - Declare_KVL_Class_TN(KEY, VAL, DEFV, DEFK, MaxFree, KEY ## VAL) -#define Declare_KVL_Class(KEY, VAL, DEFV, DEFK) \ - Declare_KVL_Class_N(KEY, VAL, DEFV, DEFK, 0) - - - -Declare_KVL(EST_String,EST_String) - -template -EST_Litem *EST_TKVL::find_pair_key(const K &key) const -{ - EST_Litem *ptr; - - for (ptr = list.head(); ptr != 0; ptr= next(ptr)) - if (list.item(ptr).k == key) - return ptr; - return 0; -} - -// look for key rkey in list. If found, change its value to rval and -// return true, otherwise return false. -template -int EST_TKVL::change_val(const K &rkey,const V &rval) -{ - EST_Litem *ptr=find_pair_key(rkey); - if (ptr == 0) - return 0; - else - { - list.item(ptr).v = rval; - return 1; - } -} - -template -const V &EST_TKVL::val_def(const K &rkey, const V &def) const -{ - EST_Litem *ptr = find_pair_key(rkey); - if (ptr == 0) - return def; - else - return list.item(ptr).v; -} - -void make_updatable(EST_ChunkPtr &cp) -{ - if (cp.ptr && cp.ptr->count > 1) - { - EST_Chunk *newchunk = new(cp.ptr->size) EST_Chunk; - - memcpy(newchunk->memory, cp.ptr->memory, cp.ptr->size); - - cp = newchunk; - } -} - -const EST_Val &EST_Features::val(const char *name, const EST_Val &def) const -{ - // Because so many access are from char* literals we all access - // directly rather than requiring the creation of an EST_String - EST_Litem *p; - - for (p=features->list.head(); p; p=next(p)) - { - if (features->list(p).k == name) - return features->list(p).v; - } - return def; -} - -EST_String operator + (const EST_String &a, const char *b) -{ - CHECK_STRING_ARG(b); - - int al = a.size; - int bl = safe_strlen(b); - - if (al == 0) - return EST_String(b, 0, bl); - if (bl == 0) - return EST_String(a); - - EST_ChunkPtr c = chunk_allocate(al+bl+1, a.str(), al); - - if (bl>0) - memmove((char *)c + al, b, bl); - c(al+bl)='\0'; - - return EST_String(al+bl, c); -} - -EST_Val EST_Features::feature_default_value("0"); - -EST_Featured::~EST_Featured(void) -{ - clear_features(); -} - -template -EST_TMatrix::~EST_TMatrix() -{ - p_num_rows = 0; - p_row_step=0; -} - -template -EST_TVector::~EST_TVector() -{ - p_num_columns = 0; - p_offset=0; - p_column_step=0; - - if (p_memory != NULL && !p_sub_matrix) - { - delete [] (p_memory-p_offset); - p_memory = NULL; - } -} - -void EST_Track::set_channel_name(const EST_String &fn, int i) -{ - p_channel_names[i] = fn; -} - -EST_String operator + (const char *a, const EST_String &b) -{ - CHECK_STRING_ARG(a); - - int al = safe_strlen(a); - int bl = b.size; - - if (bl == 0) - return EST_String(a, 0, al); - if (al == 0) - return EST_String(b); - - EST_ChunkPtr c = chunk_allocate(al+bl+1, a, al); - - memmove((char *)c + al, b.str(), bl); - - c(al+bl)='\0'; - - return EST_String(al+bl, c); -} - -void EST_Track::default_vals(void) -{ - p_equal_space = FALSE; - p_single_break = FALSE; - p_values.resize(0, 0); - p_times.resize(0); - p_is_val.resize(0); - p_aux.resize(0, 0); - p_aux_names.resize(0); - p_channel_names.resize(0); - p_map = NULL; - p_t_offset=0; - - init_features(); -} - -template -EST_TVector::EST_TVector() -{ - default_vals(); -} - -template -EST_TMatrix::EST_TMatrix() -{ - default_vals(); -} - -EST_Featured::EST_Featured(void) -{ - init_features(); -} - -template EST_TSimpleVector::EST_TSimpleVector(const EST_TSimpleVector &in) -{ - this->default_vals(); - copy(in); -} - -void *safe_walloc(int size) -{ - char *p; - - if (size == 0) - /* Some mallocs return NULL for size 0, which means you can't tell - if it failed or not. So we'll avoid that problem by never - asking for 0 bytes */ - p = (char*)calloc(1,1); - else - p = (char*)calloc(size,1); - - if (p == NULL) - { - fprintf(stderr,"WALLOC: failed to malloc %d bytes\n",size); - exit(-1); /* I'd rather not do this but this is the only safe */ - /* thing to do */ - } - - return p; -} - -/* return the lesser of the two values */ -#define Lof(a, b) (((a) < (b)) ? (a) : (b)) - -template -void EST_TSimpleMatrix::resize(int new_rows, - int new_cols, - int set) -{ - T* old_vals=NULL; - int old_offset = this->p_offset; - - if (new_rows<0) - new_rows = this->num_rows(); - if (new_cols<0) - new_cols = this->num_columns(); - - if (set) - { - if (!this->p_sub_matrix && new_cols == this->num_columns() && new_rows != this->num_rows()) - { - int copy_r = Lof(this->num_rows(), new_rows); - - just_resize(new_rows, new_cols, &old_vals); - - memcpy((void *)this->p_memory, - (const void *)old_vals, - copy_r*new_cols*sizeof(T)); - - int i,j; - - if (new_rows > copy_r) - if (*this->def_val == 0) - { - memset((void *)(this->p_memory + copy_r*this->p_row_step), - 0, - (new_rows-copy_r)*new_cols*sizeof(T)); - } - else - { - for(j=0; ja_no_check(i,j) = *this->def_val; - } - } - else if (!this->p_sub_matrix) - { - int old_row_step = this->p_row_step; - int old_column_step = this->p_column_step; - int copy_r = Lof(this->num_rows(), new_rows); - int copy_c = Lof(this->num_columns(), new_cols); - - just_resize(new_rows, new_cols, &old_vals); - - set_values(old_vals, - old_row_step, old_column_step, - 0, copy_r, - 0, copy_c); - - int i,j; - - for(i=0; ia_no_check(i,j) = *this->def_val; - - if (new_rows > copy_r) - if (*this->def_val == 0) - { - memset((void *)(this->p_memory + copy_r*this->p_row_step), - 0, - (new_rows-copy_r)*new_cols*sizeof(T)); - } - else - { - for(j=0; ja_no_check(i,j) = *this->def_val; - } - } - else - EST_TMatrix::resize(new_rows, new_cols, 1); - } - else - EST_TMatrix::resize(new_rows, new_cols, 0); - - if (old_vals && old_vals != this->p_memory) - delete [] (old_vals-old_offset); -} - - -void EST_Track::set_value(int i) // make location i hold a value -{ - p_is_val[i] = 0; -} - -void EST_Track::set_break(int i) // make location i hold a break -{ - if (i >= num_frames()) - cerr << "Requested setting of break value of the end of the array\n"; - - p_is_val[i] = 1; -} - -float EST_Track::shift() const -{ - int j1 = 0; - int j2 = 0; - - if (!p_equal_space) - exit(1);//EST_error("Tried to take shift from non-fixed contour\n"); - - do - { - j1 = next_non_break(++j1); - j2 = next_non_break(j1); - // cout << "j1:" << j1 << " j2:" << j2 << endl; - } - while ((j2 != 0) && (j2 != (j1 +1))); - - if (j2 == 0) - { - if (num_frames() > 1) - return p_times(1) - p_times(0); - else - exit(1);//EST_error("Couldn't determine shift size\n"); - - } - return (p_times(j2) - p_times(j1)); -} - -EST_Track &EST_Track::operator=(const EST_Track& a) -{ - copy(a); - return *this; -} - -int EST_Track::empty() const -{ - int i, num; - - for (i = num = 0; i < num_frames(); ++i) - if (val(i)) - return 0; // i.e. false - - return 1; // i.e. true -} - -const float EST_Val::to_flt(void) const -{ - // coerce this to a float - if (t==val_int) - return (float)v.ival; - else if (t==val_string) - return atof(sval); - else - return v.fval; // just for completeness -} - -int EST_Track::next_non_break(int j) const -{ - int i = j; - for (++i; i < num_frames(); ++i) - { - // cout << "i: " << i << " " << value[i] << endl; - if (!track_break(i)) - return i; - } - - return 0; -} - -float EST_Track::a(int i, int c) const -{ - return ((EST_Track *)this)->a(i,c); -} - -void EST_Track::resize(int new_num_frames, int new_num_channels, bool set) -{ - int old_num_frames = num_frames(); - - if (new_num_frames<0) - new_num_frames = num_frames(); - - if (new_num_channels<0) - new_num_channels = num_channels(); - - p_channel_names.resize(new_num_channels); - - // this ensures the new channels have a default name - if (new_num_channels > num_channels()) - for (int i = num_channels(); i < new_num_channels; ++i) - set_channel_name("track_" + itoString(i), i); - - p_values.resize(new_num_frames, new_num_channels, set); - p_times.resize(new_num_frames, set); - p_is_val.resize(new_num_frames, set); - - p_aux.resize(new_num_frames, num_aux_channels(), set); - - // Its important that any new vals get set to 0 - for (int i = old_num_frames; i < num_frames(); ++i) - p_is_val.a_no_check(i) = 0; - -} - -Declare_TVector(float) - -EST_Chunk::EST_Chunk () -{ - count = 0; - memory[0] = '\0'; - // cerr<<"created " << hex << (int)&memory << "," << dec << size <<"\n"; -} - -void *EST_Chunk::operator new (size_t size, int bytes) -{ - - if (bytes > MAX_CHUNK_SIZE) - { - cerr<<"trying to make chunk of size "< size = bytes; - - return it; -} - -EST_String::EST_String(const char *s, int s_size, int start, int len) -{ - CHECK_STRING_ARG(s); - - if (len <0) - len=s_size-start; - - size=len; - if (size != 0) - memory = chunk_allocate(len+1, s+start, len); - else - memory=NULL; -} - -int EST_String::locate(const char *s, int len, int from, int &start, int &end) const -{ - CHECK_STRING_ARG(s); - - const char *sub=NULL; - - if (!s) - return 0; - - if (from < 0 && -from < size) - { - int endpos=size+from+1; - int p=0; - const char *nextsub; - - while ((nextsub=strstr(str()+p, s))) - { - p=nextsub-str()+1; - if (p > endpos) - break; - sub=nextsub; - } - } - else if (from>=0 && from <= size) - sub= strstr(str()+from, s); - - if (sub != NULL) - { - start = sub-str(); - end = start + len; - return 1; - } - else - { - return 0; - } - -} - -Declare_KVL_N(EST_String, EST_Val, 100) - -template EST_TKVL &EST_TKVL::operator = -(const EST_TKVL &kv) -{ - list = kv.list; - return *this; -} - - - -#define SWAPINT(x) ((((unsigned)x) & 0xff) << 24 | \ - (((unsigned)x) & 0xff00) << 8 | \ - (((unsigned)x) & 0xff0000) >> 8 | \ - (((unsigned)x) & 0xff000000) >> 24) -#define SWAPSHORT(x) ((((unsigned)x) & 0xff) << 8 | \ - (((unsigned)x) & 0xff00) >> 8) - -#define WAVE_FORMAT_PCM 0x0001 -#define WAVE_FORMAT_ADPCM 0x0002 -#define WAVE_FORMAT_ALAW 0x0006 -#define WAVE_FORMAT_MULAW 0x0007 - -void swap_bytes_short(short *data, int length) -{ - /* Swap shorts in an array */ - int i; - - for (i=0; i -INFO &EST_TValuedEnumI::info (ENUM token) const -{ - int i; - - for(i=0; indefinitions; i++) - if (this->definitions[i].token == token) - return this->definitions[i].info; - - exit(1);//cerr << "Fetching info for invalid entry\n"; - abort(); - - static INFO dummyI; - return dummyI; -} - -template -ENUM EST_TValuedEnumI::token (VAL value) const -{ - int i,j; - - for(i=0; indefinitions; i++) - for(j=0; jdefinitions[i].values[j] ; j++) - if (eq_vals(this->definitions[i].values[j], value)) - return this->definitions[i].token; - - return this->p_unknown_enum; -} - - -void EST_TokenStream::default_values() -{ - type = tst_none; - peeked_tokp = FALSE; - peeked_charp = FALSE; - eof_flag = FALSE; - quotes = FALSE; - p_filepos = 0; - linepos = 1; - WhiteSpaceChars = EST_Token_Default_WhiteSpaceChars; - SingleCharSymbols = EST_String::Empty; - PrePunctuationSymbols = EST_String::Empty; - PunctuationSymbols = EST_String::Empty; - build_table(); - close_at_end=TRUE; -} - -template -VAL EST_TValuedEnumI::value (ENUM token, int n) const -{ - int i; - - for(i=0; indefinitions; i++) - if (this->definitions[i].token == token) - return this->definitions[i].values[n]; - - return this->p_unknown_value; -} - -int EST_TokenStream::seek(int position) -{ - peeked_charp = FALSE; - peeked_tokp = FALSE; - - switch (type) - { - case tst_none: - exit(1);//cerr << "EST_TokenStream unset" << endl; - return -1; - break; - case tst_file: - p_filepos = position; - return fseek(fp,position,SEEK_SET); - case tst_pipe: - exit(1);//cerr << "EST_TokenStream seek on pipe not supported" << endl; - return -1; - break; - case tst_istream: - exit(1);//cerr << "EST_TokenStream seek on istream not yet supported" << endl; - return -1; - break; - case tst_string: - if (position >= pos) - { - pos = position; - return -1; - } - else - { - pos = position; - return 0; - } - break; - default: - exit(1);//cerr << "EST_TokenStream: unknown type" << endl; - return -1; - } - - return -1; // can't get here - -} - -template -int EST_TValuedEnumI::n(void) const -{ -return this->ndefinitions; -} - -EST_String::EST_String(const char *s, int start_or_fill, int len) -{ - - if (s) - { - int start= start_or_fill; - if (len <0) - len=safe_strlen(s)-start; - - size=len; - if (size != 0) - memory = chunk_allocate(len+1, s+start, len); - else - memory=NULL; - } - else - { - char fill = start_or_fill; - if (len<0) len=0; - size=len; - if (size != 0) - { - memory = chunk_allocate(len+1); - char *p = memory; - for(int j=0; j -void EST_TVector::resize(int new_cols, int set) -{ - int i; - T * old_vals = p_memory; - int old_cols = num_columns(); - int old_offset = p_offset; - int old_column_step = p_column_step; - - just_resize(new_cols, &old_vals); - - if (set) - { - int copy_c = 0; - - if (!old_vals) - copy_c=0; - else if (old_vals != p_memory) - { - copy_c = Lof(num_columns(), old_cols); - - for(i=0; i -void EST_TMatrix::resize(int new_rows, int new_cols, int set) -{ - int i,j; - T * old_vals = this->p_memory; - int old_rows = num_rows(); - int old_cols = num_columns(); - int old_row_step = p_row_step; - int old_offset = this->p_offset; - int old_column_step = this->p_column_step; - - if (new_rows<0) - new_rows = old_rows; - if (new_cols<0) - new_cols = old_cols; - - just_resize(new_rows, new_cols, &old_vals); - - if (set) - { - int copy_r = 0; - int copy_c = 0; - - if (old_vals != NULL) - { - copy_r = Lof(num_rows(), old_rows); - copy_c = Lof(num_columns(), old_cols); - - set_values(old_vals, - old_row_step, old_column_step, - 0, copy_r, - 0, copy_c); - } - else - { - copy_r = old_rows; - copy_c = old_cols; - } - - for(i=0; idef_val; - - for(i=copy_r; idef_val; - } - - if (old_vals && old_vals != this->p_memory && !this->p_sub_matrix) - delete [] (old_vals-old_offset); -} - -// should copy from and delete old version first -template void EST_TSimpleVector::resize(int newn, int set) -{ - int oldn = this->n(); - T *old_vals =NULL; - int old_offset = this->p_offset; - - just_resize(newn, &old_vals); - - if (set && old_vals) - { - int copy_c = 0; - if (this->p_memory != NULL) - { - copy_c = Lof(this->n(), oldn); - memcpy((void *)this->p_memory, (const void *)old_vals, copy_c* sizeof(T)); - } - - for (int i=copy_c; i < this->n(); ++i) - this->p_memory[i] = *this->def_val; - } - - if (old_vals != NULL && old_vals != this->p_memory && !this->p_sub_matrix) - delete [] (old_vals - old_offset); - -} - -void EST_Track::copy(const EST_Track& a) -{ - copy_setup(a); - p_values = a.p_values; - p_times = a.p_times; - p_is_val = a.p_is_val; - p_t_offset = a.p_t_offset; - p_aux = a.p_aux; - p_aux_names = a.p_aux_names; -} - -int EST_Track::val(int i) const -{ - return !p_is_val(i); -} - -void uchar_to_short(const unsigned char *chars,short *data,int length) -{ - /* Convert 8 bit data to shorts UNSIGNED CHAR */ - int i; - - for (i=0; i> 4 ) & 0x07; - mantissa = ulawbyte & 0x0F; - sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) ); - if ( sign != 0 ) sample = -sample; - - return sample; -} - -void ulaw_to_short(const unsigned char *ulaw,short *data,int length) -{ - /* Convert ulaw to shorts */ - int i; - - for (i=0; i -void EST_TMatrix::set_memory(T *buffer, int offset, - int rows, int columns, - int free_when_destroyed) -{ - EST_TVector::set_memory(buffer, offset, columns, free_when_destroyed); - p_num_rows = rows; - p_row_step = columns; -} - -void EST_TokenStream::build_table() -{ - int i; - const char *p; - unsigned char c; - - for (i=0; i<256; ++i) - p_table[i]=0; - - for (p=WhiteSpaceChars; *p; ++p) - if (p_table[c=(unsigned char)*p]) - exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", - // *p, c, ' '); - else - p_table[c] = ' '; - - for (p=SingleCharSymbols; *p; ++p) - if (p_table[c=(unsigned char)*p]) - exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", - // *p, p_table[c], '!'); - else - p_table[c] = '@'; - - for (p=PunctuationSymbols; *p; ++p) - if (p_table[c=(unsigned char)*p] == '@') - continue; - else if (p_table[c]) - exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", - // *p, p_table[c], '.'); - else - p_table[c] = '.'; - - for(p=PrePunctuationSymbols; *p; ++p) - if (p_table[c=(unsigned char)*p] == '@') - continue; - else if (p_table[c] == '.') - p_table[c] = '"'; - else if (p_table[c]) - exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", - // *p, p_table[c], '$'); - else - p_table[c] = '$'; - - p_table_wrong=0; -} - -const EST_String EST_String::Empty(""); - -const EST_String EST_Token_Default_WhiteSpaceChars = " \t\n\r"; - -EST_ChunkPtr chunk_allocate(int bytes) -{ - EST_Chunk *cp = new(bytes) EST_Chunk; - - return (EST_ChunkPtr)cp; -} - - -template -EST_TVector &EST_TVector::operator=(const EST_TVector &in) -{ - copy(in); - return *this; -} - -template -EST_TMatrix &EST_TMatrix::operator=(const EST_TMatrix &in) -{ - copy(in); - return *this; -} - -template EST_TSimpleVector &EST_TSimpleVector::operator=(const EST_TSimpleVector &in) -{ - copy(in); - return *this; -} - -void EST_Track::copy_setup(const EST_Track& a) -{ - p_equal_space = a.p_equal_space; - p_single_break = a.p_single_break; - p_channel_names = a.p_channel_names; - p_map = a.p_map; - copy_features(a); -} - -template EST_TSimpleMatrix &EST_TSimpleMatrix::operator=(const EST_TSimpleMatrix &in) -{ - copy(in); - return *this; -} - -template -void EST_TSimpleMatrix::copy(const EST_TSimpleMatrix &a) -{ - if (this->num_rows() != a.num_rows() || this->num_columns() != a.num_columns()) - resize(a.num_rows(), a.num_columns(), 0); - - copy_data(a); -} - -void EST_Featured::copy_features(const EST_Featured &f) -{ - clear_features(); - - if (f.p_features) - p_features = new EST_Features(*(f.p_features)); -} - -template -EST_TVector::EST_TVector(int n) -{ - default_vals(); - resize(n); -} - -void EST_UList::clear_and_free(void (*item_free)(EST_UItem *p)) -{ - EST_UItem *p, *np; - - for (p=head(); p != 0; p = np) - { - np=next(p); - if (item_free) - item_free(p); - else - delete p; - } - h = t = 0; -} - -template void EST_TList::free_item(EST_UItem *item) -{ EST_TItem::release((EST_TItem *)item); } - -void EST_UList::append(EST_UItem *new_item) -{ - - if (new_item == 0) return; - - new_item->n = 0; - new_item->p = t; - if (t == 0) - h = new_item; - else - t->n = new_item; - t = new_item; -} - -template EST_TItem *EST_TItem::make(const T &val) -{ - EST_TItem *it=NULL; - if (s_free!=NULL) - { - void *mem = s_free; - s_free=(EST_TItem *)s_free->n; - s_nfree--; - - // Create an item in the retrieved memory. - it=new (mem) EST_TItem(val); - } - else - it = new EST_TItem(val); - - return it; -} - -template -ENUM EST_TValuedEnumI::nth_token (int n) const -{ - if (n>=0 && n < this->ndefinitions) - return this->definitions[n].token; - - return this->p_unknown_enum; -} - -EST_TrackMap::~EST_TrackMap() -{ -} - -template -void EST_TVector::default_vals() -{ - p_num_columns = 0; - p_offset=0; - p_column_step=0; - - p_memory = NULL; - p_sub_matrix=FALSE; -} - -template -void EST_TMatrix::default_vals() -{ - EST_TVector::default_vals(); - p_num_rows = 0; - p_row_step=0; -} - -template -void EST_TMatrix::set_values(const T *data, - int r_step, int c_step, - int start_r, int num_r, - int start_c, int num_c - ) -{ - for(int r=start_r, i=0, rp=0; i< num_r; i++, r++, rp+=r_step) - for(int c=start_c, j=0, cp=0; j< num_c; j++, c++, cp+=c_step) - a_no_check(r,c) = data[rp+cp]; -} - -template -void EST_TMatrix::just_resize(int new_rows, - int new_cols, - T** old_vals) -{ - T *new_m; - - if (num_rows() != new_rows || num_columns() != new_cols || this->p_memory == NULL ) - { - if (this->p_sub_matrix) - exit(1);//EST_error("Attempt to resize Sub-Matrix"); - - if (new_cols < 0 || new_rows < 0) - exit(1);//EST_error("Attempt to resize matrix to negative size: %d x %d", - // new_rows, - // new_cols); - - - new_m = new T[new_rows*new_cols]; - - if (this->p_memory != NULL) - if (old_vals != NULL) - *old_vals = this->p_memory; - else if (!this->p_sub_matrix) - delete [] (this->p_memory-this->p_offset); - - p_num_rows = new_rows; - this->p_num_columns = new_cols; - this->p_offset=0; - p_row_step=this->p_num_columns; - this->p_column_step=1; - - this->p_memory = new_m; - } - else - *old_vals = this->p_memory; - -} - -template void EST_TSimpleVector::copy(const EST_TSimpleVector &a) -{ - if (this->p_column_step==1 && a.p_column_step==1) - { - resize(a.n(), FALSE); - memcpy((void *)(this->p_memory), (const void *)(a.p_memory), this->n() * sizeof(T)); - } -else - ((EST_TVector *)this)->copy(a); -} - -template -void EST_TVector::just_resize(int new_cols, T** old_vals) -{ - T *new_m; - - if (num_columns() != new_cols || p_memory == NULL ) - { - if (p_sub_matrix) - exit(1);//EST_error("Attempt to resize Sub-Vector"); - - if (new_cols < 0) - exit(1);//EST_error("Attempt to resize vector to negative size: %d", - // new_cols); - - new_m = new T[new_cols]; - - if (p_memory != NULL) - if (old_vals != NULL) - *old_vals = p_memory; - else if (!p_sub_matrix) - delete [] (p_memory-p_offset); - - p_memory = new_m; - //cout << "vr: mem: " << p_memory << " (" << (int)p_memory << ")\n"; - p_offset=0; - p_num_columns = new_cols; - p_column_step=1; - } - else - *old_vals = p_memory; -} - -template -void EST_TVector::set_memory(T *buffer, int offset, int columns, - int free_when_destroyed) -{ - if (p_memory != NULL && !p_sub_matrix) - delete [] (p_memory-p_offset); - - p_memory = buffer-offset; - p_offset=offset; - p_num_columns = columns; - p_column_step=1; - p_sub_matrix = !free_when_destroyed; -} - -template -void EST_TSimpleMatrix::copy_data(const EST_TSimpleMatrix &a) -{ - if (!a.p_sub_matrix && !this->p_sub_matrix) - memcpy((void *)&this->a_no_check(0,0), - (const void *)&a.a_no_check(0,0), - this->num_rows()*this->num_columns()*sizeof(T) - ); - else - { - for (int i = 0; i < this->num_rows(); ++i) - for (int j = 0; j < this->num_columns(); ++j) - this->a_no_check(i,j) = a.a_no_check(i,j); - } -} - -Declare_TVector(short) - -template void EST_TItem::release(EST_TItem *it) -{ - if (s_nfree < s_maxFree) - { - // Destroy the value in case it holds resources. - it->EST_TItem::~EST_TItem(); - - // I suppose it's a bit weird to use 'n' after calling the destructor. - it->n=s_free; - s_free=it; - s_nfree++; - } - else - delete it; -} - -EST_Val &EST_Val::operator=(const EST_Val &c) -{ - // Have to be careful with the case where they are different types - if ((t != val_int) && - (t != val_float) && - (t != val_unset) && - (t != val_string)) - delete v.pval; - - if (c.t == val_string) - sval = c.sval; - else if (c.t == val_int) - v.ival = c.v.ival; - else if (c.t == val_float) - v.fval = c.v.fval; - else if (c.t != val_unset) - { // does references not a real copy - v.pval = new EST_Contents; - *v.pval = *c.v.pval; - } - t=c.t; - return *this; -} - -template EST_TList &EST_TList::operator=(const EST_TList &a) -{ - clear(); // clear out all current items in list. - copy_items(a); - return *this; -} - -int operator == (const EST_String &a, const EST_String &b) -{ - if (a.size==0) - return b.size == 0; - else if (b.size == 0) - return 0; - else - return a.size == b.size && a(0) == b(0) && memcmp(a.str(),b.str(),a.size)==0; -}; - -Declare_TVector(char) -Declare_TVector(EST_Val) -Declare_TVector(EST_String) - -template -void EST_TMatrix::copy(const EST_TMatrix &a) -{ - resize(a.num_rows(), a.num_columns(), 0); - copy_data(a); -} - -template -void EST_TVector::copy(const EST_TVector &a) -{ - resize(a.n(), FALSE); - copy_data(a); -} - -template void EST_TList::copy_items(const EST_TList &l) -{ - EST_UItem *p; - for (p = l.head(); p; p = next(p)) - append(l.item(p)); -} - -template -void EST_TMatrix::copy_data(const EST_TMatrix &a) -{ - - set_values(a.p_memory, - a.p_row_step, a.p_column_step, - 0, a.num_rows(), - 0, a.num_columns()); -} - -template -void EST_TVector::copy_data(const EST_TVector &a) -{ - set_values(a.p_memory, a.p_column_step, 0, num_columns()); -} - -EST_Val::EST_Val(const EST_Val &c) -{ - if (c.t == val_string) - sval = c.sval; - else if (c.t == val_int) - v.ival = c.v.ival; - else if (c.t == val_float) - v.fval = c.v.fval; - else if (c.t != val_unset) - { // does references not a real copy - v.pval = new EST_Contents; - *v.pval = *c.v.pval; - } - t=c.t; -} - -template -void EST_TVector::set_values(const T *data, - int step, - int start_c, - int num_c) -{ - for(int i=0, c=start_c, p=0; i -void EST_TValuedEnumI::initialise(const void *vdefs) -{ - int n=0; - typedef EST_TValuedEnumDefinition defn; - const defn *defs = (const defn *)vdefs; - - for(n=1; defs[n].token != defs[0].token; n++) - ; - - this->ndefinitions = n; - this->definitions = new defn[n]; - - this->definitions[0] = defs[0]; - for(n=1; defs[n].token != defs[0].token; n++) - this->definitions[n] = defs[n]; - - this->p_unknown_enum = defs[n].token; - this->p_unknown_value = defs[n].values[0]; -} - -template -EST_TValuedEnumI::~EST_TValuedEnumI(void) -{ - if (this->definitions) - delete[] this->definitions; -} - -struct Srpd_Op { - int sample_freq; /* Hz */ - int Nmax, Nmin; - double shift, length; /* ms */ - double min_pitch; /* Hz */ - double max_pitch; /* Hz */ - int L; /* Decimation factor (samples) */ - double Tmin, Tmax_ratio, Thigh, Tdh; - int Tsilent; - int make_ascii; - int peak_tracking; -}; - -#define MINARG 5 -#define BREAK_NUMBER 0.0 - -#define DEFAULT_DECIMATION 4 /* samples */ -#define DEFAULT_MIN_PITCH 60.0 /* Hz */ -#define DEFAULT_MAX_PITCH 600.0 /* Hz */ - -#define DEFAULT_SF 20000 /* Hz. Sampling Frequency */ -#define DEFAULT_SHIFT 5.0 /* ms */ -#define DEFAULT_LENGTH 10.0 /* ms */ -#define DEFAULT_TSILENT 120 /* max. abs sample amplitude of noise */ -#define DEFAULT_TMIN 0.75 -#define DEFAULT_TMAX_RATIO 0.85 -#define DEFAULT_THIGH 0.88 -#define DEFAULT_TDH 0.77 - -enum Voice { - UNVOICED = 0, - VOICED = 1, - SILENT = 2, -}; - - -enum Hold { - HOLD = 1, - HELD = 1, - SEND = 2, - SENT = 2, -}; - - -static struct Srpd_Op *default_srpd_op(struct Srpd_Op *srpd) -{ - srpd->L = DEFAULT_DECIMATION; - srpd->min_pitch = DEFAULT_MIN_PITCH; - srpd->max_pitch = DEFAULT_MAX_PITCH; - srpd->shift = DEFAULT_SHIFT; - srpd->length = DEFAULT_LENGTH; - srpd->Tsilent = DEFAULT_TSILENT; - srpd->Tmin = DEFAULT_TMIN; - srpd->Tmax_ratio = DEFAULT_TMAX_RATIO; - srpd->Thigh = DEFAULT_THIGH; - srpd->Tdh = DEFAULT_TDH; - srpd->make_ascii = 0; - srpd->peak_tracking = 0; - srpd->sample_freq = DEFAULT_SF; - /* p_par->Nmax and p_par->Nmin cannot be initialised */ - return(srpd); -} - -struct STATUS_ -{ - double pitch_freq; - Voice v_uv; - Hold s_h; - double cc_max, threshold; -}; - -#define rint(N) ((float)(int)((N)+0.5)) - -void initialise_structures (struct Srpd_Op *p_par, SEGMENT_ *p_seg, CROSS_CORR_ *p_cc) -{ - p_par->Nmax = (int) ceil((float)p_par->sample_freq / p_par->min_pitch); - p_par->Nmin = (int) floor((float)p_par->sample_freq / p_par->max_pitch); - p_par->min_pitch = (float)p_par->sample_freq / (float)p_par->Nmax; - p_par->max_pitch = (float)p_par->sample_freq / (float)p_par->Nmin; - - p_seg->size = 3 * p_par->Nmax; - p_seg->shift = (int) rint( p_par->shift / 1000.0 * (float)p_par->sample_freq ); - p_seg->length = (int) rint( p_par->length / 1000.0 * (float)p_par->sample_freq ); - p_seg->data = walloc(short,p_seg->size); - - p_cc->size = p_par->Nmax - p_par->Nmin + 1; - p_cc->coeff = walloc(double,p_cc->size); -} - -void initialise_status (const Srpd_Op ¶s, STATUS_ *p_status) -{ - - p_status->pitch_freq = BREAK_NUMBER; - p_status->v_uv = SILENT; - p_status->s_h = SEND; /* SENT */ - p_status->cc_max = 0.0; - p_status->threshold = paras.Thigh; - return; - -} - - -short ConvertFloatTo16Bit( float fSample ) -{ - short ret = fSample * 32768.0f; - return ret; -} - -int read_next_wave_segment2(RageSoundReader_FileReader *sample, const Srpd_Op ¶s, SEGMENT_ *p_seg) -{ - printf("read: size %d shift %d length %d\n", p_seg->size, p_seg->shift, p_seg->length); - - ASSERT( sample->GetNumChannels() == 1 ); - - int iSize = p_seg->size; - float *pfData = new float[iSize]; - int iNumRead = sample->Read( pfData, iSize ); - - for( int i=0; idata[i] = d; - } - else - { - p_seg->data[i] = 0; - } - } - - SAFE_DELETE_ARRAY( pfData ); - - return iNumRead > 0; -} - - -typedef struct list { - int N0, score; - struct list *next_item; -} LIST_; - -void add_to_list (LIST_ **p_list_hd, LIST_ **p_list_tl, int N_val, - int score_val) -{ - - LIST_ *new_node, *last_node; - - new_node = walloc(LIST_ ,1); - last_node = *p_list_tl; - new_node->N0 = N_val; - new_node->score = score_val; - new_node->next_item = NULL; - if (*p_list_hd == NULL) - *p_list_hd = new_node; - else - last_node->next_item = new_node; - *p_list_tl = new_node; - -} - -void free_list (LIST_ **p_list_hd) -{ - - LIST_ *next; - - while (*p_list_hd != NULL) { - next = (*p_list_hd)->next_item; - wfree (*p_list_hd); - *p_list_hd = next; - } - -} - -void super_resolution_pda (const Srpd_Op ¶s, const SEGMENT_ &seg, CROSS_CORR_ *p_cc, STATUS_ *p_status) -{ - static int zx_lft_N, zx_rht_N; - static double prev_pf = BREAK_NUMBER; - - int n, j, k, N0 = 0, N1, N2, N_, q, lower_found = 0, score = 1, apply_bias; - int x_index, y_index, z_index; - int zx_rate = 0, zx_at_N0 = 0, prev_sign; - int seg1_zxs = 0, seg2_zxs = 0, total_zxs; - short prev_seg1, prev_seg2; - short x_max = -MAXSHORT, x_min = MAXSHORT; - short y_max = -MAXSHORT, y_min = MAXSHORT; - double xx = 0.0, yy = 0.0, zz = 0.0, xy = 0.0, yz = 0.0, xz = 0.0; - double max_cc = 0.0, coefficient, coeff_weight; - double xx_N, yy_N, xy_N, y1y1_N, xy1_N, yy1_N, beta; - LIST_ *sig_pks_hd, *sig_pks_tl, *sig_peak, *head, *tail; - - sig_pks_hd = head = NULL; - sig_pks_tl = tail = NULL; - /* set correlation coefficient threshold */ - if (p_status->v_uv == UNVOICED || p_status->v_uv == SILENT) - p_status->threshold = paras.Thigh; - else /* p_status->v_uv == VOICED */ - p_status->threshold = (paras.Tmin > paras.Tmax_ratio * - p_status->cc_max) ? paras.Tmin : paras.Tmax_ratio * - p_status->cc_max; - /* determine if a bias should be applied */ - if (paras.peak_tracking && prev_pf != BREAK_NUMBER && - p_status->v_uv == VOICED && p_status->s_h != HOLD && - p_status->pitch_freq < 1.75 * prev_pf && - p_status->pitch_freq > 0.625 * prev_pf) - apply_bias = 1; - else - apply_bias = 0; - /* consider first two segments of period n = Nmin */ - prev_seg1 = seg.data[paras.Nmax - paras.Nmin] < 0 ? -1 : 1; - prev_seg2 = seg.data[paras.Nmax] < 0 ? -1 : 1; - for (j = 0; j < paras.Nmin; j += paras.L) { - /* find max and min amplitudes in x and y segments */ - x_index = paras.Nmax - paras.Nmin + j; - y_index = paras.Nmax + j; - if (seg.data[x_index] > x_max) x_max = seg.data[x_index]; - if (seg.data[x_index] < x_min) x_min = seg.data[x_index]; - if (seg.data[y_index] > y_max) y_max = seg.data[y_index]; - if (seg.data[y_index] < y_min) y_min = seg.data[y_index]; - /* does new sample in x or y segment represent an input zero-crossing */ - if (seg.data[x_index] * prev_seg1 < 0) { - prev_seg1 *= -1; - seg1_zxs++; - } - if (seg.data[y_index] * prev_seg2 < 0) { - prev_seg2 *= -1; - seg2_zxs++; - } - /* calculate parts for first correlation coefficient */ - xx += (double) seg.data[x_index] * seg.data[x_index]; - yy += (double) seg.data[y_index] * seg.data[y_index]; - xy += (double) seg.data[x_index] * seg.data[y_index]; - } - /* low amplitude segment represents silence */ - if (abs (x_max) + abs (x_min) < 2 * paras.Tsilent || - abs (y_max) + abs (y_min) < 2 * paras.Tsilent) { - for (q = 0; q < p_cc->size; p_cc->coeff[q++] = 0.0); - prev_pf = p_status->pitch_freq; - p_status->pitch_freq = BREAK_NUMBER; - p_status->v_uv = SILENT; - p_status->s_h = SEND; - p_status->cc_max = 0.0; - return; - } - /* determine first correlation coefficients, for period n = Nmin */ - p_cc->coeff[0] = p_status->cc_max = xy / sqrt (xx) / sqrt (yy); - for (q = 1; q < p_cc->size && q < paras.L; p_cc->coeff[q++] = 0.0); - total_zxs = seg1_zxs + seg2_zxs; - prev_sign = p_cc->coeff[0] < 0.0 ? -1 : 1; - prev_seg1 = seg.data[paras.Nmax - paras.Nmin] < 0 ? -1 : 1; - /* iteratively determine correlation coefficient for next possible period */ - for (n = paras.Nmin + paras.L; n <= paras.Nmax; n += paras.L, - j += paras.L) { - x_index = paras.Nmax - n; - y_index = paras.Nmax + j; - /* does new samples in x or y segment represent an input zero-crossing */ - if (seg.data[x_index] * prev_seg1 < 0) { - prev_seg1 *= -1; - total_zxs++; - } - if (seg.data[y_index] * prev_seg2 < 0) { - prev_seg2 *= -1; - total_zxs++; - } - /* determine next coefficient */ - xx += (double) seg.data[x_index] * seg.data[x_index]; - yy += (double) seg.data[y_index] * seg.data[y_index]; - for (k = 0, xy = 0.0; k < n; k += paras.L) - xy += (double) seg.data[paras.Nmax - n + k] * seg.data[paras.Nmax + k]; - p_cc->coeff[n - paras.Nmin] = xy / sqrt (xx) / sqrt (yy); - if (p_cc->coeff[n - paras.Nmin] > p_status->cc_max) - p_status->cc_max = p_cc->coeff[n - paras.Nmin]; - /* set unknown coefficients to zero */ - for (q = n - paras.Nmin + 1; - q < p_cc->size && q < n - paras.Nmin + paras.L; - p_cc->coeff[q++] = 0.0); - /* is there a slope with positive gradient in the coefficients track yet */ - if (p_cc->coeff[n - paras.Nmin] > p_cc->coeff[n - paras.Nmin - paras.L]) - lower_found = 1; - /* has new coefficient resulted in a zero-crossing */ - if (p_cc->coeff[n - paras.Nmin] * prev_sign < 0.0) { - prev_sign *= -1; - zx_rate++; - } - /* does the new coefficient represent a pitch period candidate */ - if (N0 != 0 && zx_rate > zx_at_N0) { - add_to_list (&sig_pks_hd, &sig_pks_tl, N0, 1); - N0 = 0; - max_cc = 0.0; - } - if (apply_bias && n > zx_lft_N && n < zx_rht_N) - coeff_weight = 2.0; - else - coeff_weight = 1.0; - if (p_cc->coeff[n - paras.Nmin] > max_cc && total_zxs > 3 && lower_found) { - max_cc = p_cc->coeff[n - paras.Nmin]; - if (max_cc * coeff_weight >= p_status->threshold) { - zx_at_N0 = zx_rate; - N0 = n; - } - } - } - /* unvoiced if no significant peak found in coefficients track */ - if (sig_pks_hd == NULL) { - prev_pf = p_status->pitch_freq; - p_status->pitch_freq = BREAK_NUMBER; - p_status->v_uv = UNVOICED; - p_status->s_h = SEND; - return; - } - /* find which significant peak in list corresponds to true pitch period */ - sig_peak = sig_pks_hd; - while (sig_peak != NULL) { - yy = zz = yz = 0.0; - for (j = 0; j < sig_peak->N0; j++) { - y_index = paras.Nmax + j; - z_index = paras.Nmax + sig_peak->N0 + j; - yy += (double) seg.data[y_index] * seg.data[y_index]; - zz += (double) seg.data[z_index] * seg.data[z_index]; - yz += (double) seg.data[y_index] * seg.data[z_index]; - } - if (yy == 0.0 || zz == 0.0) - coefficient = 0.0; - else - coefficient = yz / sqrt (yy) / sqrt (zz); - if (apply_bias && sig_peak->N0 > zx_lft_N && sig_peak->N0 < zx_rht_N) - coeff_weight = 2.0; - else - coeff_weight = 1.0; - if (coefficient * coeff_weight >= p_status->threshold) { - sig_peak->score = 2; - if (head == NULL) { - head = sig_peak; - score = 2; - } - tail = sig_peak; - } - sig_peak = sig_peak->next_item; - } - if (head == NULL) head = sig_pks_hd; - if (tail == NULL) tail = sig_pks_tl; - N0 = head->N0; - if (tail != head) { - xx = 0.0; - for (j = 0; j < tail->N0; j++) - xx += (double) seg.data[paras.Nmax - tail->N0 + j] * - seg.data[paras.Nmax - tail->N0 + j]; - sig_peak = head; - while (sig_peak != NULL) { - if (sig_peak->score == score) { - xz = zz = 0.0; - for (j = 0; j < tail->N0; j++) { - z_index = paras.Nmax + sig_peak->N0 + j; - xz += (double) seg.data[paras.Nmax - tail->N0 + j] * - seg.data[z_index]; - zz += (double) seg.data[z_index] * seg.data[z_index]; - } - coefficient = xz / sqrt (xx) / sqrt (zz); - if (sig_peak == head) - max_cc = coefficient; - else if (coefficient * paras.Tdh > max_cc) { - N0 = sig_peak->N0; - max_cc = coefficient; - } - } - sig_peak = sig_peak->next_item; - } - } - p_status->cc_max = p_cc->coeff[N0 - paras.Nmin]; - /* voiced segment period now found */ - if ((tail == head && score == 1 && p_status->v_uv != VOICED) || - p_cc->coeff[N0 - paras.Nmin] < p_status->threshold) - p_status->s_h = HOLD; - else - p_status->s_h = SEND; - /* find left and right boundaries of peak in coefficients track */ - zx_lft_N = zx_rht_N = 0; - for (q = N0; q >= paras.Nmin; q -= paras.L) - if (p_cc->coeff[q - paras.Nmin] < 0.0) { - zx_lft_N = q; - break; - } - for (q = N0; q <= paras.Nmax; q += paras.L) - if (p_cc->coeff[q - paras.Nmin] < 0.0) { - zx_rht_N = q; - break; - } - /* define small region around peak */ - if (N0 - paras.L < paras.Nmin) { - N1 = N0; - N2 = N0 + 2 * paras.L; - } - else if (N0 + paras.L > paras.Nmax) { - N1 = N0 - 2 * paras.L; - N2 = N0; - } - else { - N1 = N0 - paras.L; - N2 = N0 + paras.L; - } - /* compensate for decimation factor L */ - if (paras.L != 1) { - xx = yy = xy = 0.0; - for (j = 0; j < N1; j++) { - x_index = paras.Nmax - N1 + j; - y_index = paras.Nmax + j; - xx += (double) seg.data[x_index] * seg.data[x_index]; - xy += (double) seg.data[x_index] * seg.data[y_index]; - yy += (double) seg.data[y_index] * seg.data[y_index]; - } - p_cc->coeff[N1 - paras.Nmin] = p_status->cc_max = - xy / sqrt (xx) / sqrt (yy); - N0 = N1; - for (n = N1 + 1; n <= N2; n++, j++) { - xx += (double) seg.data[paras.Nmax - n] * seg.data[paras.Nmax - n]; - yy += (double) seg.data[paras.Nmax + j] * seg.data[paras.Nmax + j]; - for (k = 0, xy = 0.0; k < n; k++) - xy += (double) seg.data[paras.Nmax - n + k] * seg.data[paras.Nmax + k]; - p_cc->coeff[n - paras.Nmin] = xy / sqrt (xx) / sqrt (yy); - if (p_cc->coeff[n - paras.Nmin] > p_status->cc_max) { - p_status->cc_max = p_cc->coeff[n - paras.Nmin]; - N0 = n; - } - } - } - /* compensate for finite resolution in estimating pitch */ - if (N0 - 1 < paras.Nmin || N0 == N1) N_ = N0; - else if (N0 + 1 > paras.Nmax || N0 == N2) N_ = N0 - 1; - else if (p_cc->coeff[N0 - paras.Nmin] - p_cc->coeff[N0 - paras.Nmin - 1] < - p_cc->coeff[N0 - paras.Nmin] - p_cc->coeff[N0 - paras.Nmin + 1]) - N_ = N0 - 1; - else - N_ = N0; - xx_N = yy_N = xy_N = y1y1_N = xy1_N = yy1_N = 0.0; - for (j = 0; j < N_; j++) { - x_index = paras.Nmax - N_ + j; - y_index = paras.Nmax + j; - xx_N += (double) seg.data[x_index] * seg.data[x_index]; - yy_N += (double) seg.data[y_index] * seg.data[y_index]; - xy_N += (double) seg.data[x_index] * seg.data[y_index]; - y1y1_N += (double) seg.data[y_index + 1] * seg.data[y_index + 1]; - xy1_N += (double) seg.data[x_index] * seg.data[y_index + 1]; - yy1_N += (double) seg.data[y_index] * seg.data[y_index + 1]; - } - beta = (xy1_N * yy_N - xy_N * yy1_N) / - (xy1_N * (yy_N - yy1_N) + xy_N * (y1y1_N - yy1_N)); - if (beta < 0.0) { - N_--; - beta = 0.0; - } - else if (beta >= 1.0) { - N_++; - beta = 0.0; - } - else - p_status->cc_max = ((1.0 - beta) * xy_N + beta * xy1_N) / - sqrt (xx_N * ((1.0 - beta) * (1.0 - beta) * yy_N + - 2.0 * beta * (1.0 - beta) * yy1_N + - beta * beta * y1y1_N)); - prev_pf = p_status->pitch_freq; - p_status->pitch_freq = (double) (paras.sample_freq) / (double) (N_ + beta); - p_status->v_uv = VOICED; - free_list (&sig_pks_hd); - return; - -} - - - -DetectPitch::DetectPitch() -{ - m_pSrpdOp = new Srpd_Op; - m_pSegment = new SEGMENT_; - m_iSamplesFilledInSegment = 0; - m_pCC = new CROSS_CORR_; - m_pPdaStatus = new STATUS_; -} - -DetectPitch::~DetectPitch() -{ - SAFE_DELETE( m_pSrpdOp ); - SAFE_DELETE( m_pSegment ); - m_iSamplesFilledInSegment = 0; - SAFE_DELETE( m_pCC ); - SAFE_DELETE( m_pPdaStatus ); -} - -void DetectPitch::Init(int iSampleFreq) -{ - default_srpd_op(m_pSrpdOp); // default values - - m_pSrpdOp->sample_freq = iSampleFreq; - initialise_structures (m_pSrpdOp, m_pSegment, m_pCC); - for( int i=0; isize; ++i ) - m_pCC->coeff[i] = 0.0; - initialise_status (*m_pSrpdOp, m_pPdaStatus); - - // add a low-pass filter? -} - -int DetectPitch::ReadOne(RageSoundReader_FileReader *sample) -{ - if( read_next_wave_segment2 (sample, *m_pSrpdOp, m_pSegment) != 0 ) - { - super_resolution_pda (*m_pSrpdOp, *m_pSegment, m_pCC, m_pPdaStatus); - - printf( "track set: (of %d) is %f - voiced %d, held %d\n", m_pSegment->length, m_pPdaStatus->pitch_freq, m_pPdaStatus->v_uv, m_pPdaStatus->s_h ); - return true; - } - - end_structure_use (m_pSegment, m_pCC); - return false; -} - -int DetectPitch::ReadOne(short *pData, int iCount) -{ - //printf("read: size %d shift %d length %d\n", m_pSegment->size, m_pSegment->shift, m_pSegment->length); - - for( int iDataReadCount = 0; iDataReadCount < iCount; ) - { - int iSamplesLeftInSegment = m_pSegment->size - m_iSamplesFilledInSegment; - int iSamplesLeftInData = iCount - iDataReadCount; - int iSamplesToCopy = min( iSamplesLeftInSegment, iSamplesLeftInData ); - - memcpy( m_pSegment->data + m_iSamplesFilledInSegment, pData + iDataReadCount, iSamplesToCopy*sizeof(short) ); - - m_iSamplesFilledInSegment += iSamplesToCopy; - iDataReadCount += iSamplesToCopy; - - ASSERT( m_iSamplesFilledInSegment <= m_pSegment->size ); - if( m_iSamplesFilledInSegment == m_pSegment->size ) // segment is full - { - super_resolution_pda (*m_pSrpdOp, *m_pSegment, m_pCC, m_pPdaStatus); - //printf( "track set: (of %d) is %f - voiced %d, held %d\n", m_pSegment->length, m_pPdaStatus->pitch_freq, m_pPdaStatus->v_uv, m_pPdaStatus->s_h ); - //printf( "v %d, h %d ", m_pPdaStatus->v_uv, m_pPdaStatus->s_h ); - const int iNumBars = 30; - for( int i=0; ipitch_freq < freq) ? "|" : "X" ); - } - //printf( "\n" ); - - int iNumSamplesToShift = m_pSegment->size - m_pSegment->shift; - m_iSamplesFilledInSegment = iNumSamplesToShift; - memcpy( m_pSegment->data, m_pSegment->data + m_pSegment->shift, iNumSamplesToShift*sizeof(short) ); - } - - } - return true; -} - -void DetectPitch::GetStatus( MicrophoneStatus &out ) -{ - out.fFreq = m_pPdaStatus->pitch_freq; - out.fMaxFreq = m_pSrpdOp->max_pitch; - out.bVoiced = m_pPdaStatus->v_uv == VOICED; -} - -void DetectPitch::End() -{ - end_structure_use (m_pSegment, m_pCC); -} - - -void srpd2() -{ - RageFile file; - file.Open( "speech-test.wav" ); - RageSoundReader_FileReader *sample = new RageSoundReader_WAV; - sample->Open( &file ); - - DetectPitch dp; - dp.Init( SAMPLES_PER_SEC ); - while( dp.ReadOne(sample) ) - { - - } -} - - - -/* - * (c) 2007 Chris Danford - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ + +#include "global.h" +#include "RageUtil.h" +#include "RageLog.h" +#include "RageSoundReader_WAV.h" +#include "RageSurface_Load.h" +#include "PitchDetectionTestUtil.h" +#include "EST_String.h" +#include "EST_Chunk.h" +#include "EST_Val.h" +#include "EST_Features.h" +#include "EST_Token.h" +#include "EST_Option.h" +#include "EST_Track.h" +#include "PitchDetectionTest.h" + +// EST Library: http://www.cstr.ed.ac.uk/projects/speech_tools/ +// "pda" executable options: http://festvox.org/docs/speech_tools-1.2.0/x2152.htm +// Autocorrelation explanation: http://cnx.org/content/m11714/latest/ +// PDA algorithm tradeoffs: http://www-scf.usc.edu/~chinghuc/pitch_detection_algorithms.htm +// MIDI note numbers: http://tomscarff.tripod.com/midi_analyser/midi_note_frequency.htm +// MIDI note numbers: http://www.sengpielaudio.com/calculator-notenames.htm + +EST_String::EST_String(const char *s) +{ + CHECK_STRING_ARG(s); + + size=safe_strlen(s); + + if (size != 0) + memory = chunk_allocate(size+1, s, size); + else + memory=NULL; +} + +void EST_Chunk::operator delete (void *it) +{ + +#if defined(__CHUNK_USE_WALLOC__) + wfree(it); +#else + delete it; +#endif + +} + +val_type val_unset = "unset"; +val_type val_int = "int"; +val_type val_float = "float"; +val_type val_string = "string"; + +#define VAL_REGISTER_CLASS_DCLS(NAME,CLASS) \ +extern val_type val_type_##NAME; \ +class CLASS *NAME(const EST_Val &v); \ +EST_Val est_val(const class CLASS *v); + +VAL_REGISTER_CLASS_DCLS(feats,EST_Features) + + +#define VAL_REGISTER_CLASS(NAME,CLASS) \ +val_type val_type_##NAME=#NAME; \ +class CLASS *NAME(const EST_Val &v) \ +{ \ + if (v.type() == val_type_##NAME) \ + return (class CLASS *)v.internal_ptr(); \ + else \ + exit(1); /*EST_error("val not of type val_type_"#NAME);*/ \ + return NULL; \ +} \ + \ +static void val_delete_##NAME(void *v) \ +{ \ + delete (class CLASS *)v; \ +} \ + \ +EST_Val est_val(const class CLASS *v) \ +{ \ + return EST_Val(val_type_##NAME, \ + (void *)v,val_delete_##NAME); \ +} \ + +VAL_REGISTER_CLASS(feats,EST_Features) + + +EST_Val::~EST_Val(void) +{ + if ((t != val_int) && + (t != val_float) && + (t != val_unset) && + (t != val_string)) + delete v.pval; +} + + +EST_Chunk::~EST_Chunk () +{ + if (count > 0) + { + //cerr << "deleting chunk with non-zero count\n"; + exit(1); + } + // cerr << "deleted "<< hex << (int)&memory << "," << dec << size <<"\n"; +} + +void EST_Features::set_path(const EST_String &name, const EST_Val &sval) +{ + // Builds sub features (if necessary) + + if (strchr(name,'.') == NULL) + set_val(name,sval); + else + { + EST_String nname = name; + EST_String fname = nname.before("."); + if (present(fname)) + { + const EST_Val &v = val(fname); + if (v.type() == val_type_feats) + feats(v)->set_path(nname.after("."),sval); + else + exit(1);//EST_error("Feature %s not feature valued\n", + // (const char *)fname); + } + else + { + EST_Features f; + set(fname,f); + A(fname).set_path(nname.after("."),sval); + } + } +} + + + +template +V &EST_TKVL::val(const K &rkey, int must) +{ + EST_Litem *ptr = find_pair_key(rkey); + + if (ptr == 0) + { + if (must) + EST_error("No value set for '%s'", error_name(rkey)); + + return *default_val; + } + else + return list.item(ptr).v; +} + +EST_String &EST_TKVL::val(const EST_String &rkey, int must) +{ + EST_Litem *ptr = find_pair_key(rkey); + + if (ptr == 0) + { + if (must) + exit(1);//EST_error("No value set for '%s'", error_name(rkey)); + + return *default_val; + } + else + return list.item(ptr).v; +} + + +template +int EST_TKVL::add_item(const K &rkey, const V &rval, int no_search) +{ + if (!no_search) + if (change_val(rkey, rval)) // first see if key exists + return 1; + + EST_TKVI item; + item.k = rkey; + item.v = rval; + + list.append(item); + return 1; +} + +int EST_TKVL::add_item(const EST_String &rkey, const EST_String &rval, int no_search) +{ + if (!no_search) + if (change_val(rkey, rval)) // first see if key exists + return 1; + + EST_TKVI item; + item.k = rkey; + item.v = rval; + + list.append(item); + return 1; +} + +template +const int EST_TKVL::present(const K &rkey) const +{ + if (find_pair_key(rkey) == 0) + return 0; + else + return 1; +} + +const int EST_TKVL::present(const EST_String &rkey) const +{ + if (find_pair_key(rkey) == 0) + return 0; + else + return 1; +} + + +static const EST_String Empty_String(""); + + +int EST_Option::ival(const EST_String &rkey, int must) const +{ + const EST_String &tval = val_def(rkey, Empty_String); + if (tval != "") + return atoi(tval); + + if (must) + exit(1);//cerr << "EST_Option: No value set for " << rkey << endl; + return 0; +} + +EST_String &EST_String::operator = (const char *str) +{ + CHECK_STRING_ARG(str); + int len = safe_strlen(str); + if (!len) + memory = NULL; + else if (!shareing() && len < size) + memcpy((char *)memory, str, len+1); + else if (len) + memory = chunk_allocate(len+1, str, len); + size=len; + return *this; +} + +EST_String &EST_String::operator = (const char c) +{ + memory = chunk_allocate(2, &c, 1); + size=1; + return *this; +} + +EST_String &EST_String::operator = (const EST_String &s) +{ +#if 1 + static EST_ChunkPtr hack = s.memory; + memory = NON_CONST_CHUNKPTR(s.memory); + size = s.size; +#else + *(struct EST_dumb_string *)this = *(struct EST_dumb_string *)(&s); +#endif + return *this; +} + +int operator == (const char *a, const EST_String &b) +{ + CHECK_STRING_ARG(a); + + if (!a) + return 0; + else if (b.size==0) + return *a == '\0'; + else + return (*a == b(0)) && strcmp(a, b.str())==0; +} + +const EST_Val &EST_Features::val_path(const EST_String &name, const EST_Val &d) const +{ + // For when name contains references to sub-features + + if (strchr(name,'.') == NULL) + return val(name, d); + else + { + EST_String nname = name; + EST_String fname = nname.before("."); + const EST_Val &v = val(fname, d); + if (v.type() == val_type_feats) + return feats(v)->val_path(nname.after("."), d); + else + return d; + } +} + +EST_String itoString(int n) +{ + char tmp[1000]; + + sprintf(tmp, "%d", n); + return EST_String(tmp); +} + +EST_String ftoString(float n, int pres=3, int width=0, int right_justify=0) +{ + (void)right_justify; + EST_String val; + char tmp[1000]; + char spec[10]; + strcpy(spec, "%"); + if (width != 0) + strcat(spec, itoString(width)); + strcat(spec, "."); + strcat(spec, itoString(pres)); + strcat(spec, "f"); + + sprintf(tmp, spec, n); + val = tmp; + return val; +} + + +const EST_String &EST_Val::to_str(void) const +{ + // coerce this to and save it for later + // This requires the following casting, so we can still tell the + // compiler this is a const function. If this was properly declared + // non-const vast amounts of the rest of this would also have to be + // non-const. So we do one nasty bit here for uniformity elsewhere. + // Not saving the result is also a possibility but probably too + // inefficient (maybe not with rjc's string class) + EST_String *n = (EST_String *)((void *)&sval); + if (t==val_int) + *n = itoString(v.ival); + else if (t==val_float) + { + if (v.fval == 0) + *n = "0"; // to be compatible with other's notion of fstrings + else + *n = ftoString(v.fval); + } + else if (t != val_string) + *n = EST_String("[Val ")+t+"]"; + + return sval; +} + +int EST_Features::present(const EST_String &name) const +{ + if (strchr(name,'.') == NULL) + return features->present(name); + EST_String nname = name; + if (features->present(nname.before("."))) + { + const EST_Val &v = val(nname.before(".")); + if (v.type() == val_type_feats) + return feats(v)->present(nname.after(".")); + else + return FALSE; + } + else + return FALSE; +} + +const EST_Val &EST_Features::val_path(const EST_String &name) const +{ + // For when name contains references to sub-features + + if (strchr(name,'.') == NULL) + return val(name); + else + { + EST_String nname = name; + EST_String fname = nname.before("."); + const EST_Val &v = val(fname); + if (v.type() == val_type_feats) + return feats(v)->val_path(nname.after(".")); + else + exit(1);//EST_error("Feature %s not feature valued\n", (const char *)fname); + return feature_default_value; // wont get here + } +} + +EST_Track::~EST_Track(void) +{ + // clear_features(); +} + +void EST_Track::default_channel_names() +{ + for (int i = 0; i < num_channels(); ++i) + set_channel_name("track" + itoString(i), i); +} + +EST_Track::EST_Track() +{ + default_vals(); +} + +int fastlog2(int n) { + int num_bits, power = 0; + + if ((n < 2) || (n % 2 != 0)) return(0); + num_bits = sizeof(int) * 8; /* How big are ints on this machine? */ + + while(power <= num_bits) { + n >>= 1; + power += 1; + if (n & 0x01) { + if (n > 1) return(0); + else return(power); + } + } + return(0); +} + +#define PI 3.14159265358979323846 + +static int slowFFTsub(EST_FVector &real, EST_FVector &imag, float f) +{ + // f = -1 for FFT, 1 for IFFT + // would be nicer if we used a complex number class, + // but we don't, so it isn't + + // taken from the FORTRAN old chestnut + // in various sig proc books + // FORTRAN uses 1..n arrays, so subtract 1 all over the place + + + float u_real,u_imag; + float w_real,w_imag; + float t_real,t_imag; + float tmp_real,tmp_imag; + + int M,N; + int i,j,k,l; + + M = fastlog2(real.n()); + N = (int)powf(2,(float)M); + + if (N != real.n()) + { + exit(1);//EST_warning("Illegal FFT order %d", real.n()); + return -1; + } + + for(l=1;l<=M;l++){ + + int le = (int)powf(2,(float)(M+1-l)); + int le1=le/2; + + u_real = 1.0; + u_imag = 0.0; + + w_real=cos(PI/le1); + w_imag=f * sin(PI/le1); + + for (j=1;j<=le1;j++) + { + for (i=j;i<=N-le1;i+=le) + { + int ip=i+le1; + t_real = real.a_no_check(i-1) + real.a_no_check(ip-1); + t_imag = imag.a_no_check(i-1) + imag.a_no_check(ip-1); + + tmp_real = real.a_no_check(i-1) - real.a_no_check(ip-1); + tmp_imag = imag.a_no_check(i-1) - imag.a_no_check(ip-1); + + real.a_no_check(ip-1) = tmp_real*u_real - tmp_imag*u_imag; + imag.a_no_check(ip-1) = tmp_real*u_imag + tmp_imag*u_real; + + real.a_no_check(i-1) = t_real; + imag.a_no_check(i-1) = t_imag; + } + + tmp_real = u_real*w_real - u_imag*w_imag; + tmp_imag = u_real*w_imag + u_imag*w_real; + + u_real=tmp_real; + u_imag=tmp_imag; + + } + + } + + + int NV2=N/2; + int NM1=N-1; + j=1; + + + for (i=1; i<=NM1;i++) + { + if (i < j) + { + t_real=real(j-1); + t_imag=imag(j-1); + + real[j-1] = real(i-1); + imag[j-1] = imag(i-1); + + real[i-1] = t_real; + imag[i-1] = t_imag; + + } + + k=NV2; + + while(k < j) + { + j=j-k; + k=k/2; + } + + j=j+k; + + } + + return 0; +} + +int slowIFFT(EST_FVector &real, EST_FVector &imag) +{ + int N=real.n(); + if (N <=0 ) + return -1; + + if (slowFFTsub(real,imag,1.0) != 0) + return -1; + + for(int i=1;i<=N;i++){ + real[i-1] /= (float)N; + imag[i-1] /= (float)N; + } + + return 0; +} + + +EST_FVector design_FIR_filter(const EST_FVector &frequency_response, + int filter_order) +{ + // frequency_response contains the desired filter reponse, + // on a scale 0...sampling frequency + + // check filter_order is odd + if((filter_order & 1) == 0){ + cerr << "Requested filter order must be odd" << endl; + return EST_FVector(0); + } + + // check frequency_response has dimension 2^N + int N = fastlog2(frequency_response.n()); + if(frequency_response.n() != (int)powf(2,(float)N)){ + cerr << "Desired frequency response must have dimension 2^N" << endl; + return EST_FVector(0); + } + + int i; + EST_FVector filt(frequency_response); + EST_FVector dummy(frequency_response.n()); + for(i=0;ismooth_double = FALSE; + ms->apply_hanning = TRUE; + ms->extrapolate = TRUE; + ms->first_median = 11; + ms->second_median = 1; + ms->window_length = 7; + ms->breaker = -1.0; + return (ms); +} + +int parse_ms_list(EST_Features &al, struct Ms_Op *ms) +{ + default_ms_op(ms); + + if (al.present("smooth_double")) + ms->smooth_double = al.I("smooth_double"); + if (al.present( "hanning")) + ms->apply_hanning = al.I("hanning"); + if (al.present("extrapolate")) + ms->extrapolate = al.I("extrapolate"); + if (al.present("first_length")) + ms->first_median = al.I("first_length"); + if (al.present("second_length")) + ms->second_median = al.I("second_length"); + if (al.present("window_length")) + ms->window_length = al.I("window_length"); + + return 0; +} + +#define MAX_LEN 127 + +#define TWO_PI 6.28318530717958647698 + +void mk_window_coeffs (int length, float win_coeff[]) +{ + int i; + double x; + + for (i = 0; i < length; i++) { + x = TWO_PI * (i + 1.0) / (length + 1.0); + win_coeff[i] = (1.0 - (float) cos (x)) / (length + 1.0); + } + +} + +float median (int *counter, float valin, float valbuf[], int lmed, int mmed) +{ + int i, j; + float tmp, filmed[MAX_LEN]; + + for (i = lmed - 1; i > 0; i--) + valbuf[i] = valbuf[i - 1]; + valbuf[0] = valin; + + if (*counter > 0) + { + (*counter)--; + return (0.0); + } + else + { + *counter = -1; + + for (i = 0; i < lmed; i++) + filmed[i] = valbuf[i]; + + for (j = lmed - 1; j > 0; j--) + for (i = 0; i < j; i++) + if (filmed[i] > filmed[i + 1]) + { + tmp = filmed[i + 1]; + filmed[i + 1] = filmed[i]; + filmed[i] = tmp; + } + return (filmed[mmed]); + } + +} + +float hanning (int *counter, float valin, float valhan[], float win_coeff[], + struct Ms_Op *par) +{ + int i, j, k = 0; + float valout = 0.0, weight[MAX_LEN]; + + for (i = par->window_length - 1; i > 0; i--) + valhan[i] = valhan[i - 1]; + valhan[0] = valin; + if (*counter > 0) { + (*counter)--; + return (0.0); + } + else { + *counter = -1; + for (i = 0; i < par->window_length; i++) + if (valhan[i] == par->breaker) + k++; + if (!k) + for (i = 0; i < par->window_length; i++) + valout += valhan[i] * win_coeff[i]; + else if (k <= par->window_length / 2 && par->extrapolate) { + mk_window_coeffs (par->window_length - k, weight); + for (i = 0, j = 0; i < par->window_length; i++) + if (valhan[i] != par->breaker) + valout += valhan[i] * weight[j++]; + } + else + valout = par->breaker; + return (valout); + } + +} + + +void array_smoother (float *p_array, int arraylen, struct Ms_Op *ms) +{ + int i, j, mid1, mid2 = 0, filler, nloops; + int C1, C2 = 0, C3 = 0, C4 = 0, c1, c2, c3, c4; + int delay, delx = 0, dely = 0; + int in = 0, out = 0; + float input, output; + float *inarray; + float xdel[2 * MAX_LEN - 2], ydel[2 * MAX_LEN - 2]; + float medbuf1[MAX_LEN], medbuf2[MAX_LEN]; + float hanbuf1[MAX_LEN], hanbuf2[MAX_LEN], win_coeffs[MAX_LEN]; + float medval1, medval2, hanval1, hanval2, zatn; + + inarray = new float[arraylen]; + for (i = 0; i < arraylen; ++i) + inarray[i] = p_array[i]; + + if (ms == NULL) + { + ms = new Ms_Op; + default_ms_op(ms); + } + + mk_window_coeffs (ms->window_length, win_coeffs); + /* determine the size and delay of each stage concerned */ + mid1 = ms->first_median / 2; + C1 = delay = ms->first_median - 1; + if (ms->apply_hanning) + { + C2 = ms->window_length - 1; + delay = ms->first_median + ms->window_length - 2; + } + if (ms->smooth_double) { + mid2 = ms->second_median / 2; + C3 = ms->second_median - 1; + if (!ms->apply_hanning) { + delx = ms->first_median; + dely = ms->second_median; + } + else { + C4 = ms->window_length - 1; + delx = ms->first_median + ms->window_length - 1; + dely = ms->second_median + ms->window_length - 1; + } + delay = delx + dely - 2; + } + /* prepare for smoothing */ + c1 = C1; + c2 = C2; + c3 = C3; + c4 = C4; + if (!ms->extrapolate) { + /* pad with breakers at the beginning */ + for (i = 0; i < delay / 2; i++) + p_array[out++] = ms->breaker; + filler = 0; + nloops = arraylen; + } + else { + /* extrapolate by initialising filter with dummy breakers */ + filler = delay / 2; + nloops = arraylen + delay; + } + /* smooth track element by track element */ + for (j = 0; j < nloops; j++) + { + if (j < filler || j >= nloops - filler) + input = ms->breaker; + else + input = inarray[in++]; + + /* store input value if double smoothing */ + if (ms->smooth_double) { + for (i = delx - 1; i > 0; i--) + xdel[i] = xdel[i - 1]; + xdel[0] = input; + } + /* first median smoothing */ + + medval1 = median (&c1, input, medbuf1, ms->first_median, mid1); + + if (c1 == -1) + { + output = medval1; + /* first hanning window (optional) */ + if (ms->apply_hanning) + { + hanval1 = hanning (&c2, medval1, hanbuf1, win_coeffs, ms); + if (c2 == -1) + output = hanval1; + else + continue; + } + /* procedures for double smoothing (optional) */ + if (ms->smooth_double) + { + /* compute rough component z(n) */ + if (output != ms->breaker && xdel[delx - 1] + != ms->breaker) + zatn = xdel[delx - 1] - output; + else + zatn = ms->breaker; + /* store results of first smoothing */ + for (i = dely - 1; i > 0; i--) + ydel[i] = ydel[i - 1]; + ydel[0] = output; + /* second median smoothing */ + medval2 = median (&c3, zatn, medbuf2, + ms->second_median, mid2); + if (c3 == -1) + { + output = medval2; + /* second hanning smoothing (optional) */ + if (ms->apply_hanning) { + hanval2 = hanning (&c4, medval2, hanbuf2, + win_coeffs, ms); + if (c4 == -1) + output = hanval2; + else + continue; + } + if (output != ms->breaker && ydel[dely - 1] + != ms->breaker) + output += ydel[dely - 1]; + else + output = ms->breaker; + } + else + continue; + } + /* write filtered result */ + p_array[out++] = output; + } + } + if (!ms->extrapolate) /* pad with breakers at the end */ + for (i = 0; i < delay / 2; i++) + p_array[out++] = ms->breaker; + + delete inarray; +} + +void smooth_portion(EST_Track &c, EST_Features &op) +{ + int i; + float *a; // need float * so it can be passed to array_smoother + struct Ms_Op *ms; + ms = new Ms_Op; + + default_ms_op(ms); + parse_ms_list(op, ms); + + if (op.present("point_window_size")) + ms->window_length = op.I("point_window_size"); + + a = new float[c.num_frames()]; + + for (i = 0; i < c.num_frames(); ++i) + a[i] = c.track_break(i) ? -1.0 : c.a(i); + + array_smoother(a, c.num_frames(), ms); + + for (i = 0; i < c.num_frames(); ++i) + { // occasionally NaNs result... + if (isnanf(a[i])) + { + c.set_break(i); + c.a(i) = 0.0; + } + else + { + if (a[i] < 0.0) + c.set_break(i); + else + c.set_value(i); + c.a(i) = a[i]; + } + } + + delete a; +} + +static void interp(const EST_Track &c, const EST_Track &speech, int fill, + EST_Track &interp) +{ + // Interpolate between unvoiced sections, and ensure breaks + // during silences + int i, n, p; + float m; + float n_val, p_val; + float f = c.shift(); + + interp = c; // copy track + + if (speech.num_frames() < c.num_frames()) + interp.resize(speech.num_frames(), interp.num_channels()); + + + for (i = 1; i < interp.num_frames(); ++i) + { + if ((fill == 1) || (speech.a(i) > 0.5)) + { + if (!interp.track_break(i)) + continue; // already has a value + + p = i - 1; + if ((n = interp.next_non_break(i)) == 0) + n = interp.num_frames() - 1; + n_val = interp.a(n); + p_val = interp.a(p); + if (n_val <= 0) n_val = p_val; + if (p_val <= 0) p_val = n_val; + // if they are both zero, well we'll learn to live it. + m = (n_val - p_val) / ( interp.t(n) - interp.t(p)); + + interp.a(i) = (m * f) + p_val; + interp.set_value(i); + } + else + interp.set_break(i); + } +} + +void smooth_phrase(EST_Track &fz, EST_Track &speech, EST_Features &op, + EST_Track &smi_fz) +{ + int n=0; + EST_Track sm_fz; + char nstring[10]; + + if (fz.empty()) + { + smi_fz = fz; + return; + } + sm_fz = fz; + sm_fz.set_channel_name("F0", 0); + + n = (int)(op.F("window_length") / fz.shift()); + sprintf(nstring, "%d", n); + op.set("point_window_size", nstring); + + if (!op.present("icda_no_smooth")) + smooth_portion(sm_fz, op); + + if (op.present("icda_no_interp")) + { + sm_fz = fz; + return; // no unvoiced interpolation + } + + int fill = op.present("icda_fi") ? 1 : 0; + interp(sm_fz, speech, fill, smi_fz); // fill unvoiced region + + n = (int)(op.F("second_length") / fz.shift()); + sprintf(nstring, "%d", n); + op.set("point_window_size", nstring); + + if (!op.present("icda_no_smooth")) + smooth_portion(smi_fz, op); +} + +const int EST_Val::to_int(void) const +{ + // coerce this to an int + if (t==val_float) + return (int)v.fval; + else if (t==val_string) + return atoi(sval); + else + return v.ival; // just for completeness +} + +struct SEGMENT_ +{ /* segment of speech data */ + int size, shift, length; /* in samples */ + short *data; +}; + +struct CROSS_CORR_ +{ + int size; + double *coeff; +}; + + +void end_structure_use(SEGMENT_ *p_seg, CROSS_CORR_ *p_cc) +{ + + wfree (p_seg->data); + wfree (p_cc->coeff); + return; + +} + +static bool bounds_check(const EST_Track &t, int f, int c, int set) +{ + const char *what = set? "set" : "access"; + + if (f<0 || f >= t.num_frames()) + { + cerr << "Attempt to " << what << " frame " << f << " of " << t.num_frames() << " frame track\n"; + return FALSE; + } + if (c<0 || c >= t.num_channels()) + { + cerr << "Attempt to " << what << " channel " << c << " of " << t.num_channels() << " channel track\n"; + return FALSE; + } + +return TRUE; +} + + +float &EST_Track::a(int i, int c) +{ + if (!bounds_check(*this, i,c,0)) + return *(p_values.error_return); + + return p_values.a_no_check(i,c); +} + +EST_ChunkPtr chunk_allocate(int bytes, const char *initial, int initial_len) +{ + if (initial_len >= bytes) + { + cerr<<"initialiser too long\n"; + abort(); + } + + EST_Chunk *cp = new(bytes) EST_Chunk; + + memcpy(cp->memory, initial, initial_len); + + cp->memory[initial_len] = '\0'; + + return (EST_ChunkPtr)cp; +} + +void wfree(void *p) +{ + if (p != NULL) + free(p); +} + +EST_Features::EST_Features() +{ + features = new EST_TKVL; +} + +EST_Features::~EST_Features() +{ + if (features != NULL) + { + delete features; + features=NULL; + } +} + +const EST_Val &EST_Features::val(const char *name) const +{ + // Because so many access are from char* literals we all access + // directly rather than requiring the creation of an EST_String + EST_Litem *p; + + for (p=features->list.head(); p; p=next(p)) + { + if (features->list(p).k == name) + return features->list(p).v; + } + + exit(1);//EST_error("{FND} Feature %s not defined\n", name); + return feature_default_value; +} + +EST_String EST_String::chop_internal(const char *it, int len, int from, EST_chop_direction mode) const +{ + CHECK_STRING_ARG(it); + + int start, end; + + if (it && locate(it, len, from, start, end)) + switch (mode) + { + case Chop_Before: + return EST_String(str(), size, 0, start); break; + case Chop_At: + return EST_String(str(), size, start, end-start); break; + case Chop_After: + return EST_String(str(), size, end, -1); + } + return EST_String(); + +} + +EST_Val::EST_Val(val_type type,void *p, void (*f)(void *)) +{ + t=type; + v.pval = new EST_Contents; + v.pval->set_contents(p,f); +} + +EST_Features::EST_Features(const EST_Features &f) +{ + features = new EST_TKVL; + *features = *f.features; +} + +void EST_TokenStream::close(void) +{ + // close any files (if they were used) + + switch (type) + { + case tst_none: + break; + case tst_file: + if (close_at_end) + fclose(fp); + case tst_pipe: + // close(fd); + break; + case tst_istream: + break; + case tst_string: + delete [] buffer; + buffer = 0; + break; + default: + cerr << "EST_TokenStream: unknown type" << endl; + break; + } + + type = tst_none; + peeked_charp = FALSE; + peeked_tokp = FALSE; + +} + +EST_TokenStream::~EST_TokenStream() +{ + if (type != tst_none) + close(); + delete [] tok_wspace; + delete [] tok_stuff; + delete [] tok_prepuncs; + +} + +int EST_TokenStream::open(const EST_String &filename) +{ + if (type != tst_none) + close(); + default_values(); + fp = fopen(filename,"rb"); + if (fp == NULL) + { + exit(1);//cerr << "Cannot open file " << filename << " as tokenstream" + // << endl; + return -1; + } + Origin = filename; + type = tst_file; + + return 0; +} + +const EST_String Token_Origin_FD = "existing file descriptor"; + +int EST_TokenStream::open(FILE *ofp, int close_when_finished) +{ + // absorb already open stream + if (type != tst_none) + close(); + default_values(); + fp = ofp; + if (fp == NULL) + { + cerr << "Cannot absorb NULL filestream as tokenstream" << endl; + return -1; + } + Origin = Token_Origin_FD; + type = tst_file; + + close_at_end = close_when_finished; + + return 0; +} + +EST_TokenStream::EST_TokenStream() +{ + tok_wspacelen = 64; // will grow if necessary + tok_wspace = new char[tok_wspacelen]; + tok_stufflen = 512; // will grow if necessary + tok_stuff = new char[tok_stufflen]; + tok_prepuncslen = 32; // will grow if necessary + tok_prepuncs = new char[tok_prepuncslen]; + + default_values(); +} + + + + + + + + + + + +#define Instantiate_KVL_T(KEY, VAL, TAG) \ + template class EST_TKVL; \ + template class EST_TKVI; \ + ostream &operator<<(ostream &s, EST_TKVI< KEY , VAL > const &i){ return s << i.k << "\t" << i.v << "\n"; } \ + ostream& operator << (ostream& s, EST_TKVL< KEY , VAL > const &l) {EST_Litem *p; for (p = l.list.head(); p ; p = next(p)) s << l.list(p).k << "\t" << l.list(p).v << endl; return s;} \ + Instantiate_TIterator_T(KVL_ ## TAG ## _t, KVL_ ## TAG ## _t::IPointer_k, KEY, KVL_ ## TAG ##_kitt) \ + Instantiate_TStructIterator_T(KVL_ ## TAG ## _t, KVL_ ## TAG ## _t::IPointer, KVI_ ## TAG ## _t, KVL_ ## TAG ##_itt) \ + Instantiate_TIterator_T(KVL_ ## TAG ## _t, KVL_ ## TAG ## _t::IPointer, KVI_ ## TAG ## _t, KVL_ ## TAG ##_itt) \ + Instantiate_TList(KVI_ ## TAG ## _t) + +// template ostream & operator<<(ostream &s, EST_TKVI const &i); + +#define Instantiate_KVL(KEY, VAL) \ + Instantiate_KVL_T(KEY, VAL, KEY ## VAL) + +#define Declare_KVL_TN(KEY, VAL, MaxFree, TAG) \ + typedef EST_TKVI KVI_ ## TAG ## _t; \ + typedef EST_TKVL KVL_ ## TAG ## _t; \ + \ + static VAL TAG##_kv_def_val_s; \ + static KEY TAG##_kv_def_key_s; \ + \ + template <> VAL *EST_TKVL< KEY, VAL >::default_val=&TAG##_kv_def_val_s; \ + template <> KEY *EST_TKVL< KEY, VAL >::default_key=&TAG##_kv_def_key_s; \ + \ + Declare_TList_N(KVI_ ## TAG ## _t, MaxFree) +#define Declare_KVL_T(KEY, VAL, TAG) \ + Declare_KVL_TN(KEY, VAL, 0, TAG) + +#define Declare_KVL_Base_TN(KEY, VAL, DEFV, DEFK, MaxFree, TAG) \ + typedef EST_TKVI KVI_ ## TAG ## _t; \ + typedef EST_TKVL KVL_ ## TAG ## _t; \ + \ + static VAL TAG##_kv_def_val_s=DEFV; \ + static KEY TAG##_kv_def_key_s=DEFK; \ + \ + template <> VAL *EST_TKVL< KEY, VAL >::default_val=&TAG##_kv_def_val_s; \ + template <> KEY *EST_TKVL< KEY, VAL >::default_key=&TAG##_kv_def_key_s; \ + \ + Declare_TList_N(KVI_ ## TAG ## _t, MaxFree) +#define Declare_KVL_Base_T(KEY, VAL, DEFV, DEFK, TAG) \ + Declare_KVL_Base_TN(KEY, VAL, DEFV, DEFK, 0, TAG) + +#define Declare_KVL_Class_TN(KEY, VAL, DEFV, DEFK, MaxFree, TAG) \ + typedef EST_TKVI KVI_ ## TAG ## _t; \ + typedef EST_TKVL KVL_ ## TAG ## _t; \ + \ + static VAL TAG##_kv_def_val_s(DEFV); \ + static KEY TAG##_kv_def_key_s(DEFK); \ + \ + template <> VAL *EST_TKVL< KEY, VAL >::default_val=&TAG##_kv_def_val_s; \ + template <> KEY *EST_TKVL< KEY, VAL >::default_key=&TAG##_kv_def_key_s; \ + \ + Declare_TList_N(KVI_ ## TAG ## _t, MaxFree) +#define Declare_KVL_Class_T(KEY, VAL, DEFV, DEFK,TAG) \ + Declare_KVL_Class_TN(KEY, VAL, DEFV, DEFK, 0, TAG) + +#define Declare_KVL_N(KEY, VAL, MaxFree) \ + Declare_KVL_TN(KEY, VAL, MaxFree, KEY ## VAL) +#define Declare_KVL(KEY, VAL) \ + Declare_KVL_N(KEY, VAL, 0) + +#define Declare_KVL_Base_N(KEY, VAL, DEFV, DEFK, MaxFree) \ + Declare_KVL_Base_TN(KEY, VAL, DEFV, DEFK, , MaxFree, KEY ## VAL) +#define Declare_KVL_Base(KEY, VAL, DEFV, DEFK) \ + Declare_KVL_Base_N(KEY, VAL, DEFV, DEFK, 0) + +#define Declare_KVL_Class_N(KEY, VAL, DEFV, DEFK, MaxFree) \ + Declare_KVL_Class_TN(KEY, VAL, DEFV, DEFK, MaxFree, KEY ## VAL) +#define Declare_KVL_Class(KEY, VAL, DEFV, DEFK) \ + Declare_KVL_Class_N(KEY, VAL, DEFV, DEFK, 0) + + + +Declare_KVL(EST_String,EST_String) + +template +EST_Litem *EST_TKVL::find_pair_key(const K &key) const +{ + EST_Litem *ptr; + + for (ptr = list.head(); ptr != 0; ptr= next(ptr)) + if (list.item(ptr).k == key) + return ptr; + return 0; +} + +// look for key rkey in list. If found, change its value to rval and +// return true, otherwise return false. +template +int EST_TKVL::change_val(const K &rkey,const V &rval) +{ + EST_Litem *ptr=find_pair_key(rkey); + if (ptr == 0) + return 0; + else + { + list.item(ptr).v = rval; + return 1; + } +} + +template +const V &EST_TKVL::val_def(const K &rkey, const V &def) const +{ + EST_Litem *ptr = find_pair_key(rkey); + if (ptr == 0) + return def; + else + return list.item(ptr).v; +} + +void make_updatable(EST_ChunkPtr &cp) +{ + if (cp.ptr && cp.ptr->count > 1) + { + EST_Chunk *newchunk = new(cp.ptr->size) EST_Chunk; + + memcpy(newchunk->memory, cp.ptr->memory, cp.ptr->size); + + cp = newchunk; + } +} + +const EST_Val &EST_Features::val(const char *name, const EST_Val &def) const +{ + // Because so many access are from char* literals we all access + // directly rather than requiring the creation of an EST_String + EST_Litem *p; + + for (p=features->list.head(); p; p=next(p)) + { + if (features->list(p).k == name) + return features->list(p).v; + } + return def; +} + +EST_String operator + (const EST_String &a, const char *b) +{ + CHECK_STRING_ARG(b); + + int al = a.size; + int bl = safe_strlen(b); + + if (al == 0) + return EST_String(b, 0, bl); + if (bl == 0) + return EST_String(a); + + EST_ChunkPtr c = chunk_allocate(al+bl+1, a.str(), al); + + if (bl>0) + memmove((char *)c + al, b, bl); + c(al+bl)='\0'; + + return EST_String(al+bl, c); +} + +EST_Val EST_Features::feature_default_value("0"); + +EST_Featured::~EST_Featured(void) +{ + clear_features(); +} + +template +EST_TMatrix::~EST_TMatrix() +{ + p_num_rows = 0; + p_row_step=0; +} + +template +EST_TVector::~EST_TVector() +{ + p_num_columns = 0; + p_offset=0; + p_column_step=0; + + if (p_memory != NULL && !p_sub_matrix) + { + delete [] (p_memory-p_offset); + p_memory = NULL; + } +} + +void EST_Track::set_channel_name(const EST_String &fn, int i) +{ + p_channel_names[i] = fn; +} + +EST_String operator + (const char *a, const EST_String &b) +{ + CHECK_STRING_ARG(a); + + int al = safe_strlen(a); + int bl = b.size; + + if (bl == 0) + return EST_String(a, 0, al); + if (al == 0) + return EST_String(b); + + EST_ChunkPtr c = chunk_allocate(al+bl+1, a, al); + + memmove((char *)c + al, b.str(), bl); + + c(al+bl)='\0'; + + return EST_String(al+bl, c); +} + +void EST_Track::default_vals(void) +{ + p_equal_space = FALSE; + p_single_break = FALSE; + p_values.resize(0, 0); + p_times.resize(0); + p_is_val.resize(0); + p_aux.resize(0, 0); + p_aux_names.resize(0); + p_channel_names.resize(0); + p_map = NULL; + p_t_offset=0; + + init_features(); +} + +template +EST_TVector::EST_TVector() +{ + default_vals(); +} + +template +EST_TMatrix::EST_TMatrix() +{ + default_vals(); +} + +EST_Featured::EST_Featured(void) +{ + init_features(); +} + +template EST_TSimpleVector::EST_TSimpleVector(const EST_TSimpleVector &in) +{ + this->default_vals(); + copy(in); +} + +void *safe_walloc(int size) +{ + char *p; + + if (size == 0) + /* Some mallocs return NULL for size 0, which means you can't tell + if it failed or not. So we'll avoid that problem by never + asking for 0 bytes */ + p = (char*)calloc(1,1); + else + p = (char*)calloc(size,1); + + if (p == NULL) + { + fprintf(stderr,"WALLOC: failed to malloc %d bytes\n",size); + exit(-1); /* I'd rather not do this but this is the only safe */ + /* thing to do */ + } + + return p; +} + +/* return the lesser of the two values */ +#define Lof(a, b) (((a) < (b)) ? (a) : (b)) + +template +void EST_TSimpleMatrix::resize(int new_rows, + int new_cols, + int set) +{ + T* old_vals=NULL; + int old_offset = this->p_offset; + + if (new_rows<0) + new_rows = this->num_rows(); + if (new_cols<0) + new_cols = this->num_columns(); + + if (set) + { + if (!this->p_sub_matrix && new_cols == this->num_columns() && new_rows != this->num_rows()) + { + int copy_r = Lof(this->num_rows(), new_rows); + + just_resize(new_rows, new_cols, &old_vals); + + memcpy((void *)this->p_memory, + (const void *)old_vals, + copy_r*new_cols*sizeof(T)); + + int i,j; + + if (new_rows > copy_r) + if (*this->def_val == 0) + { + memset((void *)(this->p_memory + copy_r*this->p_row_step), + 0, + (new_rows-copy_r)*new_cols*sizeof(T)); + } + else + { + for(j=0; ja_no_check(i,j) = *this->def_val; + } + } + else if (!this->p_sub_matrix) + { + int old_row_step = this->p_row_step; + int old_column_step = this->p_column_step; + int copy_r = Lof(this->num_rows(), new_rows); + int copy_c = Lof(this->num_columns(), new_cols); + + just_resize(new_rows, new_cols, &old_vals); + + set_values(old_vals, + old_row_step, old_column_step, + 0, copy_r, + 0, copy_c); + + int i,j; + + for(i=0; ia_no_check(i,j) = *this->def_val; + + if (new_rows > copy_r) + if (*this->def_val == 0) + { + memset((void *)(this->p_memory + copy_r*this->p_row_step), + 0, + (new_rows-copy_r)*new_cols*sizeof(T)); + } + else + { + for(j=0; ja_no_check(i,j) = *this->def_val; + } + } + else + EST_TMatrix::resize(new_rows, new_cols, 1); + } + else + EST_TMatrix::resize(new_rows, new_cols, 0); + + if (old_vals && old_vals != this->p_memory) + delete [] (old_vals-old_offset); +} + + +void EST_Track::set_value(int i) // make location i hold a value +{ + p_is_val[i] = 0; +} + +void EST_Track::set_break(int i) // make location i hold a break +{ + if (i >= num_frames()) + cerr << "Requested setting of break value of the end of the array\n"; + + p_is_val[i] = 1; +} + +float EST_Track::shift() const +{ + int j1 = 0; + int j2 = 0; + + if (!p_equal_space) + exit(1);//EST_error("Tried to take shift from non-fixed contour\n"); + + do + { + j1 = next_non_break(++j1); + j2 = next_non_break(j1); + // cout << "j1:" << j1 << " j2:" << j2 << endl; + } + while ((j2 != 0) && (j2 != (j1 +1))); + + if (j2 == 0) + { + if (num_frames() > 1) + return p_times(1) - p_times(0); + else + exit(1);//EST_error("Couldn't determine shift size\n"); + + } + return (p_times(j2) - p_times(j1)); +} + +EST_Track &EST_Track::operator=(const EST_Track& a) +{ + copy(a); + return *this; +} + +int EST_Track::empty() const +{ + int i, num; + + for (i = num = 0; i < num_frames(); ++i) + if (val(i)) + return 0; // i.e. false + + return 1; // i.e. true +} + +const float EST_Val::to_flt(void) const +{ + // coerce this to a float + if (t==val_int) + return (float)v.ival; + else if (t==val_string) + return atof(sval); + else + return v.fval; // just for completeness +} + +int EST_Track::next_non_break(int j) const +{ + int i = j; + for (++i; i < num_frames(); ++i) + { + // cout << "i: " << i << " " << value[i] << endl; + if (!track_break(i)) + return i; + } + + return 0; +} + +float EST_Track::a(int i, int c) const +{ + return ((EST_Track *)this)->a(i,c); +} + +void EST_Track::resize(int new_num_frames, int new_num_channels, bool set) +{ + int old_num_frames = num_frames(); + + if (new_num_frames<0) + new_num_frames = num_frames(); + + if (new_num_channels<0) + new_num_channels = num_channels(); + + p_channel_names.resize(new_num_channels); + + // this ensures the new channels have a default name + if (new_num_channels > num_channels()) + for (int i = num_channels(); i < new_num_channels; ++i) + set_channel_name("track_" + itoString(i), i); + + p_values.resize(new_num_frames, new_num_channels, set); + p_times.resize(new_num_frames, set); + p_is_val.resize(new_num_frames, set); + + p_aux.resize(new_num_frames, num_aux_channels(), set); + + // Its important that any new vals get set to 0 + for (int i = old_num_frames; i < num_frames(); ++i) + p_is_val.a_no_check(i) = 0; + +} + +Declare_TVector(float) + +EST_Chunk::EST_Chunk () +{ + count = 0; + memory[0] = '\0'; + // cerr<<"created " << hex << (int)&memory << "," << dec << size <<"\n"; +} + +void *EST_Chunk::operator new (size_t size, int bytes) +{ + + if (bytes > MAX_CHUNK_SIZE) + { + cerr<<"trying to make chunk of size "< size = bytes; + + return it; +} + +EST_String::EST_String(const char *s, int s_size, int start, int len) +{ + CHECK_STRING_ARG(s); + + if (len <0) + len=s_size-start; + + size=len; + if (size != 0) + memory = chunk_allocate(len+1, s+start, len); + else + memory=NULL; +} + +int EST_String::locate(const char *s, int len, int from, int &start, int &end) const +{ + CHECK_STRING_ARG(s); + + const char *sub=NULL; + + if (!s) + return 0; + + if (from < 0 && -from < size) + { + int endpos=size+from+1; + int p=0; + const char *nextsub; + + while ((nextsub=strstr(str()+p, s))) + { + p=nextsub-str()+1; + if (p > endpos) + break; + sub=nextsub; + } + } + else if (from>=0 && from <= size) + sub= strstr(str()+from, s); + + if (sub != NULL) + { + start = sub-str(); + end = start + len; + return 1; + } + else + { + return 0; + } + +} + +Declare_KVL_N(EST_String, EST_Val, 100) + +template EST_TKVL &EST_TKVL::operator = +(const EST_TKVL &kv) +{ + list = kv.list; + return *this; +} + + + +#define SWAPINT(x) ((((unsigned)x) & 0xff) << 24 | \ + (((unsigned)x) & 0xff00) << 8 | \ + (((unsigned)x) & 0xff0000) >> 8 | \ + (((unsigned)x) & 0xff000000) >> 24) +#define SWAPSHORT(x) ((((unsigned)x) & 0xff) << 8 | \ + (((unsigned)x) & 0xff00) >> 8) + +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_ADPCM 0x0002 +#define WAVE_FORMAT_ALAW 0x0006 +#define WAVE_FORMAT_MULAW 0x0007 + +void swap_bytes_short(short *data, int length) +{ + /* Swap shorts in an array */ + int i; + + for (i=0; i +INFO &EST_TValuedEnumI::info (ENUM token) const +{ + int i; + + for(i=0; indefinitions; i++) + if (this->definitions[i].token == token) + return this->definitions[i].info; + + exit(1);//cerr << "Fetching info for invalid entry\n"; + abort(); + + static INFO dummyI; + return dummyI; +} + +template +ENUM EST_TValuedEnumI::token (VAL value) const +{ + int i,j; + + for(i=0; indefinitions; i++) + for(j=0; jdefinitions[i].values[j] ; j++) + if (eq_vals(this->definitions[i].values[j], value)) + return this->definitions[i].token; + + return this->p_unknown_enum; +} + + +void EST_TokenStream::default_values() +{ + type = tst_none; + peeked_tokp = FALSE; + peeked_charp = FALSE; + eof_flag = FALSE; + quotes = FALSE; + p_filepos = 0; + linepos = 1; + WhiteSpaceChars = EST_Token_Default_WhiteSpaceChars; + SingleCharSymbols = EST_String::Empty; + PrePunctuationSymbols = EST_String::Empty; + PunctuationSymbols = EST_String::Empty; + build_table(); + close_at_end=TRUE; +} + +template +VAL EST_TValuedEnumI::value (ENUM token, int n) const +{ + int i; + + for(i=0; indefinitions; i++) + if (this->definitions[i].token == token) + return this->definitions[i].values[n]; + + return this->p_unknown_value; +} + +int EST_TokenStream::seek(int position) +{ + peeked_charp = FALSE; + peeked_tokp = FALSE; + + switch (type) + { + case tst_none: + exit(1);//cerr << "EST_TokenStream unset" << endl; + return -1; + break; + case tst_file: + p_filepos = position; + return fseek(fp,position,SEEK_SET); + case tst_pipe: + exit(1);//cerr << "EST_TokenStream seek on pipe not supported" << endl; + return -1; + break; + case tst_istream: + exit(1);//cerr << "EST_TokenStream seek on istream not yet supported" << endl; + return -1; + break; + case tst_string: + if (position >= pos) + { + pos = position; + return -1; + } + else + { + pos = position; + return 0; + } + break; + default: + exit(1);//cerr << "EST_TokenStream: unknown type" << endl; + return -1; + } + + return -1; // can't get here + +} + +template +int EST_TValuedEnumI::n(void) const +{ +return this->ndefinitions; +} + +EST_String::EST_String(const char *s, int start_or_fill, int len) +{ + + if (s) + { + int start= start_or_fill; + if (len <0) + len=safe_strlen(s)-start; + + size=len; + if (size != 0) + memory = chunk_allocate(len+1, s+start, len); + else + memory=NULL; + } + else + { + char fill = start_or_fill; + if (len<0) len=0; + size=len; + if (size != 0) + { + memory = chunk_allocate(len+1); + char *p = memory; + for(int j=0; j +void EST_TVector::resize(int new_cols, int set) +{ + int i; + T * old_vals = p_memory; + int old_cols = num_columns(); + int old_offset = p_offset; + int old_column_step = p_column_step; + + just_resize(new_cols, &old_vals); + + if (set) + { + int copy_c = 0; + + if (!old_vals) + copy_c=0; + else if (old_vals != p_memory) + { + copy_c = Lof(num_columns(), old_cols); + + for(i=0; i +void EST_TMatrix::resize(int new_rows, int new_cols, int set) +{ + int i,j; + T * old_vals = this->p_memory; + int old_rows = num_rows(); + int old_cols = num_columns(); + int old_row_step = p_row_step; + int old_offset = this->p_offset; + int old_column_step = this->p_column_step; + + if (new_rows<0) + new_rows = old_rows; + if (new_cols<0) + new_cols = old_cols; + + just_resize(new_rows, new_cols, &old_vals); + + if (set) + { + int copy_r = 0; + int copy_c = 0; + + if (old_vals != NULL) + { + copy_r = Lof(num_rows(), old_rows); + copy_c = Lof(num_columns(), old_cols); + + set_values(old_vals, + old_row_step, old_column_step, + 0, copy_r, + 0, copy_c); + } + else + { + copy_r = old_rows; + copy_c = old_cols; + } + + for(i=0; idef_val; + + for(i=copy_r; idef_val; + } + + if (old_vals && old_vals != this->p_memory && !this->p_sub_matrix) + delete [] (old_vals-old_offset); +} + +// should copy from and delete old version first +template void EST_TSimpleVector::resize(int newn, int set) +{ + int oldn = this->n(); + T *old_vals =NULL; + int old_offset = this->p_offset; + + just_resize(newn, &old_vals); + + if (set && old_vals) + { + int copy_c = 0; + if (this->p_memory != NULL) + { + copy_c = Lof(this->n(), oldn); + memcpy((void *)this->p_memory, (const void *)old_vals, copy_c* sizeof(T)); + } + + for (int i=copy_c; i < this->n(); ++i) + this->p_memory[i] = *this->def_val; + } + + if (old_vals != NULL && old_vals != this->p_memory && !this->p_sub_matrix) + delete [] (old_vals - old_offset); + +} + +void EST_Track::copy(const EST_Track& a) +{ + copy_setup(a); + p_values = a.p_values; + p_times = a.p_times; + p_is_val = a.p_is_val; + p_t_offset = a.p_t_offset; + p_aux = a.p_aux; + p_aux_names = a.p_aux_names; +} + +int EST_Track::val(int i) const +{ + return !p_is_val(i); +} + +void uchar_to_short(const unsigned char *chars,short *data,int length) +{ + /* Convert 8 bit data to shorts UNSIGNED CHAR */ + int i; + + for (i=0; i> 4 ) & 0x07; + mantissa = ulawbyte & 0x0F; + sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) ); + if ( sign != 0 ) sample = -sample; + + return sample; +} + +void ulaw_to_short(const unsigned char *ulaw,short *data,int length) +{ + /* Convert ulaw to shorts */ + int i; + + for (i=0; i +void EST_TMatrix::set_memory(T *buffer, int offset, + int rows, int columns, + int free_when_destroyed) +{ + EST_TVector::set_memory(buffer, offset, columns, free_when_destroyed); + p_num_rows = rows; + p_row_step = columns; +} + +void EST_TokenStream::build_table() +{ + int i; + const char *p; + unsigned char c; + + for (i=0; i<256; ++i) + p_table[i]=0; + + for (p=WhiteSpaceChars; *p; ++p) + if (p_table[c=(unsigned char)*p]) + exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", + // *p, c, ' '); + else + p_table[c] = ' '; + + for (p=SingleCharSymbols; *p; ++p) + if (p_table[c=(unsigned char)*p]) + exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", + // *p, p_table[c], '!'); + else + p_table[c] = '@'; + + for (p=PunctuationSymbols; *p; ++p) + if (p_table[c=(unsigned char)*p] == '@') + continue; + else if (p_table[c]) + exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", + // *p, p_table[c], '.'); + else + p_table[c] = '.'; + + for(p=PrePunctuationSymbols; *p; ++p) + if (p_table[c=(unsigned char)*p] == '@') + continue; + else if (p_table[c] == '.') + p_table[c] = '"'; + else if (p_table[c]) + exit(1);//EST_warning("Character '%c' has two classes, '%c' and '%c'", + // *p, p_table[c], '$'); + else + p_table[c] = '$'; + + p_table_wrong=0; +} + +const EST_String EST_String::Empty(""); + +const EST_String EST_Token_Default_WhiteSpaceChars = " \t\n\r"; + +EST_ChunkPtr chunk_allocate(int bytes) +{ + EST_Chunk *cp = new(bytes) EST_Chunk; + + return (EST_ChunkPtr)cp; +} + + +template +EST_TVector &EST_TVector::operator=(const EST_TVector &in) +{ + copy(in); + return *this; +} + +template +EST_TMatrix &EST_TMatrix::operator=(const EST_TMatrix &in) +{ + copy(in); + return *this; +} + +template EST_TSimpleVector &EST_TSimpleVector::operator=(const EST_TSimpleVector &in) +{ + copy(in); + return *this; +} + +void EST_Track::copy_setup(const EST_Track& a) +{ + p_equal_space = a.p_equal_space; + p_single_break = a.p_single_break; + p_channel_names = a.p_channel_names; + p_map = a.p_map; + copy_features(a); +} + +template EST_TSimpleMatrix &EST_TSimpleMatrix::operator=(const EST_TSimpleMatrix &in) +{ + copy(in); + return *this; +} + +template +void EST_TSimpleMatrix::copy(const EST_TSimpleMatrix &a) +{ + if (this->num_rows() != a.num_rows() || this->num_columns() != a.num_columns()) + resize(a.num_rows(), a.num_columns(), 0); + + copy_data(a); +} + +void EST_Featured::copy_features(const EST_Featured &f) +{ + clear_features(); + + if (f.p_features) + p_features = new EST_Features(*(f.p_features)); +} + +template +EST_TVector::EST_TVector(int n) +{ + default_vals(); + resize(n); +} + +void EST_UList::clear_and_free(void (*item_free)(EST_UItem *p)) +{ + EST_UItem *p, *np; + + for (p=head(); p != 0; p = np) + { + np=next(p); + if (item_free) + item_free(p); + else + delete p; + } + h = t = 0; +} + +template void EST_TList::free_item(EST_UItem *item) +{ EST_TItem::release((EST_TItem *)item); } + +void EST_UList::append(EST_UItem *new_item) +{ + + if (new_item == 0) return; + + new_item->n = 0; + new_item->p = t; + if (t == 0) + h = new_item; + else + t->n = new_item; + t = new_item; +} + +template EST_TItem *EST_TItem::make(const T &val) +{ + EST_TItem *it=NULL; + if (s_free!=NULL) + { + void *mem = s_free; + s_free=(EST_TItem *)s_free->n; + s_nfree--; + + // Create an item in the retrieved memory. + it=new (mem) EST_TItem(val); + } + else + it = new EST_TItem(val); + + return it; +} + +template +ENUM EST_TValuedEnumI::nth_token (int n) const +{ + if (n>=0 && n < this->ndefinitions) + return this->definitions[n].token; + + return this->p_unknown_enum; +} + +EST_TrackMap::~EST_TrackMap() +{ +} + +template +void EST_TVector::default_vals() +{ + p_num_columns = 0; + p_offset=0; + p_column_step=0; + + p_memory = NULL; + p_sub_matrix=FALSE; +} + +template +void EST_TMatrix::default_vals() +{ + EST_TVector::default_vals(); + p_num_rows = 0; + p_row_step=0; +} + +template +void EST_TMatrix::set_values(const T *data, + int r_step, int c_step, + int start_r, int num_r, + int start_c, int num_c + ) +{ + for(int r=start_r, i=0, rp=0; i< num_r; i++, r++, rp+=r_step) + for(int c=start_c, j=0, cp=0; j< num_c; j++, c++, cp+=c_step) + a_no_check(r,c) = data[rp+cp]; +} + +template +void EST_TMatrix::just_resize(int new_rows, + int new_cols, + T** old_vals) +{ + T *new_m; + + if (num_rows() != new_rows || num_columns() != new_cols || this->p_memory == NULL ) + { + if (this->p_sub_matrix) + exit(1);//EST_error("Attempt to resize Sub-Matrix"); + + if (new_cols < 0 || new_rows < 0) + exit(1);//EST_error("Attempt to resize matrix to negative size: %d x %d", + // new_rows, + // new_cols); + + + new_m = new T[new_rows*new_cols]; + + if (this->p_memory != NULL) + if (old_vals != NULL) + *old_vals = this->p_memory; + else if (!this->p_sub_matrix) + delete [] (this->p_memory-this->p_offset); + + p_num_rows = new_rows; + this->p_num_columns = new_cols; + this->p_offset=0; + p_row_step=this->p_num_columns; + this->p_column_step=1; + + this->p_memory = new_m; + } + else + *old_vals = this->p_memory; + +} + +template void EST_TSimpleVector::copy(const EST_TSimpleVector &a) +{ + if (this->p_column_step==1 && a.p_column_step==1) + { + resize(a.n(), FALSE); + memcpy((void *)(this->p_memory), (const void *)(a.p_memory), this->n() * sizeof(T)); + } +else + ((EST_TVector *)this)->copy(a); +} + +template +void EST_TVector::just_resize(int new_cols, T** old_vals) +{ + T *new_m; + + if (num_columns() != new_cols || p_memory == NULL ) + { + if (p_sub_matrix) + exit(1);//EST_error("Attempt to resize Sub-Vector"); + + if (new_cols < 0) + exit(1);//EST_error("Attempt to resize vector to negative size: %d", + // new_cols); + + new_m = new T[new_cols]; + + if (p_memory != NULL) + if (old_vals != NULL) + *old_vals = p_memory; + else if (!p_sub_matrix) + delete [] (p_memory-p_offset); + + p_memory = new_m; + //cout << "vr: mem: " << p_memory << " (" << (int)p_memory << ")\n"; + p_offset=0; + p_num_columns = new_cols; + p_column_step=1; + } + else + *old_vals = p_memory; +} + +template +void EST_TVector::set_memory(T *buffer, int offset, int columns, + int free_when_destroyed) +{ + if (p_memory != NULL && !p_sub_matrix) + delete [] (p_memory-p_offset); + + p_memory = buffer-offset; + p_offset=offset; + p_num_columns = columns; + p_column_step=1; + p_sub_matrix = !free_when_destroyed; +} + +template +void EST_TSimpleMatrix::copy_data(const EST_TSimpleMatrix &a) +{ + if (!a.p_sub_matrix && !this->p_sub_matrix) + memcpy((void *)&this->a_no_check(0,0), + (const void *)&a.a_no_check(0,0), + this->num_rows()*this->num_columns()*sizeof(T) + ); + else + { + for (int i = 0; i < this->num_rows(); ++i) + for (int j = 0; j < this->num_columns(); ++j) + this->a_no_check(i,j) = a.a_no_check(i,j); + } +} + +Declare_TVector(short) + +template void EST_TItem::release(EST_TItem *it) +{ + if (s_nfree < s_maxFree) + { + // Destroy the value in case it holds resources. + it->EST_TItem::~EST_TItem(); + + // I suppose it's a bit weird to use 'n' after calling the destructor. + it->n=s_free; + s_free=it; + s_nfree++; + } + else + delete it; +} + +EST_Val &EST_Val::operator=(const EST_Val &c) +{ + // Have to be careful with the case where they are different types + if ((t != val_int) && + (t != val_float) && + (t != val_unset) && + (t != val_string)) + delete v.pval; + + if (c.t == val_string) + sval = c.sval; + else if (c.t == val_int) + v.ival = c.v.ival; + else if (c.t == val_float) + v.fval = c.v.fval; + else if (c.t != val_unset) + { // does references not a real copy + v.pval = new EST_Contents; + *v.pval = *c.v.pval; + } + t=c.t; + return *this; +} + +template EST_TList &EST_TList::operator=(const EST_TList &a) +{ + clear(); // clear out all current items in list. + copy_items(a); + return *this; +} + +int operator == (const EST_String &a, const EST_String &b) +{ + if (a.size==0) + return b.size == 0; + else if (b.size == 0) + return 0; + else + return a.size == b.size && a(0) == b(0) && memcmp(a.str(),b.str(),a.size)==0; +}; + +Declare_TVector(char) +Declare_TVector(EST_Val) +Declare_TVector(EST_String) + +template +void EST_TMatrix::copy(const EST_TMatrix &a) +{ + resize(a.num_rows(), a.num_columns(), 0); + copy_data(a); +} + +template +void EST_TVector::copy(const EST_TVector &a) +{ + resize(a.n(), FALSE); + copy_data(a); +} + +template void EST_TList::copy_items(const EST_TList &l) +{ + EST_UItem *p; + for (p = l.head(); p; p = next(p)) + append(l.item(p)); +} + +template +void EST_TMatrix::copy_data(const EST_TMatrix &a) +{ + + set_values(a.p_memory, + a.p_row_step, a.p_column_step, + 0, a.num_rows(), + 0, a.num_columns()); +} + +template +void EST_TVector::copy_data(const EST_TVector &a) +{ + set_values(a.p_memory, a.p_column_step, 0, num_columns()); +} + +EST_Val::EST_Val(const EST_Val &c) +{ + if (c.t == val_string) + sval = c.sval; + else if (c.t == val_int) + v.ival = c.v.ival; + else if (c.t == val_float) + v.fval = c.v.fval; + else if (c.t != val_unset) + { // does references not a real copy + v.pval = new EST_Contents; + *v.pval = *c.v.pval; + } + t=c.t; +} + +template +void EST_TVector::set_values(const T *data, + int step, + int start_c, + int num_c) +{ + for(int i=0, c=start_c, p=0; i +void EST_TValuedEnumI::initialise(const void *vdefs) +{ + int n=0; + typedef EST_TValuedEnumDefinition defn; + const defn *defs = (const defn *)vdefs; + + for(n=1; defs[n].token != defs[0].token; n++) + ; + + this->ndefinitions = n; + this->definitions = new defn[n]; + + this->definitions[0] = defs[0]; + for(n=1; defs[n].token != defs[0].token; n++) + this->definitions[n] = defs[n]; + + this->p_unknown_enum = defs[n].token; + this->p_unknown_value = defs[n].values[0]; +} + +template +EST_TValuedEnumI::~EST_TValuedEnumI(void) +{ + if (this->definitions) + delete[] this->definitions; +} + +struct Srpd_Op { + int sample_freq; /* Hz */ + int Nmax, Nmin; + double shift, length; /* ms */ + double min_pitch; /* Hz */ + double max_pitch; /* Hz */ + int L; /* Decimation factor (samples) */ + double Tmin, Tmax_ratio, Thigh, Tdh; + int Tsilent; + int make_ascii; + int peak_tracking; +}; + +#define MINARG 5 +#define BREAK_NUMBER 0.0 + +#define DEFAULT_DECIMATION 4 /* samples */ +#define DEFAULT_MIN_PITCH 60.0 /* Hz */ +#define DEFAULT_MAX_PITCH 600.0 /* Hz */ + +#define DEFAULT_SF 20000 /* Hz. Sampling Frequency */ +#define DEFAULT_SHIFT 5.0 /* ms */ +#define DEFAULT_LENGTH 10.0 /* ms */ +#define DEFAULT_TSILENT 120 /* max. abs sample amplitude of noise */ +#define DEFAULT_TMIN 0.75 +#define DEFAULT_TMAX_RATIO 0.85 +#define DEFAULT_THIGH 0.88 +#define DEFAULT_TDH 0.77 + +enum Voice { + UNVOICED = 0, + VOICED = 1, + SILENT = 2, +}; + + +enum Hold { + HOLD = 1, + HELD = 1, + SEND = 2, + SENT = 2, +}; + + +static struct Srpd_Op *default_srpd_op(struct Srpd_Op *srpd) +{ + srpd->L = DEFAULT_DECIMATION; + srpd->min_pitch = DEFAULT_MIN_PITCH; + srpd->max_pitch = DEFAULT_MAX_PITCH; + srpd->shift = DEFAULT_SHIFT; + srpd->length = DEFAULT_LENGTH; + srpd->Tsilent = DEFAULT_TSILENT; + srpd->Tmin = DEFAULT_TMIN; + srpd->Tmax_ratio = DEFAULT_TMAX_RATIO; + srpd->Thigh = DEFAULT_THIGH; + srpd->Tdh = DEFAULT_TDH; + srpd->make_ascii = 0; + srpd->peak_tracking = 0; + srpd->sample_freq = DEFAULT_SF; + /* p_par->Nmax and p_par->Nmin cannot be initialised */ + return(srpd); +} + +struct STATUS_ +{ + double pitch_freq; + Voice v_uv; + Hold s_h; + double cc_max, threshold; +}; + +#define rint(N) ((float)(int)((N)+0.5)) + +void initialise_structures (struct Srpd_Op *p_par, SEGMENT_ *p_seg, CROSS_CORR_ *p_cc) +{ + p_par->Nmax = (int) ceil((float)p_par->sample_freq / p_par->min_pitch); + p_par->Nmin = (int) floor((float)p_par->sample_freq / p_par->max_pitch); + p_par->min_pitch = (float)p_par->sample_freq / (float)p_par->Nmax; + p_par->max_pitch = (float)p_par->sample_freq / (float)p_par->Nmin; + + p_seg->size = 3 * p_par->Nmax; + p_seg->shift = (int) rint( p_par->shift / 1000.0 * (float)p_par->sample_freq ); + p_seg->length = (int) rint( p_par->length / 1000.0 * (float)p_par->sample_freq ); + p_seg->data = walloc(short,p_seg->size); + + p_cc->size = p_par->Nmax - p_par->Nmin + 1; + p_cc->coeff = walloc(double,p_cc->size); +} + +void initialise_status (const Srpd_Op ¶s, STATUS_ *p_status) +{ + + p_status->pitch_freq = BREAK_NUMBER; + p_status->v_uv = SILENT; + p_status->s_h = SEND; /* SENT */ + p_status->cc_max = 0.0; + p_status->threshold = paras.Thigh; + return; + +} + + +short ConvertFloatTo16Bit( float fSample ) +{ + short ret = fSample * 32768.0f; + return ret; +} + +int read_next_wave_segment2(RageSoundReader_FileReader *sample, const Srpd_Op ¶s, SEGMENT_ *p_seg) +{ + printf("read: size %d shift %d length %d\n", p_seg->size, p_seg->shift, p_seg->length); + + ASSERT( sample->GetNumChannels() == 1 ); + + int iSize = p_seg->size; + float *pfData = new float[iSize]; + int iNumRead = sample->Read( pfData, iSize ); + + for( int i=0; idata[i] = d; + } + else + { + p_seg->data[i] = 0; + } + } + + SAFE_DELETE_ARRAY( pfData ); + + return iNumRead > 0; +} + + +typedef struct list { + int N0, score; + struct list *next_item; +} LIST_; + +void add_to_list (LIST_ **p_list_hd, LIST_ **p_list_tl, int N_val, + int score_val) +{ + + LIST_ *new_node, *last_node; + + new_node = walloc(LIST_ ,1); + last_node = *p_list_tl; + new_node->N0 = N_val; + new_node->score = score_val; + new_node->next_item = NULL; + if (*p_list_hd == NULL) + *p_list_hd = new_node; + else + last_node->next_item = new_node; + *p_list_tl = new_node; + +} + +void free_list (LIST_ **p_list_hd) +{ + + LIST_ *next; + + while (*p_list_hd != NULL) { + next = (*p_list_hd)->next_item; + wfree (*p_list_hd); + *p_list_hd = next; + } + +} + +void super_resolution_pda (const Srpd_Op ¶s, const SEGMENT_ &seg, CROSS_CORR_ *p_cc, STATUS_ *p_status) +{ + static int zx_lft_N, zx_rht_N; + static double prev_pf = BREAK_NUMBER; + + int n, j, k, N0 = 0, N1, N2, N_, q, lower_found = 0, score = 1, apply_bias; + int x_index, y_index, z_index; + int zx_rate = 0, zx_at_N0 = 0, prev_sign; + int seg1_zxs = 0, seg2_zxs = 0, total_zxs; + short prev_seg1, prev_seg2; + short x_max = -MAXSHORT, x_min = MAXSHORT; + short y_max = -MAXSHORT, y_min = MAXSHORT; + double xx = 0.0, yy = 0.0, zz = 0.0, xy = 0.0, yz = 0.0, xz = 0.0; + double max_cc = 0.0, coefficient, coeff_weight; + double xx_N, yy_N, xy_N, y1y1_N, xy1_N, yy1_N, beta; + LIST_ *sig_pks_hd, *sig_pks_tl, *sig_peak, *head, *tail; + + sig_pks_hd = head = NULL; + sig_pks_tl = tail = NULL; + /* set correlation coefficient threshold */ + if (p_status->v_uv == UNVOICED || p_status->v_uv == SILENT) + p_status->threshold = paras.Thigh; + else /* p_status->v_uv == VOICED */ + p_status->threshold = (paras.Tmin > paras.Tmax_ratio * + p_status->cc_max) ? paras.Tmin : paras.Tmax_ratio * + p_status->cc_max; + /* determine if a bias should be applied */ + if (paras.peak_tracking && prev_pf != BREAK_NUMBER && + p_status->v_uv == VOICED && p_status->s_h != HOLD && + p_status->pitch_freq < 1.75 * prev_pf && + p_status->pitch_freq > 0.625 * prev_pf) + apply_bias = 1; + else + apply_bias = 0; + /* consider first two segments of period n = Nmin */ + prev_seg1 = seg.data[paras.Nmax - paras.Nmin] < 0 ? -1 : 1; + prev_seg2 = seg.data[paras.Nmax] < 0 ? -1 : 1; + for (j = 0; j < paras.Nmin; j += paras.L) { + /* find max and min amplitudes in x and y segments */ + x_index = paras.Nmax - paras.Nmin + j; + y_index = paras.Nmax + j; + if (seg.data[x_index] > x_max) x_max = seg.data[x_index]; + if (seg.data[x_index] < x_min) x_min = seg.data[x_index]; + if (seg.data[y_index] > y_max) y_max = seg.data[y_index]; + if (seg.data[y_index] < y_min) y_min = seg.data[y_index]; + /* does new sample in x or y segment represent an input zero-crossing */ + if (seg.data[x_index] * prev_seg1 < 0) { + prev_seg1 *= -1; + seg1_zxs++; + } + if (seg.data[y_index] * prev_seg2 < 0) { + prev_seg2 *= -1; + seg2_zxs++; + } + /* calculate parts for first correlation coefficient */ + xx += (double) seg.data[x_index] * seg.data[x_index]; + yy += (double) seg.data[y_index] * seg.data[y_index]; + xy += (double) seg.data[x_index] * seg.data[y_index]; + } + /* low amplitude segment represents silence */ + if (abs (x_max) + abs (x_min) < 2 * paras.Tsilent || + abs (y_max) + abs (y_min) < 2 * paras.Tsilent) { + for (q = 0; q < p_cc->size; p_cc->coeff[q++] = 0.0); + prev_pf = p_status->pitch_freq; + p_status->pitch_freq = BREAK_NUMBER; + p_status->v_uv = SILENT; + p_status->s_h = SEND; + p_status->cc_max = 0.0; + return; + } + /* determine first correlation coefficients, for period n = Nmin */ + p_cc->coeff[0] = p_status->cc_max = xy / sqrt (xx) / sqrt (yy); + for (q = 1; q < p_cc->size && q < paras.L; p_cc->coeff[q++] = 0.0); + total_zxs = seg1_zxs + seg2_zxs; + prev_sign = p_cc->coeff[0] < 0.0 ? -1 : 1; + prev_seg1 = seg.data[paras.Nmax - paras.Nmin] < 0 ? -1 : 1; + /* iteratively determine correlation coefficient for next possible period */ + for (n = paras.Nmin + paras.L; n <= paras.Nmax; n += paras.L, + j += paras.L) { + x_index = paras.Nmax - n; + y_index = paras.Nmax + j; + /* does new samples in x or y segment represent an input zero-crossing */ + if (seg.data[x_index] * prev_seg1 < 0) { + prev_seg1 *= -1; + total_zxs++; + } + if (seg.data[y_index] * prev_seg2 < 0) { + prev_seg2 *= -1; + total_zxs++; + } + /* determine next coefficient */ + xx += (double) seg.data[x_index] * seg.data[x_index]; + yy += (double) seg.data[y_index] * seg.data[y_index]; + for (k = 0, xy = 0.0; k < n; k += paras.L) + xy += (double) seg.data[paras.Nmax - n + k] * seg.data[paras.Nmax + k]; + p_cc->coeff[n - paras.Nmin] = xy / sqrt (xx) / sqrt (yy); + if (p_cc->coeff[n - paras.Nmin] > p_status->cc_max) + p_status->cc_max = p_cc->coeff[n - paras.Nmin]; + /* set unknown coefficients to zero */ + for (q = n - paras.Nmin + 1; + q < p_cc->size && q < n - paras.Nmin + paras.L; + p_cc->coeff[q++] = 0.0); + /* is there a slope with positive gradient in the coefficients track yet */ + if (p_cc->coeff[n - paras.Nmin] > p_cc->coeff[n - paras.Nmin - paras.L]) + lower_found = 1; + /* has new coefficient resulted in a zero-crossing */ + if (p_cc->coeff[n - paras.Nmin] * prev_sign < 0.0) { + prev_sign *= -1; + zx_rate++; + } + /* does the new coefficient represent a pitch period candidate */ + if (N0 != 0 && zx_rate > zx_at_N0) { + add_to_list (&sig_pks_hd, &sig_pks_tl, N0, 1); + N0 = 0; + max_cc = 0.0; + } + if (apply_bias && n > zx_lft_N && n < zx_rht_N) + coeff_weight = 2.0; + else + coeff_weight = 1.0; + if (p_cc->coeff[n - paras.Nmin] > max_cc && total_zxs > 3 && lower_found) { + max_cc = p_cc->coeff[n - paras.Nmin]; + if (max_cc * coeff_weight >= p_status->threshold) { + zx_at_N0 = zx_rate; + N0 = n; + } + } + } + /* unvoiced if no significant peak found in coefficients track */ + if (sig_pks_hd == NULL) { + prev_pf = p_status->pitch_freq; + p_status->pitch_freq = BREAK_NUMBER; + p_status->v_uv = UNVOICED; + p_status->s_h = SEND; + return; + } + /* find which significant peak in list corresponds to true pitch period */ + sig_peak = sig_pks_hd; + while (sig_peak != NULL) { + yy = zz = yz = 0.0; + for (j = 0; j < sig_peak->N0; j++) { + y_index = paras.Nmax + j; + z_index = paras.Nmax + sig_peak->N0 + j; + yy += (double) seg.data[y_index] * seg.data[y_index]; + zz += (double) seg.data[z_index] * seg.data[z_index]; + yz += (double) seg.data[y_index] * seg.data[z_index]; + } + if (yy == 0.0 || zz == 0.0) + coefficient = 0.0; + else + coefficient = yz / sqrt (yy) / sqrt (zz); + if (apply_bias && sig_peak->N0 > zx_lft_N && sig_peak->N0 < zx_rht_N) + coeff_weight = 2.0; + else + coeff_weight = 1.0; + if (coefficient * coeff_weight >= p_status->threshold) { + sig_peak->score = 2; + if (head == NULL) { + head = sig_peak; + score = 2; + } + tail = sig_peak; + } + sig_peak = sig_peak->next_item; + } + if (head == NULL) head = sig_pks_hd; + if (tail == NULL) tail = sig_pks_tl; + N0 = head->N0; + if (tail != head) { + xx = 0.0; + for (j = 0; j < tail->N0; j++) + xx += (double) seg.data[paras.Nmax - tail->N0 + j] * + seg.data[paras.Nmax - tail->N0 + j]; + sig_peak = head; + while (sig_peak != NULL) { + if (sig_peak->score == score) { + xz = zz = 0.0; + for (j = 0; j < tail->N0; j++) { + z_index = paras.Nmax + sig_peak->N0 + j; + xz += (double) seg.data[paras.Nmax - tail->N0 + j] * + seg.data[z_index]; + zz += (double) seg.data[z_index] * seg.data[z_index]; + } + coefficient = xz / sqrt (xx) / sqrt (zz); + if (sig_peak == head) + max_cc = coefficient; + else if (coefficient * paras.Tdh > max_cc) { + N0 = sig_peak->N0; + max_cc = coefficient; + } + } + sig_peak = sig_peak->next_item; + } + } + p_status->cc_max = p_cc->coeff[N0 - paras.Nmin]; + /* voiced segment period now found */ + if ((tail == head && score == 1 && p_status->v_uv != VOICED) || + p_cc->coeff[N0 - paras.Nmin] < p_status->threshold) + p_status->s_h = HOLD; + else + p_status->s_h = SEND; + /* find left and right boundaries of peak in coefficients track */ + zx_lft_N = zx_rht_N = 0; + for (q = N0; q >= paras.Nmin; q -= paras.L) + if (p_cc->coeff[q - paras.Nmin] < 0.0) { + zx_lft_N = q; + break; + } + for (q = N0; q <= paras.Nmax; q += paras.L) + if (p_cc->coeff[q - paras.Nmin] < 0.0) { + zx_rht_N = q; + break; + } + /* define small region around peak */ + if (N0 - paras.L < paras.Nmin) { + N1 = N0; + N2 = N0 + 2 * paras.L; + } + else if (N0 + paras.L > paras.Nmax) { + N1 = N0 - 2 * paras.L; + N2 = N0; + } + else { + N1 = N0 - paras.L; + N2 = N0 + paras.L; + } + /* compensate for decimation factor L */ + if (paras.L != 1) { + xx = yy = xy = 0.0; + for (j = 0; j < N1; j++) { + x_index = paras.Nmax - N1 + j; + y_index = paras.Nmax + j; + xx += (double) seg.data[x_index] * seg.data[x_index]; + xy += (double) seg.data[x_index] * seg.data[y_index]; + yy += (double) seg.data[y_index] * seg.data[y_index]; + } + p_cc->coeff[N1 - paras.Nmin] = p_status->cc_max = + xy / sqrt (xx) / sqrt (yy); + N0 = N1; + for (n = N1 + 1; n <= N2; n++, j++) { + xx += (double) seg.data[paras.Nmax - n] * seg.data[paras.Nmax - n]; + yy += (double) seg.data[paras.Nmax + j] * seg.data[paras.Nmax + j]; + for (k = 0, xy = 0.0; k < n; k++) + xy += (double) seg.data[paras.Nmax - n + k] * seg.data[paras.Nmax + k]; + p_cc->coeff[n - paras.Nmin] = xy / sqrt (xx) / sqrt (yy); + if (p_cc->coeff[n - paras.Nmin] > p_status->cc_max) { + p_status->cc_max = p_cc->coeff[n - paras.Nmin]; + N0 = n; + } + } + } + /* compensate for finite resolution in estimating pitch */ + if (N0 - 1 < paras.Nmin || N0 == N1) N_ = N0; + else if (N0 + 1 > paras.Nmax || N0 == N2) N_ = N0 - 1; + else if (p_cc->coeff[N0 - paras.Nmin] - p_cc->coeff[N0 - paras.Nmin - 1] < + p_cc->coeff[N0 - paras.Nmin] - p_cc->coeff[N0 - paras.Nmin + 1]) + N_ = N0 - 1; + else + N_ = N0; + xx_N = yy_N = xy_N = y1y1_N = xy1_N = yy1_N = 0.0; + for (j = 0; j < N_; j++) { + x_index = paras.Nmax - N_ + j; + y_index = paras.Nmax + j; + xx_N += (double) seg.data[x_index] * seg.data[x_index]; + yy_N += (double) seg.data[y_index] * seg.data[y_index]; + xy_N += (double) seg.data[x_index] * seg.data[y_index]; + y1y1_N += (double) seg.data[y_index + 1] * seg.data[y_index + 1]; + xy1_N += (double) seg.data[x_index] * seg.data[y_index + 1]; + yy1_N += (double) seg.data[y_index] * seg.data[y_index + 1]; + } + beta = (xy1_N * yy_N - xy_N * yy1_N) / + (xy1_N * (yy_N - yy1_N) + xy_N * (y1y1_N - yy1_N)); + if (beta < 0.0) { + N_--; + beta = 0.0; + } + else if (beta >= 1.0) { + N_++; + beta = 0.0; + } + else + p_status->cc_max = ((1.0 - beta) * xy_N + beta * xy1_N) / + sqrt (xx_N * ((1.0 - beta) * (1.0 - beta) * yy_N + + 2.0 * beta * (1.0 - beta) * yy1_N + + beta * beta * y1y1_N)); + prev_pf = p_status->pitch_freq; + p_status->pitch_freq = (double) (paras.sample_freq) / (double) (N_ + beta); + p_status->v_uv = VOICED; + free_list (&sig_pks_hd); + return; + +} + + + +DetectPitch::DetectPitch() +{ + m_pSrpdOp = new Srpd_Op; + m_pSegment = new SEGMENT_; + m_iSamplesFilledInSegment = 0; + m_pCC = new CROSS_CORR_; + m_pPdaStatus = new STATUS_; +} + +DetectPitch::~DetectPitch() +{ + SAFE_DELETE( m_pSrpdOp ); + SAFE_DELETE( m_pSegment ); + m_iSamplesFilledInSegment = 0; + SAFE_DELETE( m_pCC ); + SAFE_DELETE( m_pPdaStatus ); +} + +void DetectPitch::Init(int iSampleFreq) +{ + default_srpd_op(m_pSrpdOp); // default values + + m_pSrpdOp->sample_freq = iSampleFreq; + initialise_structures (m_pSrpdOp, m_pSegment, m_pCC); + for( int i=0; isize; ++i ) + m_pCC->coeff[i] = 0.0; + initialise_status (*m_pSrpdOp, m_pPdaStatus); + + // add a low-pass filter? +} + +int DetectPitch::ReadOne(RageSoundReader_FileReader *sample) +{ + if( read_next_wave_segment2 (sample, *m_pSrpdOp, m_pSegment) != 0 ) + { + super_resolution_pda (*m_pSrpdOp, *m_pSegment, m_pCC, m_pPdaStatus); + + printf( "track set: (of %d) is %f - voiced %d, held %d\n", m_pSegment->length, m_pPdaStatus->pitch_freq, m_pPdaStatus->v_uv, m_pPdaStatus->s_h ); + return true; + } + + end_structure_use (m_pSegment, m_pCC); + return false; +} + +int DetectPitch::ReadOne(short *pData, int iCount) +{ + //printf("read: size %d shift %d length %d\n", m_pSegment->size, m_pSegment->shift, m_pSegment->length); + + for( int iDataReadCount = 0; iDataReadCount < iCount; ) + { + int iSamplesLeftInSegment = m_pSegment->size - m_iSamplesFilledInSegment; + int iSamplesLeftInData = iCount - iDataReadCount; + int iSamplesToCopy = min( iSamplesLeftInSegment, iSamplesLeftInData ); + + memcpy( m_pSegment->data + m_iSamplesFilledInSegment, pData + iDataReadCount, iSamplesToCopy*sizeof(short) ); + + m_iSamplesFilledInSegment += iSamplesToCopy; + iDataReadCount += iSamplesToCopy; + + ASSERT( m_iSamplesFilledInSegment <= m_pSegment->size ); + if( m_iSamplesFilledInSegment == m_pSegment->size ) // segment is full + { + super_resolution_pda (*m_pSrpdOp, *m_pSegment, m_pCC, m_pPdaStatus); + //printf( "track set: (of %d) is %f - voiced %d, held %d\n", m_pSegment->length, m_pPdaStatus->pitch_freq, m_pPdaStatus->v_uv, m_pPdaStatus->s_h ); + //printf( "v %d, h %d ", m_pPdaStatus->v_uv, m_pPdaStatus->s_h ); + const int iNumBars = 30; + for( int i=0; ipitch_freq < freq) ? "|" : "X" ); + } + //printf( "\n" ); + + int iNumSamplesToShift = m_pSegment->size - m_pSegment->shift; + m_iSamplesFilledInSegment = iNumSamplesToShift; + memcpy( m_pSegment->data, m_pSegment->data + m_pSegment->shift, iNumSamplesToShift*sizeof(short) ); + } + + } + return true; +} + +void DetectPitch::GetStatus( MicrophoneStatus &out ) +{ + out.fFreq = m_pPdaStatus->pitch_freq; + out.fMaxFreq = m_pSrpdOp->max_pitch; + out.bVoiced = m_pPdaStatus->v_uv == VOICED; +} + +void DetectPitch::End() +{ + end_structure_use (m_pSegment, m_pCC); +} + + +void srpd2() +{ + RageFile file; + file.Open( "speech-test.wav" ); + RageSoundReader_FileReader *sample = new RageSoundReader_WAV; + sample->Open( &file ); + + DetectPitch dp; + dp.Init( SAMPLES_PER_SEC ); + while( dp.ReadOne(sample) ) + { + + } +} + + + +/* + * (c) 2007 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/stepmania/src/PitchDetectionTestUtil.h b/stepmania/src/PitchDetectionTestUtil.h index 7c9817e38f..1a3cc90b8b 100644 --- a/stepmania/src/PitchDetectionTestUtil.h +++ b/stepmania/src/PitchDetectionTestUtil.h @@ -1,75 +1,75 @@ -/* PitchDetectionTestUtil - */ - -#ifndef PitchDetectionTestUtil_H -#define PitchDetectionTestUtil_H - -enum EST_bo_t {bo_big, bo_little, bo_perq}; - -static int est_endian_loc = 1; -/* Sun, HP, SGI Mips, M68000 */ -#define EST_BIG_ENDIAN (((char *)&est_endian_loc)[0] == 0) -/* Intel, Alpha, DEC Mips, Vax */ -#define EST_LITTLE_ENDIAN (((char *)&est_endian_loc)[0] != 0) -#define EST_NATIVE_BO (EST_BIG_ENDIAN ? bo_big : bo_little) -#define EST_SWAPPED_BO (EST_BIG_ENDIAN ? bo_little : bo_big) - - -#define SAMPLES_PER_SEC 44100 - -struct Srpd_Op; -struct SEGMENT_; -struct CROSS_CORR_; -struct STATUS_; -class RageSoundReader_FileReader; -struct MicrophoneStatus; - -class DetectPitch -{ - Srpd_Op *m_pSrpdOp; - SEGMENT_ *m_pSegment; - int m_iSamplesFilledInSegment; // how many samples in m_pSegment are filled - CROSS_CORR_ *m_pCC; - STATUS_ *m_pPdaStatus; - -public: - DetectPitch(); - ~DetectPitch(); - - void Init(RageSoundReader_FileReader *sample); - void Init(int iSampleFreq); - int ReadOne(RageSoundReader_FileReader *sample); - int ReadOne(short *pData, int iCount); - void GetStatus( MicrophoneStatus &out ); - void End(); -}; - - - - - -#endif - -/* - * (c) 2004 Chris Danford - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, and/or sell copies of the Software, and to permit persons to - * whom the Software is furnished to do so, provided that the above - * copyright notice(s) and this permission notice appear in all copies of - * the Software and that both the above copyright notice(s) and this - * permission notice appear in supporting documentation. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS - * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +/* PitchDetectionTestUtil - */ + +#ifndef PitchDetectionTestUtil_H +#define PitchDetectionTestUtil_H + +enum EST_bo_t {bo_big, bo_little, bo_perq}; + +static int est_endian_loc = 1; +/* Sun, HP, SGI Mips, M68000 */ +#define EST_BIG_ENDIAN (((char *)&est_endian_loc)[0] == 0) +/* Intel, Alpha, DEC Mips, Vax */ +#define EST_LITTLE_ENDIAN (((char *)&est_endian_loc)[0] != 0) +#define EST_NATIVE_BO (EST_BIG_ENDIAN ? bo_big : bo_little) +#define EST_SWAPPED_BO (EST_BIG_ENDIAN ? bo_little : bo_big) + + +#define SAMPLES_PER_SEC 44100 + +struct Srpd_Op; +struct SEGMENT_; +struct CROSS_CORR_; +struct STATUS_; +class RageSoundReader_FileReader; +struct MicrophoneStatus; + +class DetectPitch +{ + Srpd_Op *m_pSrpdOp; + SEGMENT_ *m_pSegment; + int m_iSamplesFilledInSegment; // how many samples in m_pSegment are filled + CROSS_CORR_ *m_pCC; + STATUS_ *m_pPdaStatus; + +public: + DetectPitch(); + ~DetectPitch(); + + void Init(RageSoundReader_FileReader *sample); + void Init(int iSampleFreq); + int ReadOne(RageSoundReader_FileReader *sample); + int ReadOne(short *pData, int iCount); + void GetStatus( MicrophoneStatus &out ); + void End(); +}; + + + + + +#endif + +/* + * (c) 2004 Chris Danford + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */