Skip to content

Commit

Permalink
add functionality for play mode button (#402)
Browse files Browse the repository at this point in the history
* This commit adds functionality for the play mode button

Adds functionality for each mode with continue, stop, repeat page, and
repeat selection.

* change for lint

* show play button on playmode stop

This shows the play button if the playmode is set to stop and the audio is ended.

* Fix issues with Repeat Selection

---------

Co-authored-by: Chris Hubbard <[email protected]>
  • Loading branch information
ChristopherRankin and chrisvire authored Oct 8, 2023
1 parent 6cc598e commit 664ab5d
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 21 deletions.
4 changes: 2 additions & 2 deletions src/lib/components/AudioBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ TODO:
function mayResetPlayMode(hasTiming) {
// If the current mode is repeatSelection and the reference is changed to something without timing
// (even chapter without audio), then reset the playMode. This matches how the Android app behaves.
if (!hasTiming && $playMode === 'repeatSelection') {
if (!hasTiming && $playMode.mode === 'repeatSelection') {
playMode.reset();
}
}
Expand Down Expand Up @@ -68,7 +68,7 @@ TODO:
class="dy-btn-sm dy-btn-ghost"
on:click={() => playMode.next($refs.hasAudio?.timingFile)}
>
<svelte:component this={playModeIconOptions[$playMode]} color={iconColor} />
<svelte:component this={playModeIconOptions[$playMode.mode]} color={iconColor} />
</button>
{/if}
</div>
Expand Down
132 changes: 127 additions & 5 deletions src/lib/data/audio.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import config from '$lib/data/config';
import { audioHighlightElements } from '$lib/data/stores/audio.js';
import {
audioHighlightElements,
playMode,
defaultPlayMode,
PLAYMODE_CONTINUE,
PLAYMODE_STOP,
PLAYMODE_REPEAT_PAGE,
PLAYMODE_REPEAT_SELECTION
} from '$lib/data/stores';
import { refs, audioPlayer as audioPlayerStore, audioPlayerDefault } from '$lib/data/stores';
import { MRUCache } from '$lib/data/mrucache';

interface AudioPlayer {
audio: HTMLAudioElement;
loaded: boolean;
Expand All @@ -22,6 +29,17 @@ audioPlayerStore.subscribe(async (value) => {
currentAudioPlayer = value;
await getAudio();
});
export let currentPlayMode;
playMode.subscribe((value) => {
if (
currentPlayMode &&
currentPlayMode.mode !== value.mode &&
value.mode === PLAYMODE_REPEAT_SELECTION
) {
value.range = getCurrentVerseTiming();
}
currentPlayMode = value;
});
// produces the cache key for the mru audio cache
function cacheKey(collection, book, chapter) {
return `${collection}-${book}-${chapter}`;
Expand Down Expand Up @@ -125,11 +143,99 @@ export function seek(position) {
pause();
currentAudioPlayer.audio.currentTime = position;
currentAudioPlayer.progress = position;
playMode.set({ ...currentPlayMode, range: getCurrentVerseTiming() });
audioPlayerStore.set(currentAudioPlayer);
if (playing === true) {
play();
}
}
let warmdown = undefined;
function handlePlayMode() {
if (warmdown) {
warmdown--;
if (warmdown === 0) {
if (currentPlayMode.mode === PLAYMODE_CONTINUE) {
skip(1);
playMode.set({ ...currentPlayMode, continue: true });
} else if (currentPlayMode.mode === PLAYMODE_REPEAT_PAGE) {
seek(0);
} else if (currentPlayMode.mode === PLAYMODE_REPEAT_SELECTION) {
seek(currentPlayMode.range.start);
play();
}
warmdown = undefined;
}
return;
}
if (currentAudioPlayer.audio.ended) {
if (currentPlayMode.mode === PLAYMODE_STOP) {
pause();
audioPlayerStore.set(currentAudioPlayer);
} else {
warmdown = 5;
}
return;
}
if (currentPlayMode.mode === PLAYMODE_CONTINUE && currentPlayMode.continue) {
playMode.set({ ...currentPlayMode, continue: false });
play();
}
if (currentPlayMode.mode === PLAYMODE_REPEAT_SELECTION) {
if (currentPlayMode.range === defaultPlayMode.range) {
const resultArray = getCurrentVerseTiming();
if (resultArray.start === undefined || resultArray.end === undefined) {
return;
}
playMode.set({
...currentPlayMode,
range: { start: resultArray.start, end: resultArray.end }
});
}
if (currentAudioPlayer.progress + 0.05 > currentPlayMode.range.end) {
pause();
warmdown = 5;
}
}
}
// gets the current verse start and end tag
function getCurrentVerseTiming() {
let end;
let start;
for (let i = 0; i < currentAudioPlayer.timing.length; i++) {
const timing = currentAudioPlayer.timing[i];
if (
currentAudioPlayer.progress >= timing.starttime &&
currentAudioPlayer.progress < timing.endtime
) {
const verseNumber = parseInt(timing.tag, 10);
for (let k = i + 1; k >= 0; k--) {
const startVerseNumber = parseInt(currentAudioPlayer.timing[k].tag, 10);
if (startVerseNumber !== verseNumber) {
start = currentAudioPlayer.timing[k + 1].tag;
break;
}
if (k === 0) {
start = currentAudioPlayer.timing.tag;
break;
}
}
for (let j = i + 1; j < currentAudioPlayer.timing.length; j++) {
const endVerseNumber = parseInt(currentAudioPlayer.timing[j].tag, 10);
if (endVerseNumber !== verseNumber) {
end = currentAudioPlayer.timing[j - 1].tag;
break;
}
if (j === currentAudioPlayer.timing.length - 1) {
end = currentAudioPlayer.timing.tag;
break;
}
}
break;
}
}
return getVerseTimingRange(start, end);
}
// function get range of current index all labels of the current verse playing
// calls updatehighlights() to see if highlights need to be change
function updateTime() {
if (!currentAudioPlayer.loaded) {
Expand All @@ -142,9 +248,7 @@ function updateTime() {
if (currentAudioPlayer.timing && currentAudioPlayer.progress) {
updateHighlights();
}
if (currentAudioPlayer.audio.ended) {
toggleTimeRunning();
}
handlePlayMode();
}
// calls updateTime() every 100ms
function toggleTimeRunning() {
Expand Down Expand Up @@ -295,3 +399,21 @@ export function seekToVerse(verseClicked) {
//forces highlighting change
updateTime();
}
// takes a start and end tag and returns the range of times
function getVerseTimingRange(startverse, endverse) {
const elements = currentAudioPlayer.timing;
let start;
for (let i = 0; i < elements.length; i++) {
const tag = currentAudioPlayer.timing[i].tag;
if (startverse === tag) {
const newstarttime = currentAudioPlayer.timing[i].starttime;
start = newstarttime;
}
if (endverse === tag) {
const newendtime = currentAudioPlayer.timing[i].endtime;
const end = newendtime;
const range = { start, end };
return range;
}
}
}
46 changes: 32 additions & 14 deletions src/lib/data/stores/audio.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,49 @@ export const audioPlayerDefault = {
};
export const audioPlayer = writable({ ...audioPlayerDefault });

export const PLAYMODE_CONTINUE = 'continue';
export const PLAYMODE_STOP = 'stop';
export const PLAYMODE_REPEAT_PAGE = 'repeatPage';
export const PLAYMODE_REPEAT_SELECTION = 'repeatSelection';

export const defaultPlayModeRange = { start: 0, end: 0 };
export const defaultPlayMode = {
mode: config.mainFeatures['audio-goto-next-chapter'] ? PLAYMODE_CONTINUE : PLAYMODE_STOP,
range: defaultPlayModeRange,
continue: false
};
function createPlayMode() {
const external = writable(config.mainFeatures['audio-goto-next-chapter'] ? 'continue' : 'stop');
const external = writable(defaultPlayMode);
return {
subscribe: external.subscribe,
set: external.set,
next: (hasTiming) => {
const cur = get(external);
let next = cur;
switch (cur) {
case 'continue':
next = 'stop';
const { mode, range } = get(external);
let nextMode = mode;
let nextRange = range;
switch (mode) {
case PLAYMODE_CONTINUE:
nextMode = PLAYMODE_STOP;
break;
case 'stop':
next = 'repeatPage';
case PLAYMODE_STOP:
nextMode = PLAYMODE_REPEAT_PAGE;
break;
case 'repeatPage':
next = hasTiming ? 'repeatSelection' : 'continue';
case PLAYMODE_REPEAT_PAGE:
if (hasTiming) {
nextMode = PLAYMODE_REPEAT_SELECTION;
nextRange = defaultPlayModeRange;
} else {
nextMode = PLAYMODE_CONTINUE;
}
break;
case 'repeatSelection':
next = 'continue';
case PLAYMODE_REPEAT_SELECTION:
nextMode = PLAYMODE_CONTINUE;
break;
}
external.set(next);
external.set({ mode: nextMode, range: nextRange });
},
reset: () => {
external.set('continue');
external.set(defaultPlayMode);
}
};
}
Expand Down

0 comments on commit 664ab5d

Please sign in to comment.