diff --git a/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.html b/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.html
index 81a21e4c2..bf995237f 100644
--- a/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.html
+++ b/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.html
@@ -3,8 +3,10 @@
+
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.scss b/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.scss
index 88b9eea6d..1e9ab1bed 100644
--- a/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.scss
+++ b/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.scss
@@ -10,6 +10,7 @@
//padding-left: 20px;
//padding-right: 20px;
padding: 40px;
+ margin: 0 auto;
}
.storyContainer > * {
@@ -57,25 +58,25 @@
.currentWord {
background-color: var(--scealai-light-green);
+ transition: background-color .1s;
}
// there is a visual bug where the toolbar is not quite stuck to the top of the screen
.Toolbar {
position: sticky;
top: 0;
- /*padding: 0;
- margin: 0;
- width: 100%;*/
+
background-color: var(--scealai-green);
max-width: 60%;
margin: auto;
display: flex;
flex-direction: row;
justify-content: center;
- //align-items: center;
+
+ margin: 0 auto;
}
-.Toolbar > button {
+.Toolbar > * {
border: none;
background-color: white;
color: var(--scealai-green);
@@ -101,10 +102,26 @@
font-size: 40px;
}
+button.playing {
+ background-color: var(--scealai-cream);
+}
+
.pause {
font-size: 20px;
}
+.voiceSelection {
+ display: flex;
+ flex-direction: row;
+ //right: 0;
+}
+
+.voiceSelection mat-form-field {
+ //margin: auto auto;
+ max-width: 150px;
+ //max-width: min-content;
+}
+
/*html {
scroll-behavior: smooth;
}*/
\ No newline at end of file
diff --git a/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.ts b/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.ts
index 2a3da6036..740a1a600 100644
--- a/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.ts
+++ b/ngapp/src/app/dr-story-viewer/dr-story-builder/dr-story-builder.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit, ViewChild, ElementRef, Input, HostListener, importProvidersFrom } from "@angular/core";
import { SynthItem } from "app/core/models/synth-item";
-import { SynthesisService, Voice } from "app/core/services/synthesis.service";
+import { SynthesisService, Voice, voices } from "app/core/services/synthesis.service";
import { TranslationService } from "app/core/services/translation.service";
import { SynthesisPlayerComponent } from "app/student/synthesis-player/synthesis-player.component";
import { ActivatedRoute, ChildActivationEnd, Router } from "@angular/router";
@@ -26,18 +26,34 @@ import { ViewEncapsulation } from '@angular/core';
import { DigitalReaderStoryService } from "app/core/services/dr-story.service";
import { firstValueFrom, Observable } from "rxjs";
import { QuillModule } from "ngx-quill";
+import { MatSelectModule } from "@angular/material/select";
+import { MatMenuModule } from "@angular/material/menu";
+import { MatIconModule } from "@angular/material/icon";
+import { MatButtonModule } from "@angular/material/button";
+
+const dialectToVoiceIndex = new Map([
+ ["Connacht f", 0],
+ ["Ulster f", 1],
+ ["Connacht m", 2],
+ ["Munster f", 3],
+ ["Munster m", 4],
+]);
@Component({
standalone: true,
//providers: [importProvidersFrom(QuillModule.forRoot())],
imports: [
CommonModule,
- QuillModule
+ QuillModule,
+ MatSelectModule,
+ MatMenuModule,
+ MatIconModule,
+ MatButtonModule
],
selector: "app-dr-story-builder",
templateUrl: "./dr-story-builder.component.html",
styleUrls: ["./dr-story-builder.component.scss"], // Digital Reader Story Styling
- encapsulation: ViewEncapsulation.None // Without this line, non-angular html can not be targetted for styling
+ encapsulation: ViewEncapsulation.None // Without this line, non-angular html cannot be targetted for styling
})
export class DigitalReaderStoryBuilderComponent implements OnInit {
@@ -52,7 +68,15 @@ export class DigitalReaderStoryBuilderComponent implements OnInit {
public forceTrustedHTML:SafeHtml;
public currentSentence:Element | null = null;
public currentWord:Element | null = null;
- public listOfAudios:any[] = []
+
+ public listOfAudios:any = [ // 5 sub-arrays, 1 for each voice option
+ [],
+ [],
+ [],
+ [],
+ []
+ ]
+
public audio:HTMLAudioElement;
public timings:any[] = []
public voiceSpeed = 1;
@@ -62,6 +86,12 @@ export class DigitalReaderStoryBuilderComponent implements OnInit {
// below boolean is needed to meaningfully distinguish audio.ended and audio.paused
public audioPaused:Boolean = false;
+ public audioPlaying:Boolean = false;
+
+ //public voiceDialect:string | null = 'Connacht';
+ //public voiceGender:string | null = 'f';
+ public voiceIndex:number = 0; // defaults to Sibéal nemo
+
constructor(
private auth: AuthenticationService,
@@ -78,35 +108,28 @@ export class DigitalReaderStoryBuilderComponent implements OnInit {
}
async ngOnInit() {
- //this.audioCreationTest()
- /*console.log(this.content.textContent)
- const audioObservable = firstValueFrom(this.synth.synthesiseText(
- this.content.textContent,
- { name: "Sibéal", gender: "female", shortCode: "snc", code: "ga_CO_snc_nemo", dialect: "connacht", algorithm: "nemo", },
- false,
- 'MP3',
- 1)
- ).then( (data) => {
- console.log(data)
- })*/
this.forceTrustedHTML = this.sanitizer.bypassSecurityTrustHtml(this.content.innerHTML)
- console.log(this.content)
// only for testing
const firstSentSpans = this.content?.querySelectorAll('.sentence')
for (let i=0;i<3;i++) {
const sent = firstSentSpans.item(i)
- this.synthRequest(sent?.textContent).then( (data) => {
+ this.synthRequest(sent?.textContent, voices[this.voiceIndex]).then( (data) => {
console.log(data)
- this.listOfAudios[i] = data // only for testing
+ this.listOfAudios[this.voiceIndex][i] = data // only for testing
console.log(this.listOfAudios)
- //return data
})
}
+
+ console.log(dialectToVoiceIndex.get('Connacht f'));
}
+ speakerSelected(dialect:string, gender:string) {
+ console.log(dialect, gender);
+ }
+
getWordPositionIndex(word:Element, childWordSpans:NodeList) {
let numNonWords = 0;
@@ -173,67 +196,47 @@ export class DigitalReaderStoryBuilderComponent implements OnInit {
const childWordSpans = sentenceSpan.querySelectorAll('.word');
- //const childWordSpans = sentenceSpan.querySelectorAll('.word')
const wordInd = this.getWordPositionIndex(word, childWordSpans)
// for testing as ASR seems to split only on spaces.
- const sentenceText:string = this.recreateSentenceFromWord(childWordSpans.item(wordInd))
- const numTimings = sentenceText.split(' ').length
- console.log(numTimings)
- console.log(wordInd)
+ //const sentenceText:string = this.recreateSentenceFromWord(childWordSpans.item(wordInd))
+ //const numTimings = sentenceText.split(' ').length
+ //console.log(numTimings)
const timings = sentAudioObj.timing;
- const tmp = [];
const timingsArr = []
- console.log(timings)
-
- //const reSyncOffset = .03
let reSyncBuffer = 0;
- //for (let i=wordInd; iwordInd) { // if it is not the first word of the sentence
- if (i>0) {
- //start = timings[i-1].end
- //console.log(timingsArr.length, timingsArr[i-1]);
- //start = timings[i-1].end;
- start = tmp[i-1].end;
- }
-
- const length = end-start;
- //reSyncBuffer+=length*.1;
+ for (let i=0; i0) {
+ start = timingsArr[i-1].end;
+ }
- timing['start'] = start;
- timing['end'] = end-reSyncBuffer; // testing
- //timing['end'] = end; // testing
+ const length = end-start;
- // there may be something wrong with the timing alignment in the actual array - may have fixed it also
- //if (i>=wordInd)
- tmp.push(timing)
+ timing['start'] = start;
+ timing['end'] = end-reSyncBuffer;
- //reSyncBuffer+=length*.09; // should not apply to the first word
- //const modifier = .033*(1 + (1-this.voiceSpeed))*(this.speakerBaseSpeed); // should not apply to the first word
- //console.log(modifier)
- //reSyncBuffer+=length*Math.min(modifier, .9);
- reSyncBuffer+=length*this.speakerAlignmentConstant;
+ timingsArr.push(timing)
+ reSyncBuffer+=length*this.speakerAlignmentConstant;
}
- console.log(tmp)
- return tmp.slice(wordInd, timings.length);
+ return timingsArr.slice(wordInd, timings.length);
}
// TODO : relocate to the story creation page
- synthRequest(text: string) {
+ synthRequest(text: string, speaker:Voice) {
const audioObservable = firstValueFrom(this.synth.synthesiseText(
text,
- { name: "Áine", gender: "female", shortCode: "anb", code: "ga_UL_anb_nemo", dialect: "ulster", algorithm: "nemo", },
+ speaker,
+ //{ name: "Áine", gender: "female", shortCode: "anb", code: "ga_UL_anb_nemo", dialect: "ulster", algorithm: "nemo", },
//{ name: "Síbéal", gender: "female", shortCode: "snc", code: "ga_CO_snc_nemo", dialect: "connacht", algorithm: "nemo", },
false,
'MP3',
@@ -254,14 +257,14 @@ export class DigitalReaderStoryBuilderComponent implements OnInit {
for (let k=i;k