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 "../ComLightLib/comLightServer.h" 3#include "loadAudioFile.h" 4#include "mfUtils.h" 5#include "AudioBuffer.h" 6#include <mfidl.h> 7#include <mfreadwrite.h> 8#include <mfapi.h> 9#pragma comment(lib, "Mfreadwrite.lib") 10#pragma comment(lib, "mfuuid.lib") 11 12namespace Whisper 13{ 14class MediaFileBuffer :public ComLight ::ObjectRoot < iAudioBuffer > 15 { 16AudioBuffer pcm ; 17uint32_t channels = 0 ; 18 19uint32_t COMLIGHTCALL countSamples ()const noexcept override final 20 { 21return (uint32_t )(pcm .mono .size () ); 22 } 23const float * COMLIGHTCALL getPcmMono ()const noexcept override final 24 { 25if ( !pcm .mono .empty () ) 26return pcm .mono .data (); 27return nullptr ; 28 } 29const float * COMLIGHTCALL getPcmStereo ()const noexcept override final 30 { 31if ( !pcm .stereo .empty () ) 32return pcm .stereo .data (); 33return nullptr ; 34 } 35HRESULT COMLIGHTCALL getTime (int64_t & rdi )const noexcept override final 36 { 37rdi = 0 ; 38return S_OK ; 39 } 40public : 41HRESULT load (LPCTSTR path ,bool stereo ); 42 }; 43 44HRESULT MediaFileBuffer ::load (LPCTSTR path ,bool stereo ) 45 { 46CComPtr < IMFSourceReader > reader ; 47HRESULT hr = MFCreateSourceReaderFromURL (path ,nullptr ,& reader ); 48if (FAILED (hr ) ) 49 { 50logErrorHr (hr ,u8"MFCreateSourceReaderFromURL failed" ); 51return hr ; 52 } 53 54CHECK (reader -> SetStreamSelection (MF_SOURCE_READER_ALL_STREAMS , FALSE ) ); 55CHECK (reader -> SetStreamSelection (MF_SOURCE_READER_FIRST_AUDIO_STREAM , TRUE ) ); 56 57CComPtr < IMFMediaType > mtNative ; 58CHECK (reader -> GetNativeMediaType (MF_SOURCE_READER_FIRST_AUDIO_STREAM ,MF_SOURCE_READER_CURRENT_TYPE_INDEX ,& mtNative ) ); 59UINT32 numChannels ; 60CHECK (mtNative -> GetUINT32 (MF_MT_AUDIO_NUM_CHANNELS ,& numChannels ) ); 61const bool sourceMono = numChannels == 1 ; 62const AudioBuffer ::pfnAppendSamples pfn = AudioBuffer ::appendSamplesFunc (sourceMono ,stereo ); 63channels = (stereo && !sourceMono ) ?2 :1 ; 64 65CComPtr < IMFMediaType > mt ; 66CHECK (createMediaType ( !sourceMono ,& mt ) ); 67 68CHECK (reader -> SetCurrentMediaType (MF_SOURCE_READER_FIRST_AUDIO_STREAM ,nullptr ,mt ) ); 69 70while ( true ) 71 { 72DWORD dwFlags = 0 ; 73CComPtr < IMFSample > sample ; 74 75// Read the next sample. 76hr = reader -> ReadSample ( (DWORD )MF_SOURCE_READER_FIRST_AUDIO_STREAM ,0 ,nullptr ,& dwFlags ,nullptr ,& sample ); 77if (FAILED (hr ) ) 78 { 79logErrorHr (hr ,u8"IMFSourceReader.ReadSample" ); 80return hr ; 81 } 82 83if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED ) 84 { 85logError (u8"Media type changes ain’t supported by the library." ); 86return E_UNEXPECTED ; 87 } 88 89if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM ) 90break ; 91 92if ( !sample ) 93 { 94// printf( "No sample\n" ); 95continue ; 96 } 97 98// Get a pointer to the audio data in the sample. 99CComPtr < IMFMediaBuffer > buffer ; 100hr = sample -> ConvertToContiguousBuffer (& buffer ); 101if (FAILED (hr ) ) 102return hr ; 103 104const float * pAudioData = nullptr ; 105DWORD cbBuffer ; 106hr = buffer -> Lock ( (BYTE ** )& pAudioData ,nullptr ,& cbBuffer ); 107if (FAILED (hr ) ) 108return hr ; 109 110try 111 { 112const size_t countFloats = cbBuffer /sizeof (float ); 113 (pcm .*pfn )(pAudioData ,countFloats ); 114 } 115catch (const std::bad_alloc & ) 116 { 117return E_OUTOFMEMORY ; 118 } 119 120// Unlock the buffer 121hr = buffer -> Unlock (); 122if (FAILED (hr ) ) 123return hr ; 124 } 125 126const size_t len = pcm .mono .size (); 127if (len == 0 ) 128 { 129logError16 (L"The audio file \"%s\" has no samples" ,path ); 130return E_INVALIDARG ; 131 } 132if (len < SAMPLE_RATE /2 ) 133logError16 (L"The file \"%s\" only has %zu samples, less than 0.5 seconds of audio" ,path ,len ); 134else 135logDebug16 (L"Loaded audio file from \"%s\": %zu samples, %g seconds" ,path ,len , (int )len * (1.0 /SAMPLE_RATE ) ); 136return S_OK ; 137 138 } 139} 140 141HRESULT COMLIGHTCALL Whisper ::loadAudioFile (LPCTSTR path ,bool stereo ,iAudioBuffer ** pp ) 142{ 143if (nullptr == path || nullptr == pp ) 144return E_POINTER ; 145 146ComLight ::CComPtr < ComLight ::Object < MediaFileBuffer >> obj ; 147CHECK (ComLight ::Object < MediaFileBuffer > ::create (obj ) ); 148CHECK (obj -> load (path ,stereo ) ); 149obj .detach (pp ); 150return S_OK ; 151}