@christianriedl/utils 1.0.93 → 1.0.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ export interface IStop {
2
+ stop(): void;
3
+ running: boolean;
4
+ }
5
+ export interface IPause extends IStop {
6
+ resume(): void;
7
+ pause(): void;
8
+ paused: boolean;
9
+ }
10
+ export declare class Audio {
11
+ static recordAudio(endThreshold: number, onEnd: (blob: Blob) => void, onStateChange?: () => void, onError?: (e: string) => void): Promise<IPause>;
12
+ static voices: SpeechSynthesisVoice[];
13
+ static getSpeechSynthesizeVoices(): Promise<SpeechSynthesisVoice[]>;
14
+ static speechSynthesize(text: string, voiceName?: string, language?: string, rate?: number, pitch?: number, onEnd?: () => void, onStateChange?: () => void, onError?: (e: string) => void): Promise<IPause>;
15
+ static speechTranscribe(language?: string, retStop?: IStop): Promise<SpeechRecognitionResult>;
16
+ static playAudio(audioData: ArrayBuffer, onEnd?: () => void): Promise<IStop>;
17
+ }
package/dist/audio.js ADDED
@@ -0,0 +1,163 @@
1
+ export class Audio {
2
+ static async recordAudio(endThreshold, onEnd, onStateChange, onError) {
3
+ const constraints = { "video": false, "audio": true };
4
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
5
+ const recordedChunks = [];
6
+ const recorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
7
+ recorder.ondataavailable = async (ev) => {
8
+ recordedChunks.push(ev.data);
9
+ const arr = await ev.data.arrayBuffer();
10
+ if (endThreshold && recordedChunks.length > 1 && ev.data.size < endThreshold)
11
+ recorder.stop();
12
+ };
13
+ recorder.start(1000);
14
+ recorder.onstop = () => {
15
+ const blob = new Blob(recordedChunks, { type: recordedChunks[0].type });
16
+ onEnd(blob);
17
+ };
18
+ if (onError) {
19
+ recorder.onerror = (ev) => onError(ev.type);
20
+ }
21
+ return {
22
+ stop: () => {
23
+ if (recorder.state != 'inactive') {
24
+ recorder.stop();
25
+ onStateChange?.();
26
+ }
27
+ },
28
+ pause: () => {
29
+ if (recorder.state != 'paused') {
30
+ recorder.pause();
31
+ onStateChange?.();
32
+ }
33
+ },
34
+ resume: () => {
35
+ if (recorder.state == 'paused') {
36
+ recorder.resume();
37
+ onStateChange?.();
38
+ }
39
+ },
40
+ get paused() { return recorder.state == 'paused'; },
41
+ get running() { return recorder.state == 'recording'; }
42
+ };
43
+ }
44
+ static voices;
45
+ static getSpeechSynthesizeVoices() {
46
+ const synth = window.speechSynthesis;
47
+ var promise = new Promise(function (resolve, reject) {
48
+ if (Audio.voices) {
49
+ resolve(Audio.voices);
50
+ }
51
+ else {
52
+ synth.onvoiceschanged = (ev) => {
53
+ Audio.voices = synth.getVoices();
54
+ resolve(Audio.voices);
55
+ };
56
+ }
57
+ });
58
+ return promise;
59
+ }
60
+ static async speechSynthesize(text, voiceName, language, rate, pitch, onEnd, onStateChange, onError) {
61
+ let voice;
62
+ const synth = window.speechSynthesis;
63
+ const utterance = new SpeechSynthesisUtterance();
64
+ utterance.text = text;
65
+ if (voiceName || language) {
66
+ const voices = await Audio.getSpeechSynthesizeVoices();
67
+ const voice = voiceName ? voices.find((v) => v.name == voiceName) : voices.find((v) => v.lang == language);
68
+ utterance.voice = voice ? voice : null;
69
+ }
70
+ if (rate)
71
+ utterance.rate = 1;
72
+ if (pitch)
73
+ utterance.pitch = 1;
74
+ if (language)
75
+ utterance.lang = "language";
76
+ if (onEnd || onStateChange) {
77
+ utterance.onend = (ev) => {
78
+ onEnd?.();
79
+ onStateChange?.();
80
+ };
81
+ }
82
+ if (onStateChange) {
83
+ utterance.onpause = (ev) => onStateChange();
84
+ utterance.onresume = (ev) => onStateChange();
85
+ utterance.onstart = (ev) => onStateChange();
86
+ }
87
+ if (onError) {
88
+ utterance.onerror = (ev) => {
89
+ onError(ev.error);
90
+ };
91
+ }
92
+ synth.speak(utterance);
93
+ return {
94
+ stop: () => {
95
+ if (synth.pending || synth.speaking) {
96
+ synth.cancel();
97
+ onEnd?.();
98
+ onStateChange?.();
99
+ }
100
+ },
101
+ pause: () => {
102
+ if (!synth.paused)
103
+ synth.pause();
104
+ },
105
+ resume: () => {
106
+ if (synth.paused)
107
+ synth.resume();
108
+ },
109
+ get paused() { return synth.paused; },
110
+ get running() { return synth.pending || synth.speaking; }
111
+ };
112
+ }
113
+ static async speechTranscribe(language, retStop) {
114
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
115
+ const speechRecognition = new SpeechRecognition();
116
+ let ended = false;
117
+ if (retStop) {
118
+ retStop.stop = () => {
119
+ if (!ended)
120
+ speechRecognition.stop();
121
+ };
122
+ }
123
+ const promise = new Promise(function (resolve, reject) {
124
+ if (language)
125
+ speechRecognition.lang = language;
126
+ speechRecognition.continuous = false;
127
+ speechRecognition.maxAlternatives = 1;
128
+ speechRecognition.onresult = (ev) => {
129
+ ended = true;
130
+ const result = ev.results[ev.resultIndex];
131
+ resolve(result);
132
+ };
133
+ speechRecognition.onerror = (ev) => {
134
+ ended = true;
135
+ reject(ev.error);
136
+ };
137
+ speechRecognition.start();
138
+ });
139
+ return promise;
140
+ }
141
+ static async playAudio(audioData, onEnd) {
142
+ const context = new AudioContext();
143
+ const buffer = await context.decodeAudioData(audioData);
144
+ const source = context.createBufferSource();
145
+ let ended = false;
146
+ source.onended = (ev) => {
147
+ ended = true;
148
+ if (onEnd)
149
+ onEnd();
150
+ };
151
+ source.buffer = buffer;
152
+ source.connect(context.destination);
153
+ source.start(0);
154
+ return {
155
+ stop: () => {
156
+ if (!ended)
157
+ source.stop();
158
+ },
159
+ get running() { return !ended; }
160
+ };
161
+ }
162
+ }
163
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -12,6 +12,5 @@ export * from './appConfig';
12
12
  export * from './statistics';
