yum-archive/TaSTT-Whisper
High-performance GPGPU inference of OpenAI's Whisper automatic speech recognition (ASR) model
git clone https://git.yummers.dev/yum-archive/TaSTT-Whisper
8c4603c
master
1#include "stdafx.h" 2#include "miscUtils.h" 3 4namespace 5{ 6wchar_t * formatMessage (HRESULT hr ) 7 { 8wchar_t * err ; 9if (FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM , 10NULL , 11hr , 12MAKELANGID (LANG_NEUTRAL ,SUBLANG_DEFAULT ), 13 (LPTSTR )& err , 140 , 15NULL ) ) 16return err ; 17return nullptr ; 18 } 19} 20 21CString formatErrorMessage (HRESULT hr ) 22{ 23CString message ; 24const wchar_t * err = formatMessage (hr ); 25if (nullptr != err ) 26 { 27message = err ; 28LocalFree ( (HLOCAL )err ); 29message .TrimRight (); 30 } 31else 32message .Format (L"Error code %i (0x%08X)" ,hr ,hr ); 33 34return message ; 35} 36 37void reportFatalError (const char * what ,HRESULT hr ) 38{ 39CString message ; 40message .Format (L"%S\n%S\n" ,"Unable to start the application." ,what ); 41message += formatErrorMessage (hr ); 42 ::MessageBox (nullptr ,message ,L"Whisper Desktop Startup" ,MB_OK |MB_ICONERROR ); 43} 44 45namespace 46{ 47using Whisper ::eModelImplementation ; 48 49struct sImplString 50 { 51eModelImplementation val ; 52LPCTSTR str ; 53 }; 54static const std::array < sImplString ,3 > s_implStrings = 55 { 56sImplString { eModelImplementation::GPU ,L"GPU" }, 57sImplString { eModelImplementation::Hybrid ,L"Hybrid" }, 58sImplString { eModelImplementation::Reference ,L"Reference" }, 59 }; 60} 61 62HRESULT implParse (const CString & s ,eModelImplementation & rdi ) 63{ 64for (const auto & is :s_implStrings ) 65 { 66if (0 != s .CompareNoCase (is .str ) ) 67continue ; 68rdi = is .val ;; 69return S_OK ; 70 } 71return E_INVALIDARG ; 72} 73 74LPCTSTR implString (eModelImplementation i ) 75{ 76for (const auto & is :s_implStrings ) 77if (is .val == i ) 78return is .str ; 79return nullptr ; 80} 81 82void implPopulateCombobox (CComboBox & cb ,Whisper ::eModelImplementation impl ) 83{ 84int curSel = 0 ; 85int idx = 0 ; 86for (const auto & is :s_implStrings ) 87 { 88cb .AddString (is .str ); 89if (is .val == impl ) 90curSel = idx ; 91idx ++ ; 92 } 93cb .SetCurSel (curSel ); 94} 95 96Whisper ::eModelImplementation implGetValue (CComboBox & cb ) 97{ 98int curSel = cb .GetCurSel (); 99if (curSel < 0 ) 100return (Whisper ::eModelImplementation )0 ; 101return s_implStrings [curSel ].val ; 102} 103 104ThreadPoolWork ::~ThreadPoolWork () 105{ 106if (nullptr != work ) 107 { 108CloseThreadpoolWork (work ); 109work = nullptr ; 110 } 111} 112 113void __stdcallThreadPoolWork ::callback (PTP_CALLBACK_INSTANCE Instance ,PVOID Context ,PTP_WORK Work ) 114{ 115iThreadPoolCallback * cb = (iThreadPoolCallback * )Context ; 116cb -> poolCallback (); 117} 118 119HRESULT ThreadPoolWork ::create (iThreadPoolCallback * cb ) 120{ 121if (nullptr == cb ) 122return E_POINTER ; 123if (nullptr != work ) 124return HRESULT_FROM_WIN32 (ERROR_ALREADY_INITIALIZED ); 125 126work = CreateThreadpoolWork (& callback ,cb ,nullptr ); 127if (nullptr != work ) 128return S_OK ; 129 130return HRESULT_FROM_WIN32 (GetLastError () ); 131} 132 133HRESULT ThreadPoolWork ::post () 134{ 135if (nullptr == work ) 136return OLE_E_BLANK ; 137SubmitThreadpoolWork (work ); 138return S_OK ; 139} 140 141void makeUtf16 (CString & rdi ,const char * utf8 ) 142{ 143const size_t length = strlen (utf8 ); 144int count = MultiByteToWideChar (CP_UTF8 ,0 ,utf8 , (int )length ,nullptr ,0 ); 145wchar_t * p = rdi .GetBufferSetLength (count ); 146MultiByteToWideChar (CP_UTF8 ,0 ,utf8 , (int )length ,p ,count ); 147rdi .ReleaseBuffer (); 148} 149 150void makeUtf8 (CStringA & rdi ,const CString & utf16 ) 151{ 152int count = WideCharToMultiByte (CP_UTF8 ,0 ,utf16 ,utf16 .GetLength (),nullptr ,0 ,nullptr ,nullptr ); 153char * s = rdi .GetBufferSetLength (count + 1 ); 154count = WideCharToMultiByte (CP_UTF8 ,0 ,utf16 ,utf16 .GetLength (),s ,count ,nullptr ,nullptr ); 155rdi .ReleaseBufferSetLength (count ); 156} 157 158constexpr int ofnBufferLength = 2048 ; 159 160bool getOpenFileName (HWND owner ,LPCTSTR title ,LPCTSTR filter ,CString & path ) 161{ 162wchar_t buffer [ofnBufferLength ]; 163buffer [0 ]= 0 ; 164OPENFILENAME ofn ; 165memset (& ofn ,0 ,sizeof (ofn ) ); 166ofn .lStructSize = sizeof (OPENFILENAME ); 167ofn .hwndOwner = owner ; 168ofn .lpstrFilter = filter ; 169ofn .lpstrTitle = title ; 170ofn .Flags = OFN_EXPLORER |OFN_FILEMUSTEXIST |OFN_PATHMUSTEXIST ; 171ofn .lpstrFile = buffer ; 172ofn .nMaxFile = ofnBufferLength - 1 ; 173 174CString dir ; 175if (path .GetLength ()> 0 && path .GetLength ()< ofnBufferLength ) 176wcsncpy_s (buffer ,path ,path .GetLength () ); 177 178if ( !GetOpenFileName (& ofn ) ) 179 { 180path = L"" ; 181return false; 182 } 183else 184 { 185path = ofn .lpstrFile ; 186return true; 187 } 188} 189 190bool getSaveFileName (HWND owner ,LPCTSTR title ,LPCTSTR filter ,CString & path ,DWORD * filterIndex ) 191{ 192wchar_t buffer [ofnBufferLength ]; 193buffer [0 ]= 0 ; 194 195OPENFILENAME ofn ; 196memset (& ofn ,0 ,sizeof (ofn ) ); 197ofn .lStructSize = sizeof (OPENFILENAME ); 198ofn .hwndOwner = owner ; 199ofn .lpstrFilter = filter ; 200ofn .lpstrTitle = title ; 201ofn .Flags = OFN_EXPLORER |OFN_PATHMUSTEXIST ; 202ofn .lpstrFile = buffer ; 203ofn .nMaxFile = ofnBufferLength - 1 ; 204if (nullptr != filterIndex ) 205ofn .nFilterIndex = * filterIndex + 1 ; 206 207if (path .GetLength ()> 0 && path .GetLength ()< ofnBufferLength ) 208wcsncpy_s (buffer ,path ,path .GetLength () ); 209 210if ( !GetSaveFileName (& ofn ) ) 211return false; 212 213path = ofn .lpstrFile ; 214 215if (nullptr != filterIndex ) 216* filterIndex = ofn .nFilterIndex - 1 ; 217 218return true; 219} 220 221void reportError (HWND owner ,LPCTSTR text ,LPCTSTR title ,HRESULT hr ) 222{ 223if (nullptr == title ) 224title = L"Operation Failed" ; 225 226CString message = text ; 227message .TrimRight (); 228if (FAILED (hr ) ) 229 { 230message += L"\n" ; 231message += formatErrorMessage (hr ); 232 } 233 234 ::MessageBox (owner ,message ,title ,MB_OK |MB_ICONWARNING ); 235} 236 237HRESULT writeUtf8Bom (CAtlFile & file ) 238{ 239const std::array < uint8_t ,3 > bom = {0xEF ,0xBB ,0xBF }; 240return file .Write (bom .data (),3 ); 241} 242 243bool isInvalidTranslate (HWND owner ,uint32_t lang ,bool translate ) 244{ 245if ( !translate ) 246return false; 247constexpr uint32_t english = 0x6E65 ; 248if (lang != english ) 249return false; 250 251LPCTSTR message = L"The translate feature translates speech to English.\nIt’s not available when the audio language is already English." ; 252MessageBox (owner ,message ,L"Incompatible parameters" ,MB_OK |MB_ICONINFORMATION ); 253return true; 254}