audio renderer v1

This commit is contained in:
riqo 2020-12-13 15:07:06 -06:00
commit 64ac22f8d9
4 changed files with 103 additions and 43 deletions

View file

@ -3,28 +3,45 @@
<g id="Group_126" data-name="Group 126" transform="translate(0 0)">
<rect id="Rectangle_478" data-name="Rectangle 478" :width="bubbleWidth" height="34" rx="10" transform="translate(0 0)" fill="#b9b9b9"/>
<g id="Group_125" data-name="Group 125">
<!-- <path id="Path_328" data-name="Path 328" d="M0,25v-10" transform="translate(10 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
<path v-for="(path, index) in paths"
:key="index"
:id="path.id"
:data-name="path.name"
:d="path.d"
:transform="path.transform"
fill="none"
stroke="#000"
stroke-linecap="round"
stroke-width="1.5"
/>
<!-- <path id="Path_328" data-name="Path 328" d="M0,25v-10" transform="translate(10 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
<path id="Path_328" data-name="Path 328" d="M0,25v-15" transform="translate(15 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
<path id="Path_328" data-name="Path 328" d="M0,25v-20" transform="translate(20 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
<path id="Path_328" data-name="Path 328" d="M0,25v-15" transform="translate(25 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
<path id="Path_328" data-name="Path 328" d="M0,25v-10" transform="translate(30 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
<path id="Path_328" data-name="Path 328" d="M0,25v-5" transform="translate(120 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/> -->
</g>
<path id="Path_328" data-name="Path 328" d="M0,25v-5" transform="translate(120 0)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.5"/>
--> </g>
</g>
</svg>
</template>
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { defineComponent, computed, ref } from 'vue'
export default defineComponent ({
name: 'AudioInput',
props: {
bubbleWidth: Number
bubbleWidth: Number,
paths: Array
},
setup(props){
// need audioPath type/interface
const center = computed(() => {
if (props.bubbleWidth) {
return 175 - props.bubbleWidth / 2;

View file

@ -2,6 +2,7 @@
<audio-input
v-if="renderAudio"
:bubbleWidth="reactiveWidth"
:paths="paths"
/>
<text-input
v-else
@ -20,13 +21,19 @@ export default defineComponent({
components: {TextInput, AudioInput},
setup() {
const { input, renderAudio, reactiveWidth, textInputXoffset } = useInputRenderer();
const {
input,
renderAudio,
reactiveWidth,
textInputXoffset,
paths } = useInputRenderer();
return {
input,
textInputXoffset,
renderAudio,
reactiveWidth
reactiveWidth,
paths
}
}
})

View file

@ -10,17 +10,20 @@ export default function useInputRenderer() {
// program ref varaiables
const renderAudio = ref(false);
const reactiveWidth = ref(10);
const pathOffset = ref(10);
const paths = ref([]);
// get input feedback & handler function
const { keyDownHandler, input } = useKeyDownHandler();
// get text Offset and & textRender function
const { textInputXoffset, renderTextInput } = useTextInput(input, renderAudio);
// why do we have audio stuff here
let stream: any;
const {handleStream} = useStreamRecorder(renderAudio)
// why do we have audio stuff here ?
let stream: MediaStream;
const {renderStream} = useStreamRecorder(renderAudio)
onMounted(async () => {
stream = await useMediaStream()
const streamRes = await useMediaStream()
stream = streamRes.stream;
})
// stop stream recording on space keyup event
@ -30,6 +33,7 @@ export default function useInputRenderer() {
renderAudio.value = false;
input.value = "";
reactiveWidth.value = 10;
pathOffset.value = 10;
}
}
@ -54,7 +58,7 @@ export default function useInputRenderer() {
if (input === " " && renderAudio.value === false) {
console.log("record");
renderAudio.value = true;
handleStream(stream.stream, reactiveWidth);
renderStream(stream, reactiveWidth, pathOffset, paths);
return;
}
renderTextInput();
@ -64,7 +68,8 @@ export default function useInputRenderer() {
input,
renderAudio,
reactiveWidth,
textInputXoffset
textInputXoffset,
paths
}
}

View file

@ -1,23 +1,14 @@
import { watch, ref, inject } from "vue";
import useAudioRenderer from "@/composables/audioRenderer/useAudioRenderer";
import AnimeFunc from "@/types/animejs/index";
export default function useStreamRecorder(render: any) {
import {Ref} from '@/types/vueRef/index';
import { ref } from 'vue';
export default function useStreamRecorder(render: Ref<boolean>) {
let streamRecorder: MediaRecorder;
const chunks: Blob[] = [];
// imports animejs safely
let anime: AnimeFunc;
const animeInject: AnimeFunc | undefined = inject("animejs");
if (animeInject) anime = animeInject;
window.AudioContext = window.AudioContext;
let audio_context = new AudioContext();
const analyzer = audio_context.createAnalyser();
// window.AudioContext = window.AudioContext;
const audioContext = new AudioContext();
const analyzer = audioContext.createAnalyser();
analyzer.fftSize = 2048;
var bufferLengthAlt = analyzer.frequencyBinCount;
var dataArrayAlt = new Uint8Array(bufferLengthAlt);
let source: any;
const dataArray = new Uint8Array(analyzer.frequencyBinCount);
const initRecorder = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
@ -32,36 +23,76 @@ export default function useStreamRecorder(render: any) {
}
}
function visualize(w: any) {
interface AmplitudePath {
id: string;
name: string;
d: string;
transform: string;
}
function drawAlt() {
const createAudioPath = (a: number, offset: number) => {
const identifier = `path_${offset}`
const path: AmplitudePath = {
id: identifier,
name: identifier,
d: `M0,25v${-a}`,
transform: `translate(${offset} 0)`
}
return path;
}
const xInitial = 24;
const xFinal = 640;
function visualize(w: Ref<number>, p: Ref<number>, paths: Ref<any>) {
const amplitude = () => {
const dataView = dataArray.slice(xInitial, xFinal);
const sum = dataView.reduce((a, b) => a + b);
const average = sum / dataView.length;
const scaled = average * 0.45;
return scaled;
}
function draw() {
if (!render.value) {
return;
}
const drawVisual = requestAnimationFrame(drawAlt);
analyzer.getByteTimeDomainData(dataArrayAlt);
requestAnimationFrame(draw);
analyzer.getByteFrequencyData(dataArray);
// max-width
if (w.value === 190) {
if (w.value === 300) {
return;
}
// increase width and center as time passes
w.value++;
const center = 175 - w.value / 2;
// w.value= center;
// increase width as time passes
// get amplitude
const a = amplitude();
if (a > 1) {
w.value++;
p.value += 5;
console.log(a)
const path = createAudioPath(a, p.value);
paths.value.push(path)
}
// create path item
}
drawAlt();
draw();
}
function handleStream(s: MediaStream, w: any) {
source = audio_context.createMediaStreamSource(s);
function renderStream(s: MediaStream, w: Ref<number>, pathOffset: Ref<number>, paths: Ref<any>) {
const source = audioContext.createMediaStreamSource(s);
source.connect(analyzer);
visualize(w);
visualize(w, pathOffset, paths);
}
return {
initRecorder,
handleStream
renderStream
}
}