message playback anim
This commit is contained in:
parent
ceb7743c8b
commit
88d7029a5c
4 changed files with 80 additions and 32 deletions
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
import { sendAudio } from './session'
|
import { sendAudio } from './session'
|
||||||
import { ipcMain } from "electron";
|
import { ipcMain } from "electron";
|
||||||
|
import { backgroundMitt } from './emitter';
|
||||||
|
|
||||||
const portAudio = require('naudiodon');
|
const portAudio = require('naudiodon');
|
||||||
|
|
||||||
let ai: typeof portAudio.AudioIO | null = null;
|
let ai: typeof portAudio.AudioIO | null = null;
|
||||||
|
|
@ -83,9 +85,14 @@ export function play(input: Buffer): void {
|
||||||
|
|
||||||
const audio = bufSplit(input, 8192);
|
const audio = bufSplit(input, 8192);
|
||||||
|
|
||||||
// call this fuction after last audio chunk has been written.
|
// Called on end of write.
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
// TODO: clear portAudio writable buffer on write end.
|
|
||||||
|
// We stop audio playback anim.
|
||||||
|
backgroundMitt.emit('ipc-renderer', {
|
||||||
|
endpoint: 'stop-playback-anim'
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write();
|
write();
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,18 @@ const onMessage = (message: string): void => {
|
||||||
|
|
||||||
// check to see if this is a Render Message.
|
// check to see if this is a Render Message.
|
||||||
if (m.content) {
|
if (m.content) {
|
||||||
|
|
||||||
// If there is audio, play it.
|
// If there is audio, play it.
|
||||||
if (m.content.audio) {
|
if (m.content.audio) {
|
||||||
const audioBytes = Buffer.from(m.content.audio as string, 'hex');
|
const audioBytes = Buffer.from(m.content.audio as string, 'hex');
|
||||||
|
m.content.audio = true;
|
||||||
play(audioBytes);
|
play(audioBytes);
|
||||||
|
} else {
|
||||||
|
m.content.audio = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is no unique id, add it.
|
// if there is no unique id, add it.
|
||||||
if(!m.uid) m.uid = uuidv4();
|
if(!m.uid) m.uid = uuidv4();
|
||||||
}
|
}
|
||||||
|
|
||||||
backgroundMitt.emit('ipc-renderer', {
|
backgroundMitt.emit('ipc-renderer', {
|
||||||
|
|
|
||||||
|
|
@ -143,28 +143,22 @@ export default defineComponent({
|
||||||
.pause {
|
.pause {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
&::before {
|
&::before {
|
||||||
-moz-animation: audio1 1.5s infinite ease-in-out;
|
-moz-animation: circle1 1.5s infinite ease-in-out;
|
||||||
-o-animation: audio1 1.5s infinite ease-in-out;
|
-o-animation: circle1 1.5s infinite ease-in-out;
|
||||||
-webkit-animation: audio1 1.5s infinite ease-in-out;
|
-webkit-animation: circle1 1.5s infinite ease-in-out;
|
||||||
animation: audio1 1.5s infinite ease-in-out;
|
animation: circle1 1.5s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
&::after {
|
&::after {
|
||||||
-moz-animation: audio2 2.2s infinite ease-in-out;
|
-moz-animation: circle2 2.2s infinite ease-in-out;
|
||||||
-o-animation: audio2 2.2s infinite ease-in-out;
|
-o-animation: circle2 2.2s infinite ease-in-out;
|
||||||
-webkit-animation: audio2 2.2s infinite ease-in-out;
|
-webkit-animation: circle2 2.2s infinite ease-in-out;
|
||||||
animation: audio2 2.2s infinite ease-in-out;
|
animation: circle2 2.2s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate-audio1 {
|
@keyframes circle1 {
|
||||||
-moz-animation: audio1 1.5s infinite ease-in-out;
|
|
||||||
-o-animation: audio1 1.5s infinite ease-in-out;
|
|
||||||
-webkit-animation: audio1 1.5s infinite ease-in-out;
|
|
||||||
animation: audio1 1.5s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
@keyframes audio1 {
|
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4);
|
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4);
|
||||||
|
|
@ -179,13 +173,8 @@ export default defineComponent({
|
||||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25);
|
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animate-audio2 {
|
|
||||||
-moz-animation: audio2 2.2s infinite ease-in-out;
|
@keyframes circle2 {
|
||||||
-o-animation: audio2 2.2s infinite ease-in-out;
|
|
||||||
-webkit-animation: audio2 2.2s infinite ease-in-out;
|
|
||||||
animation: audio2 2.2s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
@keyframes audio2 {
|
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Render Crimata icon or friend's initials. -->
|
<!-- Render Crimata icon or friend's initials. -->
|
||||||
<div v-if="message.modifier == 'fr'" class="photo">
|
<div v-if="message.modifier == 'fr'" class="photo"
|
||||||
|
:class="{ playing: isPlaying }"
|
||||||
|
>
|
||||||
{{ message.context[0] }}
|
{{ message.context[0] }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -65,7 +67,7 @@
|
||||||
|
|
||||||
<script lang='ts'>
|
<script lang='ts'>
|
||||||
|
|
||||||
import {defineComponent} from 'vue';
|
import {defineComponent, ref, onMounted} from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "MessageItem",
|
name: "MessageItem",
|
||||||
|
|
@ -75,6 +77,29 @@
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props) {
|
||||||
|
let isPlaying = ref(false);
|
||||||
|
|
||||||
|
const onStopPlayback = (e: any) => {
|
||||||
|
window.ipcRenderer.removeAllListeners("stop-playback-anim");
|
||||||
|
isPlaying.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
// Turn on audio playback animation if audio.
|
||||||
|
if (props.message.content.audio === true) {
|
||||||
|
window.ipcRenderer.on("stop-playback-anim", onStopPlayback);
|
||||||
|
isPlaying.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
isPlaying
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
@ -152,6 +177,15 @@
|
||||||
animation-duration: 0.25s;
|
animation-duration: 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes appear {
|
||||||
|
from {
|
||||||
|
transform: scale(0.3);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#aiBubble {
|
#aiBubble {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -191,12 +225,26 @@
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes appear {
|
// Apply for audio message playback.
|
||||||
from {
|
.playing {
|
||||||
transform: scale(0.3);
|
animation-name: circle1;
|
||||||
|
animation-duration: 2s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes circle1 {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 0 0.4em rgba(195, 195, 195, 0.4), 0 0 0 0.25em rgba(195, 195, 195, 0.15);
|
||||||
}
|
}
|
||||||
to {
|
25% {
|
||||||
transform: scale(1);
|
box-shadow: 0 0 0 0.15em rgba(195, 195, 195, 0.15), 0 0 0 0.4em rgba(195, 195, 195, 0.3);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 0 0 0.55em rgba(195, 195, 195, 0.55), 0 0 0 0.15em rgba(195, 195, 195, 0.05);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
box-shadow: 0 0 0 0.25em rgba(195, 195, 195, 0.25), 0 0 0 0.55em rgba(195, 195, 195, 0.45);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue