Changeset 35446 for main


Ignore:
Timestamp:
2021-09-21T14:58:07+12:00 (3 years ago)
Author:
cstephen
Message:

Significant improvements to audio playback

Location:
main/trunk/model-interfaces-dev/atea/korero-maori-asr/src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/App.vue

    r35445 r35446  
    103103    data() {
    104104        return {
    105             /** @type {{id: String, url: String} | null} */
    106             currentlyLoadedAudio: null,
    107             player: new Audio(),
    108105            showInfo: false
    109106        }
     
    111108    computed: mapState({
    112109        translations: state => state.translations,
    113         transcriptions: state => state.rawTranscriptions,
    114         playbackState: state => state.playbackState,
    115         shouldPlayAudio: state => state.playbackState.isPlaying
    116     }),
    117     watch: {
    118         async playbackState(newValue) {
    119             if (!newValue.isPlaying) {
    120                 return;
    121             }
    122 
    123             const transcription = this.transcriptions.get(newValue.id);
    124             loadTranscriptionAudio(this.player, transcription, this.currentlyLoadedAudio);
    125 
    126             let playbackTime = 0;
    127             if (newValue.currentTime > 0) {
    128                 playbackTime = newValue.currentTime;
    129             }
    130 
    131             this.player.currentTime = playbackTime;
    132             await this.player.play();
    133 
    134             this.playbackState.length = this.player.duration;
    135         }//,
    136         // shouldPlayAudio(newValue) {
    137         //     if (newValue && this.$refs.audioPlayer.paused) {
    138         //         this.$refs.audioPlayer.play();
    139         //     }
    140         //     else if (!newValue && !this.$refs.audioPlayer.paused) {
    141         //         this.$refs.audioPlayer.pause();
    142         //     }
    143         // }
    144     },
    145     mounted() {
    146         pollAudioTime(this.player, this.$store);
    147     }
    148 }
    149 
    150 // Adapted from https://davidwalsh.name/javascript-polling
    151 function pollAudioTime(audioElement, store) {
    152     var lastTime = 0;
    153     (function p() {
    154         if (audioElement.currentTime !== lastTime) {
    155             lastTime = audioElement.currentTime;
    156             store.commit("playbackStateSetCurrentTime", lastTime);
    157             store.commit("playbackStateSetIsPlaying", true);
    158         }
    159         else {
    160             store.commit("playbackStateSetIsPlaying", false);
    161         }
    162 
    163         setTimeout(p, 33); // Slightly more than 30hz
    164     })();
    165 }
    166 
    167 /**
    168  * Loads an audio file.
    169  * @param {Audio} player The audio player.
    170  * @param {TranscriptionViewModel} transcription The name of the requested audio file.
    171  * @param {{id: String, url: String} | null} current The currently loaded audio.
    172  * @returns {{id: String, url: String}} If a new audio file was loaded, a new audio tracking object, else the current one.
    173  */
    174 function loadTranscriptionAudio(player, transcription, current) {
    175     if (current == null || current.id !== transcription.id) {
    176         // TODO: Need to profile on some larger tracks; this may not be worth it? Better to cache a URL object instead?
    177         if (current !== null) {
    178             URL.revokeObjectURL(current.url);
    179         }
    180 
    181         const urlObject = URL.createObjectURL(transcription.file);
    182         player.src = urlObject;
    183         player.load();
    184 
    185         return { id: transcription.id, url: urlObject };
    186     }
    187 
    188     return current;
     110        transcriptions: state => state.rawTranscriptions
     111    })
    189112}
    190113</script>
  • main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/components/TranscriptionItem.vue

    r35445 r35446  
    33        <!-- Header containing info and actions for the transcription -->
    44        <div class="transcription__header">
    5             <button class="btn-fab" v-on:click="playAudio(-1)" type="button" title="Play Audio">
     5            <button class="btn-fab" v-on:click="toggleAudio" type="button" title="Play Audio">
    66                <span class="material-icons mdi-l play-button" v-if="!isPlaying">play_arrow</span>
    77                <span class="material-icons mdi-l play-button" v-if="isPlaying">pause</span>
     
    9595import { mapState } from "vuex";
    9696import { saveAs } from "file-saver"
     97import { TranscriptionViewModel } from "../main";
     98import AudioPlayback from "../js/AudioPlaybackModule"
     99import Util from "../js/Util"
    97100import TranscriptionItemEditor from "./TranscriptionItemEditor.vue"
    98 import { TranscriptionViewModel, PlaybackState } from "../main";
    99 import Util from "../js/Util"
    100101
    101102export default {
     
    115116    computed: mapState({
    116117        translations: state => state.translations,
    117         isPlaying: state => state.playbackState.isPlaying
     118        isPlaying(state) {
     119            return state.playbackState.isPlaying && state.playbackState.id === this.transcription.id
     120        }
    118121    }),
    119122    methods: {
     
    121124            this.showEditor = !this.showEditor;
    122125        },
    123         playAudio(startTime = 0) {
    124             const pState = new PlaybackState(this.transcription.id, true, startTime);
    125             this.$store.commit("setPlaybackState", pState);
     126        toggleAudio() {
     127            this.isPlaying ? AudioPlayback.pause() : AudioPlayback.play(this.transcription.id, -1);
    126128        },
    127129        remove() {
  • main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/components/TranscriptionItemEditor.vue

    r35445 r35446  
    7878<script>
    7979import { mapState } from "vuex";
    80 import { TranscriptionViewModel, PlaybackState } from "../main";
     80import { TranscriptionViewModel } from "../main";
     81import AudioPlayback from "../js/AudioPlaybackModule"
    8182import AudioTimeBar from "./AudioTimeBar.vue"
    8283import Util from "../js/Util";
     
    121122        return {
    122123            enableEditing: false,
    123             words: []
     124            words: [],
     125            lastHighlightedWordIndex: 0
    124126        }
    125127    },
     
    140142    methods: {
    141143        playAudio(startTime) {
    142             const pState = new PlaybackState(this.transcription.id, true, startTime);
    143             this.$store.commit("setPlaybackState", pState);
     144            AudioPlayback.play(this.transcription.id, startTime);
    144145        },
    145146        /**
     
    247248    watch: {
    248249        currentPlaybackTime(newValue) {
     250            this.words[this.lastHighlightedWordIndex].shouldHighlight = false;
     251
    249252            if (this.playbackState.id !== this.transcription.id) {
    250253                return;
    251254            }
    252255
    253             for (const word of this.words) {
    254                 word.shouldHighlight = word.startTime < newValue && word.endTime > newValue;
     256            for (let i = 0; i < this.words.length; i++) {
     257                const word = this.words[i];
     258
     259                if (word.startTime < newValue && word.endTime > newValue) {
     260                    word.shouldHighlight = true;
     261                    this.lastHighlightedWordIndex = i;
     262                    break;
     263                }
    255264            }
    256265        }
  • main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/js/AudioPlaybackModule.js

    r35445 r35446  
    2828function pollAudioTime(audioElement, store) {
    2929    var lastTime = 0;
    30     var shouldCommitNotPlaying = true;
    3130
    32     (function p() {
     31    (function poll() {
    3332        if (audioElement.currentTime !== lastTime) {
    3433            lastTime = audioElement.currentTime;
    35             shouldCommitNotPlaying = true;
    36 
    3734            store.commit("playbackStateSetCurrentTime", lastTime);
    38             store.commit("playbackStateSetIsPlaying", true);
    39         }
    40         else if (shouldCommitNotPlaying) {
    41             store.commit("playbackStateSetIsPlaying", false);
    42             shouldCommitNotPlaying = false;
    4335        }
    4436
    45         setTimeout(p, 33); // Slightly more than 30hz
     37        setTimeout(poll, 33); // Slightly more than 30hz
    4638    })();
    4739}
     
    7971        this.loadedAudio = new LoadedAudio(null, null);
    8072
    81         pollAudioTime(this.player, store)
     73        pollAudioTime(this.player, store);
     74
     75        this.player.addEventListener("ended", function() {
     76            store.commit("playbackStateSetIsPlaying", false);
     77        });
    8278    }
    8379
     
    8884     */
    8985    static async play(id, startTime = -1) {
    90         if (this.loadedAudio.id !== id) {
    91             this.loadedAudio = loadAudio(this.player, this.store.state.rawTranscriptions[id], this.loadedAudio);
    92 
    93             this.store.commit("playbackStateSetID", id);
    94         }
    95 
    9686        const playbackState = this.store.state.playbackState;
    9787
     
    10191        }
    10292
     93        if (this.loadedAudio.id !== id) {
     94            this.loadedAudio = loadAudio(this.player, this.store.state.rawTranscriptions.get(id), this.loadedAudio);
     95
     96            this.store.commit("playbackStateSetID", id);
     97        }
     98
    10399        this.player.currentTime = playbackTime;
    104100        await this.player.play();
     101
     102        this.store.commit("playbackStateSetLength", this.player.duration);
     103        this.store.commit("playbackStateSetIsPlaying", true);
    105104    }
    106105
    107106    static pause() {
    108107        this.player.pause();
     108        this.store.commit("playbackStateSetIsPlaying", false);
    109109    }
    110110}
  • main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/main.js

    r35445 r35446  
    104104            state.playbackState.currentTime = time;
    105105        },
     106        playbackStateSetLength(state, length) {
     107            state.playbackState.length = length;
     108        },
    106109
    107         /**
    108          * Sets the current playback state.
    109          * @param {*} state The state of the store.
    110          * @param {PlaybackState} playbackState The new playback state.
    111          */
    112         setPlaybackState(state, playbackState) {
    113             state.playbackState = playbackState;
    114         },
    115110        setTranslations(state, translations) {
    116111            state.translations = translations;
Note: See TracChangeset for help on using the changeset viewer.