mirror of
https://github.com/Const-me/Whisper.git
synced 2026-10-21 14:52:08 +08:00
f5d7024141
Issue #46
622 lines
17 KiB
C++
622 lines
17 KiB
C++
#include "stdafx.h"
|
|
#include "TranscribeDlg.h"
|
|
#include "Utils/logger.h"
|
|
|
|
HRESULT TranscribeDlg::show()
|
|
{
|
|
auto res = DoModal( nullptr );
|
|
if( res == -1 )
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
switch( res )
|
|
{
|
|
case IDC_BACK:
|
|
return SCREEN_MODEL;
|
|
case IDC_CAPTURE:
|
|
return SCREEN_CAPTURE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
constexpr int progressMaxInteger = 1024 * 8;
|
|
|
|
static const LPCTSTR regValInput = L"sourceMedia";
|
|
static const LPCTSTR regValOutFormat = L"resultFormat";
|
|
static const LPCTSTR regValOutPath = L"resultPath";
|
|
static const LPCTSTR regValUseInputFolder = L"useInputFolder";
|
|
|
|
LRESULT TranscribeDlg::OnInitDialog( UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
|
|
{
|
|
// First DDX call, hooks up variables to controls.
|
|
DoDataExchange( false );
|
|
printModelDescription();
|
|
languageSelector.initialize( m_hWnd, IDC_LANGUAGE, appState );
|
|
cbConsole.initialize( m_hWnd, IDC_CONSOLE, appState );
|
|
cbTranslate.initialize( m_hWnd, IDC_TRANSLATE, appState );
|
|
populateOutputFormats();
|
|
|
|
pendingState.initialize(
|
|
{
|
|
languageSelector, GetDlgItem( IDC_TRANSLATE ),
|
|
sourceMediaPath, GetDlgItem( IDC_BROWSE_MEDIA ),
|
|
transcribeOutFormat, useInputFolder,
|
|
transcribeOutputPath, GetDlgItem( IDC_BROWSE_RESULT ),
|
|
GetDlgItem( IDCANCEL ),
|
|
GetDlgItem( IDC_BACK ),
|
|
GetDlgItem( IDC_CAPTURE )
|
|
},
|
|
{
|
|
progressBar, GetDlgItem( IDC_PENDING_TEXT )
|
|
} );
|
|
|
|
HRESULT hr = work.create( this );
|
|
if( FAILED( hr ) )
|
|
{
|
|
reportError( m_hWnd, L"CreateThreadpoolWork failed", nullptr, hr );
|
|
EndDialog( IDCANCEL );
|
|
}
|
|
|
|
progressBar.SetRange32( 0, progressMaxInteger );
|
|
progressBar.SetStep( 1 );
|
|
|
|
sourceMediaPath.SetWindowText( appState.stringLoad( regValInput ) );
|
|
transcribeOutFormat.SetCurSel( (int)appState.dwordLoad( regValOutFormat, 0 ) );
|
|
transcribeOutputPath.SetWindowText( appState.stringLoad( regValOutPath ) );
|
|
if( appState.boolLoad( regValUseInputFolder ) )
|
|
useInputFolder.SetCheck( BST_CHECKED );
|
|
BOOL unused;
|
|
onOutFormatChange( 0, 0, nullptr, unused );
|
|
|
|
appState.lastScreenSave( SCREEN_TRANSCRIBE );
|
|
appState.setupIcon( this );
|
|
ATLVERIFY( CenterWindow() );
|
|
return 0;
|
|
}
|
|
|
|
void TranscribeDlg::printModelDescription()
|
|
{
|
|
CString text;
|
|
if( S_OK == appState.model->isMultilingual() )
|
|
text = L"Multilingual";
|
|
else
|
|
text = L"Single-language";
|
|
text += L" model \"";
|
|
LPCTSTR path = appState.source.path;
|
|
path = ::PathFindFileName( path );
|
|
text += path;
|
|
text += L"\", ";
|
|
const int64_t cb = appState.source.sizeInBytes;
|
|
if( cb < 1 << 30 )
|
|
{
|
|
constexpr double mul = 1.0 / ( 1 << 20 );
|
|
double mb = (double)cb * mul;
|
|
text.AppendFormat( L"%.1f MB", mb );
|
|
}
|
|
else
|
|
{
|
|
constexpr double mul = 1.0 / ( 1 << 30 );
|
|
double gb = (double)cb * mul;
|
|
text.AppendFormat( L"%.2f GB", gb );
|
|
}
|
|
text += L" on disk, ";
|
|
text += implString( appState.source.impl );
|
|
text += L" implementation";
|
|
|
|
modelDesc.SetWindowText( text );
|
|
}
|
|
|
|
// Populate the "Output Format" combobox
|
|
void TranscribeDlg::populateOutputFormats()
|
|
{
|
|
transcribeOutFormat.AddString( L"None" );
|
|
transcribeOutFormat.AddString( L"Text file" );
|
|
transcribeOutFormat.AddString( L"Text with timestamps" );
|
|
transcribeOutFormat.AddString( L"SubRip subtitles" );
|
|
transcribeOutFormat.AddString( L"WebVTT subtitles" );
|
|
}
|
|
|
|
// The enum values should match 0-based indices of the combobox items
|
|
enum struct TranscribeDlg::eOutputFormat : uint8_t
|
|
{
|
|
None = 0,
|
|
Text = 1,
|
|
TextTimestamps = 2,
|
|
SubRip = 3,
|
|
WebVTT = 4,
|
|
};
|
|
|
|
enum struct TranscribeDlg::eVisualState : uint8_t
|
|
{
|
|
Idle = 0,
|
|
Running = 1,
|
|
Stopping = 2
|
|
};
|
|
|
|
// CBN_SELCHANGE notification for IDC_OUTPUT_FORMAT combobox
|
|
LRESULT TranscribeDlg::onOutFormatChange( UINT, INT, HWND, BOOL& bHandled )
|
|
{
|
|
BOOL enabled = transcribeOutFormat.GetCurSel() != 0;
|
|
useInputFolder.EnableWindow( enabled );
|
|
|
|
if( isChecked( useInputFolder ) && enabled )
|
|
{
|
|
enabled = FALSE;
|
|
setOutputPath();
|
|
}
|
|
transcribeOutputPath.EnableWindow( enabled );
|
|
transcribeOutputBrowse.EnableWindow( enabled );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// EN_CHANGE notification for IDC_PATH_MEDIA edit box
|
|
LRESULT TranscribeDlg::onInputChange( UINT, INT, HWND, BOOL& )
|
|
{
|
|
if( !useInputFolder.IsWindowEnabled() )
|
|
return 0;
|
|
if( !isChecked( useInputFolder ) )
|
|
return 0;
|
|
setOutputPath();
|
|
return 0;
|
|
}
|
|
|
|
void TranscribeDlg::onBrowseMedia()
|
|
{
|
|
LPCTSTR title = L"Input audio file to transcribe";
|
|
LPCTSTR filters = L"Multimedia Files\0*.wav;*.wave;*.mp3;*.wma;*.mp4;*.mpeg4;*.mkv;*.m4a\0\0";
|
|
|
|
CString path;
|
|
sourceMediaPath.GetWindowText( path );
|
|
if( !getOpenFileName( m_hWnd, title, filters, path ) )
|
|
return;
|
|
sourceMediaPath.SetWindowText( path );
|
|
if( useInputFolder.IsWindowEnabled() && useInputFolder.GetCheck() == BST_CHECKED )
|
|
setOutputPath( path );
|
|
}
|
|
|
|
static const LPCTSTR outputFilters = L"Text files (*.txt)\0*.txt\0Text with timestamps (*.txt)\0*.txt\0SubRip subtitles (*.srt)\0*.srt\0WebVTT subtitles (*.vtt)\0*.vtt\0\0";
|
|
static const std::array<LPCTSTR, 4> outputExtensions =
|
|
{
|
|
L".txt", L".txt", L".srt", L".vtt"
|
|
};
|
|
|
|
void TranscribeDlg::setOutputPath( const CString& input )
|
|
{
|
|
const int format = transcribeOutFormat.GetCurSel() - 1;
|
|
if( format < 0 || format >= outputExtensions.size() )
|
|
return;
|
|
const LPCTSTR ext = outputExtensions[ format ];
|
|
CString path = input;
|
|
path.Trim();
|
|
const bool renamed = PathRenameExtension( path.GetBufferSetLength( path.GetLength() + 4 ), ext );
|
|
path.ReleaseBuffer();
|
|
if( !renamed )
|
|
return;
|
|
transcribeOutputPath.SetWindowText( path );
|
|
}
|
|
|
|
void TranscribeDlg::setOutputPath()
|
|
{
|
|
CString path;
|
|
if( !sourceMediaPath.GetWindowText( path ) )
|
|
return;
|
|
if( path.GetLength() <= 0 )
|
|
return;
|
|
setOutputPath( path );
|
|
}
|
|
|
|
void TranscribeDlg::onInputFolderCheck()
|
|
{
|
|
const bool checked = isChecked( useInputFolder );
|
|
|
|
BOOL enableOutput = checked ? FALSE : TRUE;
|
|
transcribeOutputPath.EnableWindow( enableOutput );
|
|
transcribeOutputBrowse.EnableWindow( enableOutput );
|
|
|
|
if( !checked )
|
|
return;
|
|
setOutputPath();
|
|
}
|
|
|
|
void TranscribeDlg::onBrowseOutput()
|
|
{
|
|
const DWORD origFilterIndex = (DWORD)transcribeOutFormat.GetCurSel() - 1;
|
|
|
|
LPCTSTR title = L"Output Text File";
|
|
CString path;
|
|
transcribeOutputPath.GetWindowText( path );
|
|
DWORD filterIndex = origFilterIndex;
|
|
if( !getSaveFileName( m_hWnd, title, outputFilters, path, &filterIndex ) )
|
|
return;
|
|
|
|
LPCTSTR ext = PathFindExtension( path );
|
|
if( 0 == *ext && filterIndex < outputExtensions.size() )
|
|
{
|
|
wchar_t* const buffer = path.GetBufferSetLength( path.GetLength() + 5 );
|
|
PathRenameExtension( buffer, outputExtensions[ filterIndex ] );
|
|
path.ReleaseBuffer();
|
|
}
|
|
|
|
transcribeOutputPath.SetWindowText( path );
|
|
if( filterIndex != origFilterIndex )
|
|
transcribeOutFormat.SetCurSel( filterIndex + 1 );
|
|
}
|
|
|
|
void TranscribeDlg::setPending( bool nowPending )
|
|
{
|
|
pendingState.setPending( nowPending );
|
|
}
|
|
|
|
void TranscribeDlg::transcribeError( LPCTSTR text, HRESULT hr )
|
|
{
|
|
reportError( m_hWnd, text, L"Unable to transcribe audio", hr );
|
|
}
|
|
|
|
void TranscribeDlg::onTranscribe()
|
|
{
|
|
switch( transcribeArgs.visualState )
|
|
{
|
|
case eVisualState::Running:
|
|
transcribeArgs.visualState = eVisualState::Stopping;
|
|
transcribeButton.EnableWindow( FALSE );
|
|
return;
|
|
case eVisualState::Stopping:
|
|
return;
|
|
}
|
|
|
|
// Validate input
|
|
sourceMediaPath.GetWindowText( transcribeArgs.pathMedia );
|
|
if( transcribeArgs.pathMedia.GetLength() <= 0 )
|
|
{
|
|
transcribeError( L"Please select an input audio file" );
|
|
return;
|
|
}
|
|
|
|
if( !PathFileExists( transcribeArgs.pathMedia ) )
|
|
{
|
|
transcribeError( L"Input audio file does not exist", HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) );
|
|
return;
|
|
}
|
|
|
|
transcribeArgs.language = languageSelector.selectedLanguage();
|
|
transcribeArgs.translate = cbTranslate.checked();
|
|
if( isInvalidTranslate( m_hWnd, transcribeArgs.language, transcribeArgs.translate ) )
|
|
return;
|
|
|
|
transcribeArgs.format = (eOutputFormat)(uint8_t)transcribeOutFormat.GetCurSel();
|
|
if( transcribeArgs.format != eOutputFormat::None )
|
|
{
|
|
transcribeOutputPath.GetWindowText( transcribeArgs.pathOutput );
|
|
if( transcribeArgs.pathOutput.GetLength() <= 0 )
|
|
{
|
|
transcribeError( L"Please select an output text file" );
|
|
return;
|
|
}
|
|
if( PathFileExists( transcribeArgs.pathOutput ) )
|
|
{
|
|
const int resp = MessageBox( L"The output file is already there.\nOverwrite the file?", L"Confirm Overwrite", MB_ICONQUESTION | MB_YESNO );
|
|
if( resp != IDYES )
|
|
return;
|
|
}
|
|
appState.stringStore( regValOutPath, transcribeArgs.pathOutput );
|
|
}
|
|
else
|
|
cbConsole.ensureChecked();
|
|
|
|
appState.dwordStore( regValOutFormat, (uint32_t)(int)transcribeArgs.format );
|
|
appState.boolStore( regValUseInputFolder, isChecked( useInputFolder ) );
|
|
languageSelector.saveSelection( appState );
|
|
cbTranslate.saveSelection( appState );
|
|
appState.stringStore( regValInput, transcribeArgs.pathMedia );
|
|
|
|
setPending( true );
|
|
transcribeArgs.visualState = eVisualState::Running;
|
|
transcribeButton.SetWindowText( L"Stop" );
|
|
work.post();
|
|
}
|
|
|
|
void __stdcall TranscribeDlg::poolCallback() noexcept
|
|
{
|
|
HRESULT hr = transcribe();
|
|
PostMessage( WM_CALLBACK_STATUS, (WPARAM)hr );
|
|
}
|
|
|
|
static void printTime( CString& rdi, int64_t ticks )
|
|
{
|
|
const Whisper::sTimeSpan ts{ (uint64_t)ticks };
|
|
const Whisper::sTimeSpanFields fields = ts;
|
|
|
|
if( fields.days != 0 )
|
|
{
|
|
rdi.AppendFormat( L"%i days, %i hours", fields.days, (int)fields.hours );
|
|
return;
|
|
}
|
|
if( ( fields.hours | fields.minutes ) != 0 )
|
|
{
|
|
rdi.AppendFormat( L"%02d:%02d:%02d", (int)fields.hours, (int)fields.minutes, (int)fields.seconds );
|
|
return;
|
|
}
|
|
rdi.AppendFormat( L"%.3f seconds", (double)ticks / 1E7 );
|
|
}
|
|
|
|
LRESULT TranscribeDlg::onCallbackStatus( UINT, WPARAM wParam, LPARAM, BOOL& bHandled )
|
|
{
|
|
setPending( false );
|
|
transcribeButton.SetWindowText( L"Transcribe" );
|
|
transcribeButton.EnableWindow( TRUE );
|
|
const bool prematurely = ( transcribeArgs.visualState == eVisualState::Stopping );
|
|
transcribeArgs.visualState = eVisualState::Idle;
|
|
|
|
const HRESULT hr = (HRESULT)wParam;
|
|
if( FAILED( hr ) )
|
|
{
|
|
LPCTSTR failMessage = L"Transcribe failed";
|
|
|
|
if( transcribeArgs.errorMessage.GetLength() > 0 )
|
|
{
|
|
CString tmp = failMessage;
|
|
tmp += L"\n";
|
|
tmp += transcribeArgs.errorMessage;
|
|
transcribeError( tmp, hr );
|
|
}
|
|
else
|
|
transcribeError( failMessage, hr );
|
|
|
|
return 0;
|
|
}
|
|
|
|
const int64_t elapsed = ( GetTickCount64() - transcribeArgs.startTime ) * 10'000;
|
|
const int64_t media = transcribeArgs.mediaDuration;
|
|
CString message;
|
|
if( prematurely )
|
|
message = L"Transcribed an initial portion of the audio";
|
|
else
|
|
message = L"Transcribed the audio";
|
|
message += L"\nMedia duration: ";
|
|
printTime( message, media );
|
|
message += L"\nProcessing time: ";
|
|
printTime( message, elapsed );
|
|
message += L"\nRelative processing speed: ";
|
|
double mul = (double)media / (double)elapsed;
|
|
message.AppendFormat( L"%g", mul );
|
|
|
|
MessageBox( message, L"Transcribe Completed", MB_OK | MB_ICONINFORMATION );
|
|
return 0;
|
|
}
|
|
|
|
void TranscribeDlg::getThreadError()
|
|
{
|
|
getLastError( transcribeArgs.errorMessage );
|
|
}
|
|
|
|
#define CHECK_EX( hr ) { const HRESULT __hr = ( hr ); if( FAILED( __hr ) ) { getThreadError(); return __hr; } }
|
|
|
|
HRESULT TranscribeDlg::transcribe()
|
|
{
|
|
transcribeArgs.startTime = GetTickCount64();
|
|
clearLastError();
|
|
transcribeArgs.errorMessage = L"";
|
|
|
|
using namespace Whisper;
|
|
CComPtr<iAudioReader> reader;
|
|
|
|
CHECK_EX( appState.mediaFoundation->openAudioFile( transcribeArgs.pathMedia, false, &reader ) );
|
|
|
|
const eOutputFormat format = transcribeArgs.format;
|
|
CAtlFile outputFile;
|
|
if( format != eOutputFormat::None )
|
|
CHECK( outputFile.Create( transcribeArgs.pathOutput, GENERIC_WRITE, 0, CREATE_ALWAYS ) );
|
|
|
|
transcribeArgs.resultFlags = eResultFlags::Timestamps | eResultFlags::Tokens;
|
|
|
|
CComPtr<iContext> context;
|
|
CHECK_EX( appState.model->createContext( &context ) );
|
|
|
|
sFullParams fullParams;
|
|
CHECK_EX( context->fullDefaultParams( eSamplingStrategy::Greedy, &fullParams ) );
|
|
fullParams.language = transcribeArgs.language;
|
|
fullParams.setFlag( eFullParamsFlags::Translate, transcribeArgs.translate );
|
|
fullParams.resetFlag( eFullParamsFlags::PrintRealtime );
|
|
|
|
// Setup the callbacks
|
|
fullParams.new_segment_callback = &newSegmentCallbackStatic;
|
|
fullParams.new_segment_callback_user_data = this;
|
|
fullParams.encoder_begin_callback = &encoderBeginCallback;
|
|
fullParams.encoder_begin_callback_user_data = this;
|
|
|
|
// Setup the progress indication sink
|
|
sProgressSink progressSink{ &progressCallbackStatic, this };
|
|
// Run the transcribe
|
|
CHECK_EX( context->runStreamed( fullParams, progressSink, reader ) );
|
|
|
|
// Once finished, query duration of the audio.
|
|
// The duration before the processing is sometimes different, by 20 seconds for the file in that issue:
|
|
// https://github.com/Const-me/Whisper/issues/4
|
|
CHECK_EX( reader->getDuration( transcribeArgs.mediaDuration ) );
|
|
|
|
context->timingsPrint();
|
|
|
|
if( format == eOutputFormat::None )
|
|
return S_OK;
|
|
|
|
CComPtr<iTranscribeResult> result;
|
|
CHECK_EX( context->getResults( transcribeArgs.resultFlags, &result ) );
|
|
|
|
sTranscribeLength len;
|
|
CHECK_EX( result->getSize( len ) );
|
|
const sSegment* const segments = result->getSegments();
|
|
|
|
switch( format )
|
|
{
|
|
case eOutputFormat::Text:
|
|
return writeTextFile( segments, len.countSegments, outputFile, false );
|
|
case eOutputFormat::TextTimestamps:
|
|
return writeTextFile( segments, len.countSegments, outputFile, true );
|
|
case eOutputFormat::SubRip:
|
|
return writeSubRip( segments, len.countSegments, outputFile );
|
|
case eOutputFormat::WebVTT:
|
|
return writeWebVTT( segments, len.countSegments, outputFile );
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
#undef CHECK_EX
|
|
|
|
inline HRESULT TranscribeDlg::progressCallback( double p ) noexcept
|
|
{
|
|
constexpr double mul = progressMaxInteger;
|
|
int pos = lround( mul * p );
|
|
progressBar.PostMessage( PBM_SETPOS, pos, 0 );
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT __cdecl TranscribeDlg::progressCallbackStatic( double p, Whisper::iContext* ctx, void* pv ) noexcept
|
|
{
|
|
TranscribeDlg* dlg = (TranscribeDlg*)pv;
|
|
return dlg->progressCallback( p );
|
|
}
|
|
|
|
namespace
|
|
{
|
|
HRESULT write( CAtlFile& file, const CStringA& line )
|
|
{
|
|
if( line.GetLength() > 0 )
|
|
CHECK( file.Write( cstr( line ), (DWORD)line.GetLength() ) );
|
|
return S_OK;
|
|
}
|
|
|
|
const char* skipBlank( const char* rsi )
|
|
{
|
|
while( true )
|
|
{
|
|
const char c = *rsi;
|
|
if( c == ' ' || c == '\t' )
|
|
{
|
|
rsi++;
|
|
continue;
|
|
}
|
|
return rsi;
|
|
}
|
|
}
|
|
}
|
|
|
|
using Whisper::sSegment;
|
|
|
|
|
|
HRESULT TranscribeDlg::writeTextFile( const sSegment* const segments, const size_t length, CAtlFile& file, bool timestamps )
|
|
{
|
|
using namespace Whisper;
|
|
CHECK( writeUtf8Bom( file ) );
|
|
CStringA line;
|
|
for( size_t i = 0; i < length; i++ )
|
|
{
|
|
const sSegment& seg = segments[ i ];
|
|
|
|
if( timestamps )
|
|
{
|
|
line = "[";
|
|
printTime( line, seg.time.begin );
|
|
line += " --> ";
|
|
printTime( line, seg.time.end );
|
|
line += "] ";
|
|
}
|
|
else
|
|
line = "";
|
|
|
|
line += skipBlank( seg.text );
|
|
line += "\r\n";
|
|
CHECK( write( file, line ) );
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT TranscribeDlg::writeSubRip( const sSegment* const segments, const size_t length, CAtlFile& file )
|
|
{
|
|
CHECK( writeUtf8Bom( file ) );
|
|
CStringA line;
|
|
for( size_t i = 0; i < length; i++ )
|
|
{
|
|
const sSegment& seg = segments[ i ];
|
|
|
|
line.Format( "%zu\r\n", i + 1 );
|
|
printTime( line, seg.time.begin, true );
|
|
line += " --> ";
|
|
printTime( line, seg.time.end, true );
|
|
line += "\r\n";
|
|
line += skipBlank( seg.text );
|
|
line += "\r\n\r\n";
|
|
CHECK( write( file, line ) );
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT TranscribeDlg::writeWebVTT( const sSegment* const segments, const size_t length, CAtlFile& file )
|
|
{
|
|
CHECK( writeUtf8Bom( file ) );
|
|
CStringA line;
|
|
line = "WEBVTT\r\n\r\n";
|
|
CHECK( write( file, line ) );
|
|
|
|
for( size_t i = 0; i < length; i++ )
|
|
{
|
|
const sSegment& seg = segments[ i ];
|
|
line = "";
|
|
|
|
printTime( line, seg.time.begin, false );
|
|
line += " --> ";
|
|
printTime( line, seg.time.end, false );
|
|
line += "\r\n";
|
|
line += skipBlank( seg.text );
|
|
line += "\r\n\r\n";
|
|
CHECK( write( file, line ) );
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
inline HRESULT TranscribeDlg::newSegmentCallback( Whisper::iContext* ctx, uint32_t n_new )
|
|
{
|
|
using namespace Whisper;
|
|
CComPtr<iTranscribeResult> result;
|
|
CHECK( ctx->getResults( transcribeArgs.resultFlags, &result ) );
|
|
return logNewSegments( result, n_new );
|
|
}
|
|
|
|
HRESULT __cdecl TranscribeDlg::newSegmentCallbackStatic( Whisper::iContext* ctx, uint32_t n_new, void* user_data ) noexcept
|
|
{
|
|
TranscribeDlg* dlg = (TranscribeDlg*)user_data;
|
|
return dlg->newSegmentCallback( ctx, n_new );
|
|
}
|
|
|
|
HRESULT __cdecl TranscribeDlg::encoderBeginCallback( Whisper::iContext* ctx, void* user_data ) noexcept
|
|
{
|
|
TranscribeDlg* dlg = (TranscribeDlg*)user_data;
|
|
const eVisualState visualState = dlg->transcribeArgs.visualState;
|
|
switch( visualState )
|
|
{
|
|
case eVisualState::Idle:
|
|
return E_NOT_VALID_STATE;
|
|
case eVisualState::Running:
|
|
return S_OK;
|
|
case eVisualState::Stopping:
|
|
return S_FALSE;
|
|
default:
|
|
return E_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
void TranscribeDlg::onWmClose()
|
|
{
|
|
if( GetDlgItem( IDCANCEL ).IsWindowEnabled() )
|
|
{
|
|
EndDialog( IDCANCEL );
|
|
return;
|
|
}
|
|
|
|
constexpr UINT flags = MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2;
|
|
const int res = this->MessageBox( L"Transcribe is in progress.\nDo you want to quit anyway?", L"Confirm exit", flags );
|
|
if( res != IDYES )
|
|
return;
|
|
|
|
// TODO: instead of ExitProcess(), implement another callback in the DLL API, for proper cancellation of the background task
|
|
ExitProcess( 1 );
|
|
} |