13
13
  export * from './marshalBE';
14
14
  export * from './marshalLE';
15
- export * from './useSpeechRecognition';
16
- export * from './useSpeechSynthesis';
15
+ export * from './audio';
17
16
  export { InjectionKey, Ref, ref, reactive, toRaw, isRef, watchEffect } from 'vue';
package/dist/index.js CHANGED
@@ -12,7 +12,6 @@ export * from './appConfig';
12
12
  export * from './statistics';
13
13
  export * from './marshalBE';
14
14
  export * from './marshalLE';
15
- export * from './useSpeechRecognition';
16
- export * from './useSpeechSynthesis';
15
+ export * from './audio';
17
16
  export { ref, reactive, toRaw, isRef, watchEffect } from 'vue';
18
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAqB,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,OAAO,EAAqB,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@christianriedl/utils",
3
- "version": "1.0.93",
3
+ "version": "1.0.95",
4
4
  "description": "Interfaces, local storage, service worker, configuration, application state",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,52 +1,29 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, watch } from 'vue'
3
- import { useSpeechRecognition } from '@christianriedl/utils';
3
+ import { Audio } from '@christianriedl/utils';
4
4
 
5
- const props = defineProps<{ lang?: string, maxAlternatives?: number, size?: string, cls?: string, variant?: "elevated" | "outlined" | "flat" | "text" | "tonal" | "plain" | undefined }>();
5
+ const props = defineProps<{ lang?: string, size?: string, cls?: string, variant?: "elevated" | "outlined" | "flat" | "text" | "tonal" | "plain" | undefined }>();
6
6
  const emits = defineEmits<{
7
- (e: 'result', result: string): void,
8
- (e: 'listening', isListening: boolean): void,
9
- (e: 'final', isFinal: boolean): void
7
+ (e: 'result', result: SpeechRecognitionResult): void
10
8
  }>();
11
9
 
12
10
  const sz = props.size ? props.size : "large";
13
- const cls = props.cls ? [ props.cls] : ["bg-office"];
14
- ; /*
15
- let cls = {};
16
- if (props.cls)
17
- cls[props.cls] = true;
18
- else
19
- cls["bg-office"] = true;
20
- */
11
+ const cls = props.cls ? [props.cls] : ["bg-office"];
21
12
  const vari = props.variant ? props.variant : "tonal";
