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

KonstantinSource codes8c4603c

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