-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathasl_stream.cpp
More file actions
647 lines (536 loc) · 25.8 KB
/
Copy pathasl_stream.cpp
File metadata and controls
647 lines (536 loc) · 25.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
// Real-time speech recognition of input from a microphone
//
// A very quick-n-dirty implementation serving mainly as a proof of concept.
//
#include "common-sdl.h"
#include "common.h"
#include "common-whisper.h"
#include "whisper.h"
#include <chrono>
#include <cstdio>
#include <fstream>
#include <string>
#include <thread>
#include <vector>
// sllu mod for ASL starts
#include <iostream>
#include <string>
#include <cctype>
#include <unordered_map> // hash table
#include <algorithm>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#define PAUSE_TIME 200
// Global hash map for O(1) constant time lookups
const std::unordered_map<std::string, std::string> asl_word_table = {
{"dog", "/home/sllu/whisper.cpp/asl_images/words/dog.png"},
{"cat", "/home/sllu/whisper.cpp/asl_images/words/cat.png"},
{"false", "/home/sllu/whisper.cpp/asl_images/words/false.png"},
{"true", "/home/sllu/whisper.cpp/asl_images/words/true.png"},
{"hello", "/home/sllu/whisper.cpp/asl_images/words/hello.png"}
};
// this part is for rendering images for ASL
// Global pointers (Declared exactly once at the top)
SDL_Window* gWindow = nullptr;
SDL_Renderer* gRenderer = nullptr;
// Cache map to store pre-loaded textures globally
std::unordered_map<char, SDL_Texture*> gAslTextures;
// Call this function ONCE right before your program exits entirely to free shared VRAM
void free_all_asl_textures() {
for (auto& pair : gAslTextures) {
if (pair.second) {
SDL_DestroyTexture(pair.second);
} // end if
} //end for
gAslTextures.clear();
} // end free_all_asl_textures
// Helper function to handle window events and keep the app responsive during delays
void handle_sdl_events_and_delay(Uint32 ms) {
Uint32 start_time = SDL_GetTicks();
SDL_Event event;
// Run a mini event loop for the duration of the delay
while (SDL_GetTicks() - start_time < ms) {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
// Clean up memory before exiting
free_all_asl_textures();
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
SDL_Quit();
exit(0);
} // end if
} // end while 2
SDL_Delay(10); // Small sleep to prevent high CPU usage while waiting
} // end first while
} // end func
// Displays images directly from Jetson VRAM cache instead of reading disk files
void display_cached_asl(char c) {
if (!gRenderer) return;
auto it = gAslTextures.find(c);
if (it == gAslTextures.end() || !it->second) {
return; // Texture wasn't preloaded correctly
} // end if
// Clear the screen, render the cached image, and present it
SDL_RenderClear(gRenderer);
SDL_RenderCopy(gRenderer, it->second, nullptr, nullptr); // Fills the window
SDL_RenderPresent(gRenderer);
// Pause for 200ms to allow the user to read the sign
handle_sdl_events_and_delay(PAUSE_TIME);
}
// Main entry point for printing your ASL images
void print_asl_image(char c) {
c = std::toupper(c);
// If it is a space, clear the screen
if (c == ' ') {
SDL_RenderClear(gRenderer);
SDL_RenderPresent(gRenderer);
// Pause for 200ms on spaces too, so words stay separated visually
handle_sdl_events_and_delay(PAUSE_TIME);
return;
} // end if
// Ensure the character is a valid letter
if (c >= 'A' && c <= 'Z') {
display_cached_asl(c);
} // end if
} // end print_asl_image
// Call this function ONCE inside main() initialization sequence
bool load_all_asl_textures() {
if (!gRenderer) return false;
for (char c = 'A'; c <= 'Z'; ++c) {
std::string filepath = "/home/sllu/whisper.cpp/asl_images/" + std::string(1, c) + ".png";
SDL_Texture* texture = IMG_LoadTexture(gRenderer, filepath.c_str());
if (!texture) {
std::cerr << "Failed to pre-load image " << filepath << ": " << IMG_GetError() << std::endl;
return false;
} // end if
gAslTextures[c] = texture;
} // end for
return true;
} // end load_all_asl_textures
void print_asl_letter(char c) {
c = std::toupper(c);
// Example using Unicode ASL Finger-spelling fonts/symbols if supported,
// or standard fallback text.
switch(c) {
case 'A': std::cout << "🫵(A) "; break; // Replace with your target ASL character/symbol
case 'B': std::cout << "✋(B) "; break;
case 'C': std::cout << "👌(C) "; break;
case 'D': std::cout << "☝️(D) "; break;
case 'E': std::cout << "✊(E) "; break;
case 'F': std::cout << "👌(F) "; break;
case 'G': std::cout << "🫵(G) "; break;
case 'H': std::cout << "👉(H) "; break;
case 'I': std::cout << "🤙(I) "; break;
case 'J': std::cout << "🤙(J) "; break;
case 'K': std::cout << "✌️(K) "; break;
case 'L': std::cout << "🤙(L) "; break;
case 'M': std::cout << "👊(M) "; break;
case 'N': std::cout << "👊(N) "; break;
case 'O': std::cout << "👌(O) "; break;
case 'P': std::cout << "✌️(P) "; break;
case 'Q': std::cout << "🤏(Q) "; break;
case 'R': std::cout << "🤞(R) "; break;
case 'S': std::cout << "👊(S) "; break;
case 'T': std::cout << "👊(T) "; break;
case 'U': std::cout << "✌️(U) "; break;
case 'V': std::cout << "✌️(V) "; break;
case 'W': std::cout << "🖐️(W) "; break;
case 'X': std::cout << "☝️(X) "; break;
case 'Y': std::cout << "🤙(Y) "; break;
case 'Z': std::cout << "☝️(Z) "; break;
case ' ': std::cout << " "; break; // Space between words
default: break; // Skip punctuation for pure finger-spelling
}
std::cout << std::flush;
}
void translate_string_to_asl(const std::string & text) {
for (char c : text) {
print_asl_letter(c);
}
std::cout << std::endl;
}
void translate_string_to_asl_img(const std::string & text) {
for (char c : text) {
print_asl_image(c);
}
std::cout << std::endl;
}
// sllu mod ends
// command-line parameters
struct whisper_params {
int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency());
int32_t step_ms = 3000;
int32_t length_ms = 10000;
int32_t keep_ms = 200;
int32_t capture_id = -1;
int32_t max_tokens = 32;
int32_t audio_ctx = 0;
int32_t beam_size = -1;
float vad_thold = 0.6f;
float freq_thold = 100.0f;
bool translate = false;
bool no_fallback = false;
bool print_special = false;
bool no_context = true;
bool no_timestamps = false;
bool tinydiarize = false;
bool save_audio = false; // save audio to wav file
bool use_gpu = true;
bool flash_attn = true;
std::string language = "en";
std::string model = "models/ggml-base.en.bin";
std::string fname_out;
};
void whisper_print_usage(int argc, char ** argv, const whisper_params & params);
static bool whisper_params_parse(int argc, char ** argv, whisper_params & params) {
for (int i = 1; i < argc; i++) {
std::string arg = argv[i];
if (arg == "-h" || arg == "--help") {
whisper_print_usage(argc, argv, params);
exit(0);
}
else if (arg == "-t" || arg == "--threads") { params.n_threads = std::stoi(argv[++i]); }
else if ( arg == "--step") { params.step_ms = std::stoi(argv[++i]); }
else if ( arg == "--length") { params.length_ms = std::stoi(argv[++i]); }
else if ( arg == "--keep") { params.keep_ms = std::stoi(argv[++i]); }
else if (arg == "-c" || arg == "--capture") { params.capture_id = std::stoi(argv[++i]); }
else if (arg == "-mt" || arg == "--max-tokens") { params.max_tokens = std::stoi(argv[++i]); }
else if (arg == "-ac" || arg == "--audio-ctx") { params.audio_ctx = std::stoi(argv[++i]); }
else if (arg == "-bs" || arg == "--beam-size") { params.beam_size = std::stoi(argv[++i]); }
else if (arg == "-vth" || arg == "--vad-thold") { params.vad_thold = std::stof(argv[++i]); }
else if (arg == "-fth" || arg == "--freq-thold") { params.freq_thold = std::stof(argv[++i]); }
else if (arg == "-tr" || arg == "--translate") { params.translate = true; }
else if (arg == "-nf" || arg == "--no-fallback") { params.no_fallback = true; }
else if (arg == "-ps" || arg == "--print-special") { params.print_special = true; }
else if (arg == "-kc" || arg == "--keep-context") { params.no_context = false; }
else if (arg == "-l" || arg == "--language") { params.language = argv[++i]; }
else if (arg == "-m" || arg == "--model") { params.model = argv[++i]; }
else if (arg == "-f" || arg == "--file") { params.fname_out = argv[++i]; }
else if (arg == "-tdrz" || arg == "--tinydiarize") { params.tinydiarize = true; }
else if (arg == "-sa" || arg == "--save-audio") { params.save_audio = true; }
else if (arg == "-ng" || arg == "--no-gpu") { params.use_gpu = false; }
else if (arg == "-fa" || arg == "--flash-attn") { params.flash_attn = true; }
else if (arg == "-nfa" || arg == "--no-flash-attn") { params.flash_attn = false; }
else {
fprintf(stderr, "error: unknown argument: %s\n", arg.c_str());
whisper_print_usage(argc, argv, params);
exit(0);
}
}
return true;
}
void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params & params) {
fprintf(stderr, "\n");
fprintf(stderr, "usage: %s [options]\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -h, --help [default] show this help message and exit\n");
fprintf(stderr, " -t N, --threads N [%-7d] number of threads to use during computation\n", params.n_threads);
fprintf(stderr, " --step N [%-7d] audio step size in milliseconds\n", params.step_ms);
fprintf(stderr, " --length N [%-7d] audio length in milliseconds\n", params.length_ms);
fprintf(stderr, " --keep N [%-7d] audio to keep from previous step in ms\n", params.keep_ms);
fprintf(stderr, " -c ID, --capture ID [%-7d] capture device ID\n", params.capture_id);
fprintf(stderr, " -mt N, --max-tokens N [%-7d] maximum number of tokens per audio chunk\n", params.max_tokens);
fprintf(stderr, " -ac N, --audio-ctx N [%-7d] audio context size (0 - all)\n", params.audio_ctx);
fprintf(stderr, " -bs N, --beam-size N [%-7d] beam size for beam search\n", params.beam_size);
fprintf(stderr, " -vth N, --vad-thold N [%-7.2f] voice activity detection threshold\n", params.vad_thold);
fprintf(stderr, " -fth N, --freq-thold N [%-7.2f] high-pass frequency cutoff\n", params.freq_thold);
fprintf(stderr, " -tr, --translate [%-7s] translate from source language to english\n", params.translate ? "true" : "false");
fprintf(stderr, " -nf, --no-fallback [%-7s] do not use temperature fallback while decoding\n", params.no_fallback ? "true" : "false");
fprintf(stderr, " -ps, --print-special [%-7s] print special tokens\n", params.print_special ? "true" : "false");
fprintf(stderr, " -kc, --keep-context [%-7s] keep context between audio chunks\n", params.no_context ? "false" : "true");
fprintf(stderr, " -l LANG, --language LANG [%-7s] spoken language\n", params.language.c_str());
fprintf(stderr, " -m FNAME, --model FNAME [%-7s] model path\n", params.model.c_str());
fprintf(stderr, " -f FNAME, --file FNAME [%-7s] text output file name\n", params.fname_out.c_str());
fprintf(stderr, " -tdrz, --tinydiarize [%-7s] enable tinydiarize (requires a tdrz model)\n", params.tinydiarize ? "true" : "false");
fprintf(stderr, " -sa, --save-audio [%-7s] save the recorded audio to a file\n", params.save_audio ? "true" : "false");
fprintf(stderr, " -ng, --no-gpu [%-7s] disable GPU inference\n", params.use_gpu ? "false" : "true");
fprintf(stderr, " -fa, --flash-attn [%-7s] enable flash attention during inference\n", params.flash_attn ? "true" : "false");
fprintf(stderr, " -nfa, --no-flash-attn [%-7s] disable flash attention during inference\n", params.flash_attn ? "false" : "true");
fprintf(stderr, "\n");
}
int main(int argc, char ** argv) {
// sllu added to do SDL video with SDL images using ASL .png files
// 1. Initialize SDL Video and SDL_image
SDL_Init(SDL_INIT_VIDEO);
IMG_Init(IMG_INIT_PNG);
// 2. Create a window and a hardware-accelerated renderer
gWindow = SDL_CreateWindow("ASL Stream", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 400, SDL_WINDOW_SHOWN);
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
// 3. Pre-load all ASL PNG textures into the Jetson memory cache
if (!load_all_asl_textures()) {
std::cerr << "Error: Could not cache ASL images. Exiting application." << std::endl;
// 4. Clean up any initialized SDL resources before quitting
if (gRenderer) SDL_DestroyRenderer(gRenderer);
if (gWindow) SDL_DestroyWindow(gWindow);
SDL_Quit();
return 1;}
// end sllu mod
ggml_backend_load_all();
whisper_params params;
if (whisper_params_parse(argc, argv, params) == false) {
return 1;
}
params.keep_ms = std::min(params.keep_ms, params.step_ms);
params.length_ms = std::max(params.length_ms, params.step_ms);
const int n_samples_step = (1e-3*params.step_ms )*WHISPER_SAMPLE_RATE;
const int n_samples_len = (1e-3*params.length_ms)*WHISPER_SAMPLE_RATE;
const int n_samples_keep = (1e-3*params.keep_ms )*WHISPER_SAMPLE_RATE;
const int n_samples_30s = (1e-3*30000.0 )*WHISPER_SAMPLE_RATE;
const bool use_vad = n_samples_step <= 0; // sliding window mode uses VAD
const int n_new_line = !use_vad ? std::max(1, params.length_ms / params.step_ms - 1) : 1; // number of steps to print new line
params.no_timestamps = !use_vad;
params.no_context |= use_vad;
params.max_tokens = 0;
// init audio
audio_async audio(params.length_ms);
if (!audio.init(params.capture_id, WHISPER_SAMPLE_RATE)) {
fprintf(stderr, "%s: audio.init() failed!\n", __func__);
return 1;
}
audio.resume();
// whisper init
if (params.language != "auto" && whisper_lang_id(params.language.c_str()) == -1){
fprintf(stderr, "error: unknown language '%s'\n", params.language.c_str());
whisper_print_usage(argc, argv, params);
exit(0);
}
struct whisper_context_params cparams = whisper_context_default_params();
cparams.use_gpu = params.use_gpu;
cparams.flash_attn = params.flash_attn;
struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams);
if (ctx == nullptr) {
fprintf(stderr, "error: failed to initialize whisper context\n");
return 2;
}
std::vector<float> pcmf32 (n_samples_30s, 0.0f);
std::vector<float> pcmf32_old;
std::vector<float> pcmf32_new(n_samples_30s, 0.0f);
std::vector<whisper_token> prompt_tokens;
// print some info about the processing
{
fprintf(stderr, "\n");
if (!whisper_is_multilingual(ctx)) {
if (params.language != "en" || params.translate) {
params.language = "en";
params.translate = false;
fprintf(stderr, "%s: WARNING: model is not multilingual, ignoring language and translation options\n", __func__);
}
}
fprintf(stderr, "%s: processing %d samples (step = %.1f sec / len = %.1f sec / keep = %.1f sec), %d threads, lang = %s, task = %s, timestamps = %d ...\n",
__func__,
n_samples_step,
float(n_samples_step)/WHISPER_SAMPLE_RATE,
float(n_samples_len )/WHISPER_SAMPLE_RATE,
float(n_samples_keep)/WHISPER_SAMPLE_RATE,
params.n_threads,
params.language.c_str(),
params.translate ? "translate" : "transcribe",
params.no_timestamps ? 0 : 1);
if (!use_vad) {
fprintf(stderr, "%s: n_new_line = %d, no_context = %d\n", __func__, n_new_line, params.no_context);
} else {
fprintf(stderr, "%s: using VAD, will transcribe on speech activity\n", __func__);
}
fprintf(stderr, "\n");
}
int n_iter = 0;
bool is_running = true;
std::ofstream fout;
if (params.fname_out.length() > 0) {
fout.open(params.fname_out);
if (!fout.is_open()) {
fprintf(stderr, "%s: failed to open output file '%s'!\n", __func__, params.fname_out.c_str());
return 1;
}
}
wav_writer wavWriter;
// save wav file
if (params.save_audio) {
// Get current date/time for filename
time_t now = time(0);
char buffer[80];
strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", localtime(&now));
std::string filename = std::string(buffer) + ".wav";
wavWriter.open(filename, WHISPER_SAMPLE_RATE, 16, 1);
}
printf("[Start speaking]\n");
fflush(stdout);
auto t_last = std::chrono::high_resolution_clock::now();
const auto t_start = t_last;
// main audio loop
while (is_running) {
if (params.save_audio) {
wavWriter.write(pcmf32_new.data(), pcmf32_new.size());
}
// handle Ctrl + C
is_running = sdl_poll_events();
if (!is_running) {
break;
}
// process new audio
if (!use_vad) {
while (true) {
// handle Ctrl + C
is_running = sdl_poll_events();
if (!is_running) {
break;
}
audio.get(params.step_ms, pcmf32_new);
if ((int) pcmf32_new.size() > 2*n_samples_step) {
fprintf(stderr, "\n\n%s: WARNING: cannot process audio fast enough, dropping audio ...\n\n", __func__);
audio.clear();
continue;
}
if ((int) pcmf32_new.size() >= n_samples_step) {
audio.clear();
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
const int n_samples_new = pcmf32_new.size();
// take up to params.length_ms audio from previous iteration
const int n_samples_take = std::min((int) pcmf32_old.size(), std::max(0, n_samples_keep + n_samples_len - n_samples_new));
//printf("processing: take = %d, new = %d, old = %d\n", n_samples_take, n_samples_new, (int) pcmf32_old.size());
pcmf32.resize(n_samples_new + n_samples_take);
for (int i = 0; i < n_samples_take; i++) {
pcmf32[i] = pcmf32_old[pcmf32_old.size() - n_samples_take + i];
}
memcpy(pcmf32.data() + n_samples_take, pcmf32_new.data(), n_samples_new*sizeof(float));
pcmf32_old = pcmf32;
} else {
const auto t_now = std::chrono::high_resolution_clock::now();
const auto t_diff = std::chrono::duration_cast<std::chrono::milliseconds>(t_now - t_last).count();
if (t_diff < 2000) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
audio.get(2000, pcmf32_new);
if (::vad_simple(pcmf32_new, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, false)) {
audio.get(params.length_ms, pcmf32);
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
t_last = t_now;
}
// run the inference
{
whisper_full_params wparams = whisper_full_default_params(params.beam_size > 1 ? WHISPER_SAMPLING_BEAM_SEARCH : WHISPER_SAMPLING_GREEDY);
wparams.print_progress = false;
wparams.print_special = params.print_special;
wparams.print_realtime = false;
wparams.print_timestamps = !params.no_timestamps;
wparams.translate = params.translate;
wparams.single_segment = !use_vad;
wparams.max_tokens = params.max_tokens;
wparams.language = params.language.c_str();
wparams.n_threads = params.n_threads;
wparams.beam_search.beam_size = params.beam_size;
wparams.audio_ctx = params.audio_ctx;
wparams.tdrz_enable = params.tinydiarize; // [TDRZ]
// disable temperature fallback
//wparams.temperature_inc = -1.0f;
wparams.temperature_inc = params.no_fallback ? 0.0f : wparams.temperature_inc;
/** ------------------ sllu fix chinese huluciantion
wparams.prompt_tokens = params.no_context ? nullptr : prompt_tokens.data();
wparams.prompt_n_tokens = params.no_context ? 0 : prompt_tokens.size();
*/
// If the user explicitly chose Chinese ("zh"), force-wipe the memory to prevent loops.
if (params.language == "zh") {
wparams.prompt_tokens = nullptr;
wparams.prompt_n_tokens = 0;
prompt_tokens.clear();
} else {
// Keep original context-tracking behavior for English and other languages
wparams.prompt_tokens = params.no_context ? nullptr : prompt_tokens.data();
wparams.prompt_n_tokens = params.no_context ? 0 : prompt_tokens.size();
}
// sllu fix end
if (whisper_full(ctx, wparams, pcmf32.data(), pcmf32.size()) != 0) {
fprintf(stderr, "%s: failed to process audio\n", argv[0]);
return 6;
}
// print result;
{
if (!use_vad) {
printf("\33[2K\r");
// print long empty line to clear the previous line
printf("%s", std::string(100, ' ').c_str());
printf("\33[2K\r");
} else {
const int64_t t1 = (t_last - t_start).count()/1000000;
const int64_t t0 = std::max(0.0, t1 - pcmf32.size()*1000.0/WHISPER_SAMPLE_RATE);
printf("\n");
printf("### Transcription %d START | t0 = %d ms | t1 = %d ms\n", n_iter, (int) t0, (int) t1);
printf("\n");
}
const int n_segments = whisper_full_n_segments(ctx);
for (int i = 0; i < n_segments; ++i) {
const char * text = whisper_full_get_segment_text(ctx, i);
if (params.no_timestamps) {
printf("%s", text);
// sllu mode starts
const char * text_asl = whisper_full_get_segment_text(ctx, i);
// Pass the text chunk to your ASL translator
// translate_string_to_asl(text);
translate_string_to_asl_img(text);
// sllu mod ends
fflush(stdout);
if (params.fname_out.length() > 0) {
fout << text;
}
} else {
const int64_t t0 = whisper_full_get_segment_t0(ctx, i);
const int64_t t1 = whisper_full_get_segment_t1(ctx, i);
std::string output = "[" + to_timestamp(t0, false) + " --> " + to_timestamp(t1, false) + "] " + text;
if (whisper_full_get_segment_speaker_turn_next(ctx, i)) {
output += " [SPEAKER_TURN]";
}
output += "\n";
printf("%s", output.c_str());
fflush(stdout);
if (params.fname_out.length() > 0) {
fout << output;
}
}
}
if (params.fname_out.length() > 0) {
fout << std::endl;
}
if (use_vad) {
printf("\n");
printf("### Transcription %d END\n", n_iter);
}
}
++n_iter;
if (!use_vad && (n_iter % n_new_line) == 0) {
printf("\n");
// keep part of the audio for next iteration to try to mitigate word boundary issues
pcmf32_old = std::vector<float>(pcmf32.end() - n_samples_keep, pcmf32.end());
// Add tokens of the last full length segment as the prompt
if (!params.no_context) {
prompt_tokens.clear();
const int n_segments = whisper_full_n_segments(ctx);
for (int i = 0; i < n_segments; ++i) {
const int token_count = whisper_full_n_tokens(ctx, i);
for (int j = 0; j < token_count; ++j) {
prompt_tokens.push_back(whisper_full_get_token_id(ctx, i, j));
}
}
}
}
fflush(stdout);
}
}
audio.pause();
whisper_print_timings(ctx);
whisper_free(ctx);
// Clean up custom ASL texture cache from the Jetson memory pool
free_all_asl_textures();
// Standard SDL cleanup (Must happen AFTER freeing textures)
if (gRenderer) SDL_DestroyRenderer(gRenderer);
if (gWindow) SDL_DestroyWindow(gWindow);
SDL_Quit();
return 0;
}