22
- const lang = ref('de-AT');
23
- const maxAlternatives = props.maxAlternatives ? props.maxAlternatives : 1;
24
-
25
- if (props.lang)
26
- lang.value = props.lang;
27
-
28
- const speech = useSpeechRecognition({
29
- lang,
30
- maxAlternatives,
31
- continuous: false,
32
- })
33
-
34
- const sampled = ref<string[]>([])
35
-
36
- function onStart() {
37
- speech.result.value = ''
38
- speech.start()
13
+ const language = props.lang ? props.lang : 'de-AT';
14
+ const color = ref('primary');
15
+
16
+ async function onStart() {
17
+ color.value = 'error';
18
+ var result = await Audio.speechTranscribe(language);
19
+ color.value = 'primary';
20
+ emits('result', result);
39
21
  }
40
-
41
- const { isListening, isFinal, stop, result } = speech;
42
- watch(isListening, isListening => emits("listening", isListening));
43
- watch(isFinal, isFinal => emits("final", isFinal));
44
- watch(result, result => emits("result", result));
45
22
  </script>
46
23
 
47
24
  <template>
48
25
  <v-btn :variant="vari" :class="cls" @click="onStart">
49
- <v-icon :size="sz" icon="$microphone" :color="isListening ? 'error' : 'primary'"></v-icon>
26
+ <v-icon :size="sz" icon="$microphone" :color="color"></v-icon>
50
27
  </v-btn>
51
28
  </template>
52
29
 
@@ -0,0 +1,106 @@
1
+ <script setup lang="ts">
2
+ import { ref, watch, inject, toRef, onMounted } from 'vue'
3
+ import { Audio, appConfigSymbol, IPause } from '@christianriedl/utils';
4
+
5
+ const props = defineProps<{ text: string, language?: string, autostart?: boolean }>();
6
+
7
+ const appConfig = inject(appConfigSymbol)!;
8
+ const text = toRef(props, "text");
9
+ const voiceName = ref(appConfig.localStorage.getItemString("ttsVoice", ""));
10
+ const pitch = ref(appConfig.localStorage.getItemNumber("ttsPitch", 10) / 10);
11
+ const rate = ref(appConfig.localStorage.getItemNumber("ttsRate", 10) / 10);
12
+ const voice = ref<SpeechSynthesisVoice>(undefined as unknown as SpeechSynthesisVoice)
13
+ const voices = ref<SpeechSynthesisVoice[]>([])
14
+ const configure = ref(false);
15
+ const paused = ref(false);
16
+ const ended = ref(true);
17
+ let pause: IPause;
18
+
19
+ async function onPlay() {
20
+ if (pause && pause.paused) {
21
+ pause.resume();
22
+ paused.value = false;
23
+ }
24
+ else {
25
+ paused.value = ended.value = false;
26
+ pause = await Audio.speechSynthesize(text.value, voiceName.value, props.language, rate.value, pitch.value,
27
+ () => {
28
+ ended.value = true
29
+ },
30
+ () => {
31
+ paused.value = pause.paused;
32
+ ended.value = !pause.running;
33
+ });
34
+ }
35
+ }
36
+
37
+ function onPause() {
38
+ if (pause && !pause.paused) {
39
+ pause.pause();
40
+ }
41
+ }
42
+ function onStop() {
43
+ if (pause)
44
+ pause.stop();
45
+ }
46
+ function onVoiceChange() {
47
+ appConfig.localStorage.setItem("ttsVoice", voiceName.value);
48
+ voice.value = voices.value.find((v) => v.name == voiceName.value)!;
49
+ }
50
+ function onPitchChange() {
51
+ appConfig.localStorage.setItem("ttsPitch", Math.floor (pitch.value * 10));
52
+ }
53
+ function onRateChange() {
54
+ appConfig.localStorage.setItem("ttsRate", Math.floor(rate.value * 10));
55
+ }
56
+ async function onSettings() {
57
+ configure.value = !configure.value;
58
+ if (configure.value && voices.value.length == 0) {
59
+ voices.value = await Audio.getSpeechSynthesizeVoices();
60
+ }
61
+ }
62
+ if (props.autostart) {
63
+ watch(text, text => { if (text) onPlay(); });
64
+ }
65
+ </script>
66
+
67
+ <template>
68
+ <v-row dense>
69
+ <v-col cols="12">
70
+ <v-btn v-if="!paused && !ended" @click.stop="onPause">
71
+ <v-icon icon="$pause" />
72
+ </v-btn>
73
+ <v-btn v-else @click.stop="onPlay">
74
+ <v-icon icon="$play" />
75
+ </v-btn>
76
+ <v-btn @click.stop="onStop">
77
+ <v-icon icon="$stop" />
78
+ </v-btn>
79
+ <v-btn @click.stop="onSettings">
80
+ <v-icon icon="$settings" />
81
+ </v-btn>
82
+ </v-col>
83
+ </v-row>
84
+ <v-row v-if="configure" dense>
85
+ <v-col cols="12">
86
+ <v-select density="compact" v-model="voiceName"
87
+ item-title="name"
88
+ :items="voices"
89
+ persistent-hint
90
+ @update:modelValue="onVoiceChange"
91
+ dense solo hide-details single-line>
92
+ </v-select>
93
+ </v-col>
94
+ </v-row>
95
+ <v-row v-if="configure" dense>
96
+ <v-col cols="6">
97
+ <v-slider v-model="pitch" label="Pitch" density="compact" min="0.5" max="2" step="0.1"
98
+ @update:modelValue="onPitchChange"></v-slider>
99
+ </v-col>
100
+ <v-col cols="6">
101
+ <v-slider v-model="rate" label="Rate" density="compact" min="0.5" max="2" step="0.1"
102
+ @update:modelValue="onRateChange"></v-slider>
103
+ </v-col>
104
+ </v-row>
105
+ </template>
106
+