From d3f641c0e356ea0bd130a4f30c8a8561f79341a3 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 12:25:41 -0500 Subject: [PATCH 1/9] attempt to fix issue 267 by splitting the check between persistent profile and memory card state --- Themes/_fallback/Scripts/03 CustomSpeedMods.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Themes/_fallback/Scripts/03 CustomSpeedMods.lua b/Themes/_fallback/Scripts/03 CustomSpeedMods.lua index 7a98da4eae..4886712686 100644 --- a/Themes/_fallback/Scripts/03 CustomSpeedMods.lua +++ b/Themes/_fallback/Scripts/03 CustomSpeedMods.lua @@ -212,10 +212,11 @@ local function GetSpeedMods() local playerMods = {} for pn in ivalues(GAMESTATE:GetHumanPlayers()) do - -- file loading logic per player; - -- only bother if it's not the machine profile though. - if PROFILEMAN:IsPersistentProfile(pn) or - MEMCARDMAN:GetCardState(pn) == 'MemoryCardState_ready' then + -- file loading logic per player. + if PROFILEMAN:IsPersistentProfile(pn) then + playerMods[#playerMods+1] = ParseSpeedModFile(profileDirs[pn]..baseFilename) + -- we need to make sure the memory card is ready if we're gonna grab from it. + elseif MEMCARDMAN:GetCardState(pn) == 'MemoryCardState_ready' then playerMods[#playerMods+1] = ParseSpeedModFile(profileDirs[pn]..baseFilename) end end From 06c447026db7deffcce53dc60840654529fccb32 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 12:54:21 -0500 Subject: [PATCH 2/9] [ScreenGameplay, LyricDisplay] Stop lyrics from animating on failure. Fixes issue 298. --- Docs/Changelog_sm5.txt | 5 +++++ src/LyricDisplay.cpp | 8 ++++++++ src/LyricDisplay.h | 4 ++++ src/ScreenGameplay.cpp | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 4cf748f4f7..0c6ff362cf 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,11 @@ ________________________________________________________________________________ StepMania 5.0 Preview 3 | 20110??? -------------------------------------------------------------------------------- +2011/07/31 +---------- +* [ScreenGameplay, LyricDisplay] Stop lyrics from animating on failure. + Fixes issue 298. [AJ] + 2011/07/30 ---------- * [ProfileManager] Fix an issue when deleting recently created profiles. [AJ] diff --git a/src/LyricDisplay.cpp b/src/LyricDisplay.cpp index b896814e1d..5454652d3b 100644 --- a/src/LyricDisplay.cpp +++ b/src/LyricDisplay.cpp @@ -31,10 +31,18 @@ void LyricDisplay::Init() m_iCurLyricNumber = 0; m_fLastSecond = -500; + m_bStopped = false; +} + +void LyricDisplay::Stop() { + m_bStopped = true; } void LyricDisplay::Update( float fDeltaTime ) { + if( m_bStopped ) + return; + ActorFrame::Update( fDeltaTime ); if( GAMESTATE->m_pCurSong == NULL ) diff --git a/src/LyricDisplay.h b/src/LyricDisplay.h index da6d811063..7225ef0b1e 100644 --- a/src/LyricDisplay.h +++ b/src/LyricDisplay.h @@ -13,10 +13,14 @@ public: // Call when song changes: void Init(); + // Call on song failed: + void Stop(); + private: BitmapText m_textLyrics[2]; unsigned m_iCurLyricNumber; float m_fLastSecond; + bool m_bStopped; }; #endif diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index 5e9ddbf5db..e5e1b7dfd4 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -1713,7 +1713,7 @@ void ScreenGameplay::Update( float fDeltaTime ) { m_pSoundMusic->StopPlaying(); SCREENMAN->PostMessageToTopScreen( SM_NotesEnded, 0 ); - // todo: stop lyrics (m_LyricDisplay) from animating -aj + m_LyricDisplay.Stop(); } // Update living players' alive time From eaacc41624d7ff25f21eec0a6045365ae1bb98cd Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 15:15:58 -0500 Subject: [PATCH 3/9] fix typo --- Docs/Changelog_sm-ssc.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Docs/Changelog_sm-ssc.txt b/Docs/Changelog_sm-ssc.txt index f2ed5cb0a5..fe3c392291 100644 --- a/Docs/Changelog_sm-ssc.txt +++ b/Docs/Changelog_sm-ssc.txt @@ -1171,7 +1171,7 @@ sm-ssc v1.0 Public Beta 2 | 20100331 20100309 -------- * [ScreenSelectMaster] Add GetSelectionIndex(pn) Lua binding. (You'll have to - call this one using GAMESTATE:GetTopScreen():GetSelectionIndex(PLAYER_1) or + call this one using SCREENMAN:GetTopScreen():GetSelectionIndex(PLAYER_1) or something like that.) 20100308 @@ -1246,7 +1246,6 @@ helper functions available to you in scripts via the fallback theme, either. :) -------- * [Player] CheckpointsFlashOnHold metric added. Fixes issue 16. - 20100222 -------- * [CodeDetector] NextBannerGroup and NextBannerGroup2 were previously used From 33efb74897bb12aaabe797ae78befb51399035e9 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 15:33:16 -0500 Subject: [PATCH 4/9] Changed the (still incomplete) beginner guide up slightly --- .../{sm-ssc_beginner.txt => sm5_beginner.txt} | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) rename Docs/Userdocs/{sm-ssc_beginner.txt => sm5_beginner.txt} (95%) diff --git a/Docs/Userdocs/sm-ssc_beginner.txt b/Docs/Userdocs/sm5_beginner.txt similarity index 95% rename from Docs/Userdocs/sm-ssc_beginner.txt rename to Docs/Userdocs/sm5_beginner.txt index 6331eed27a..24c31d8535 100644 --- a/Docs/Userdocs/sm-ssc_beginner.txt +++ b/Docs/Userdocs/sm5_beginner.txt @@ -1,4 +1,4 @@ -sm-ssc Beginner's Guide +StepMania 5 Beginner's Guide Written and edited by the spinal shark collective -------------------------------------------------------------------------------- Table of Contents @@ -14,15 +14,15 @@ Table of Contents 2.3.1 Installing Song Files 2.3.2 Installing Noteskins/New Gametypes 2.3.3 Installing Themes -3. sm-ssc +3. StepMania 5 ================================================================================ Chapter 1: Introduction ================================================================================ -Welcome to the sm-ssc Beginner's Guide. This guide is primarily meant for people -who do not have any previous experience with StepMania, but also includes -information on how sm-ssc differs from StepMania. If you already know what -StepMania is, and the basics of adding things to an install, you can skip ahead -to Chapter 3: sm-ssc. Otherwise, read on. +Welcome to the StepMania 5 Beginner's Guide. This guide is primarily meant for +people who do not have any previous experience with StepMania, but also includes +information on how SM5 differs from previous StepMania versions. If you already +know what StepMania is, and the basics of adding things to an install, you can +skip ahead to Chapter 3: StepMania 5. Otherwise, read on. ================================================================================ Chapter 2: StepMania @@ -372,8 +372,9 @@ When in doubt, read any documentation that comes with the theme for proper installation instructions. ================================================================================ -Chapter 3: sm-ssc +Chapter 3: StepMania 5 ================================================================================ -sm-ssc is a fork of the current StepMania codebase. It is focused on adding -features for theming, but also tries to make the process of dealing with -StepMania a little easier. \ No newline at end of file +The modern StepMania 5 originally began life as sm-ssc, a fork of StepMania 4 +alpha 5 (later renamed to StepMania 5 after the reboot of SM4). sm-ssc was a fork +focused on adding features for theming, but also tried to make the process of +dealing with StepMania a little easier. \ No newline at end of file From 8fdbe14070057e25a2bc5dd1ba50482121679bfc Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 15:54:40 -0500 Subject: [PATCH 5/9] typo --- Docs/KnownIssues.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Docs/KnownIssues.txt b/Docs/KnownIssues.txt index 316ac8b979..3786bfe1b6 100644 --- a/Docs/KnownIssues.txt +++ b/Docs/KnownIssues.txt @@ -2,7 +2,7 @@ The following is a list of known issues with StepMania 5. * Hidden, Sudden, Stealth, and RandomVanish do not work with layered note skins. Random Vanish, in particular, has caused crashes. -* The course editor is not working completley. +* The course editor is not working completely. * The scoring system needs to be made global for the game instead of tying it to the theme. Right now, this is causing a number of themes to have no score display during gameplay. From cface7fd1c215b19e41af6d0fdc63ed4d8b256d6 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 16:00:08 -0500 Subject: [PATCH 6/9] add kiu source location --- Docs/opensource_simulators.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Docs/opensource_simulators.txt b/Docs/opensource_simulators.txt index b95a0f45f0..0e0148b6df 100644 --- a/Docs/opensource_simulators.txt +++ b/Docs/opensource_simulators.txt @@ -14,4 +14,7 @@ be-pachi music [MIT license] http://x-raise.cjb.net/bpm.html marfitude [GPL license] -http://www.erestar.net/games/marfitude/ \ No newline at end of file +http://www.erestar.net/games/marfitude/ + +Kick it Up [unknown license] +http://club.paran.com/club/home.do?clubid=prg-bbsView.do?menuno=7209-clubno=291-bbs_no=0L6DV \ No newline at end of file From 7da8cceb103118c10bb9d1a4bd86146cb4d69333 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 16:01:57 -0500 Subject: [PATCH 7/9] sm-ssc -> sm5 --- Docs/WindowsNotes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Docs/WindowsNotes.txt b/Docs/WindowsNotes.txt index 4cc2d13f9f..81d6261bc2 100644 --- a/Docs/WindowsNotes.txt +++ b/Docs/WindowsNotes.txt @@ -1,5 +1,5 @@ [IMPORTANT INSTALL NOTE] -If you are using Windows Vista or Windows 7, please do not install StepMania SSC into the Program Files directory. +If you are using Windows Vista or Windows 7, please do not install StepMania 5 into the Program Files directory. [Using Google Chrome?] If you are using Google Chrome as your primary web browser, you will have to perform some extra steps to get stepmania:// URI handling to work: From 3de51c349856d50be70ce023e727d06467ba05a5 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 16:02:26 -0500 Subject: [PATCH 8/9] We no longer use NotesLoaderMidi --- Docs/Licenses.txt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Docs/Licenses.txt b/Docs/Licenses.txt index 03828b8447..5b8b8ff429 100644 --- a/Docs/Licenses.txt +++ b/Docs/Licenses.txt @@ -148,20 +148,3 @@ POSSIBILITY OF SUCH DAMAGE. The MAD library (included with most Windows binary distributions), and interface code in RageSoundReader_MP3, is under the GPL, available in Copying.MAD. Support for this library can be disabled at compile-time. - -****************************************************************************** - -NotesLoaderMidi contains code from STK under the following license: - -Copyright 2003 Gary P. Scavone - -LEGAL AND ETHICAL: - -This software was designed and created to be made publicly available for -free, primarily for academic purposes, so if you use it, pass it on with -this documentation, and for free. - -On April 19 2007, StepMania was granted an MIT license by Gary Scavone -for any STK code on the condition that all of the the STK -credits/disclaimers/copyrights from the README are retained in the -source code and in the project documentation. From 711b285e6159c67781b4d872bb7c5d5665191dc5 Mon Sep 17 00:00:00 2001 From: AJ Kelly Date: Sun, 31 Jul 2011 16:04:50 -0500 Subject: [PATCH 9/9] nuke unused PitchDetectionTest stuff --- src/PitchDetectionTest.cpp | 386 ---- src/PitchDetectionTest.h | 62 - src/PitchDetectionTestUtil.cpp | 3385 -------------------------------- src/PitchDetectionTestUtil.h | 75 - 4 files changed, 3908 deletions(-) delete mode 100644 src/PitchDetectionTest.cpp delete mode 100644 src/PitchDetectionTest.h delete mode 100644 src/PitchDetectionTestUtil.cpp delete mode 100644 src/PitchDetectionTestUtil.h diff --git a/src/PitchDetectionTest.cpp b/src/PitchDetectionTest.cpp deleted file mode 100644 index 08ec6f9e74..0000000000 --- a/src/PitchDetectionTest.cpp +++ /dev/null @@ -1,386 +0,0 @@ -#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/src/PitchDetectionTest.h b/src/PitchDetectionTest.h deleted file mode 100644 index 047ee2059f..0000000000 --- a/src/PitchDetectionTest.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Microphone - Holdover from incomplete karaoke mode. */ - -#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/src/PitchDetectionTestUtil.cpp b/src/PitchDetectionTestUtil.cpp deleted file mode 100644 index 0abb27d6cf..0000000000 --- a/src/PitchDetectionTestUtil.cpp +++ /dev/null @@ -1,3385 +0,0 @@ - /*************************************************************************/ - /* */ - /* Centre for Speech Technology Research */ - /* University of Edinburgh, UK */ - /* Copyright (c) 1995,1996 */ - /* All Rights Reserved. */ - /* Permission is hereby granted, free of charge, to use and distribute */ - /* this software and its documentation without restriction, including */ - /* without limitation the rights to use, copy, modify, merge, publish, */ - /* distribute, sublicense, and/or sell copies of this work, and to */ - /* permit persons to whom this work is furnished to do so, subject to */ - /* the following conditions: */ - /* 1. The code must retain the above copyright notice, this list of */ - /* conditions and the following disclaimer. */ - /* 2. Any modifications must be clearly marked as such. */ - /* 3. Original authors' names are not deleted. */ - /* 4. The authors' names are not used to endorse or promote products */ - /* derived from this software without specific prior written */ - /* permission. */ - /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ - /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ - /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ - /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ - /* FOR 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. */ - /* */ - /*************************************************************************/ -/* 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. - */ diff --git a/src/PitchDetectionTestUtil.h b/src/PitchDetectionTestUtil.h deleted file mode 100644 index 8663dfae35..0000000000 --- a/src/PitchDetectionTestUtil.h +++ /dev/null @@ -1,75 +0,0 @@ -/* PitchDetectionTestUtil - Holdover from incomplete karaoke mode. */ - -#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. - */