Skip to content

Commit

Permalink
Feat visualize audio (#50)
Browse files Browse the repository at this point in the history
* Add audio visualizer

* Finalize visualizer addition
  • Loading branch information
samhirtarif authored Jun 6, 2023
1 parent c6d9e64 commit 135871c
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 21 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ ReactDOM.createRoot(document.getElementById("root")).render(
| **`onNotAllowedOrFound`** | This gets called when the `getUserMedia` promise is rejected. It takes the resultant `DOMException` as its parameter | N/A | Yes
| **`downloadOnSavePress`** | A `boolean` value that determines if the recording should be downloaded when "Save recording" option is pressed | `false` | Yes |
| **`downloadFileExtension`** | The file extension to be used for the downloaded file. Allowed values are `mp3`, `wav` and `webm` | `mp3` | Yes |
| **`showVisualizer`** | Displays a waveform visualization for the audio when set to `true` | `false` | Yes |
| **`classes`** | This allows class names to be passed to modify the styles for the entire component or specific portions of it | N/A | Yes |
---
### **useAudioRecorder** hook
Expand Down
37 changes: 31 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-audio-voice-recorder",
"private": false,
"version": "1.1.7",
"version": "1.2.0",
"license": "MIT",
"author": "",
"repository": {
Expand Down Expand Up @@ -79,14 +79,15 @@
"eslint-plugin-storybook": "^0.6.4",
"jsdom": "^20.0.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.8.2",
"vite": "^3.2.7",
"vite-plugin-css-injected-by-js": "^3.1.0",
"vite-plugin-dts": "^1.4.1",
"vitest": "^0.22.1"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-audio-visualize": "^1.0.0"
}
}
42 changes: 34 additions & 8 deletions src/components/AudioRecordingComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useState, useEffect, ReactElement } from "react";
import { Props } from "./interfaces";
import useAudioRecorder from "../hooks/useAudioRecorder";
import { LiveAudioVisualizer } from "react-audio-visualize";

import micSVG from "../icons/mic.svg";
import pauseSVG from "../icons/pause.svg";
Expand All @@ -20,6 +21,7 @@ import "../styles/audio-recorder.css";
* @prop `onNotAllowedOrFound`: A method that gets called when the getUserMedia promise is rejected. It receives the DOMException as its input.
* @prop `downloadOnSavePress` If set to `true` the file gets downloaded when save recording is pressed. Defaults to `false`
* @prop `downloadFileExtension` File extension for the audio filed that gets downloaded. Defaults to `mp3`. Allowed values are `mp3`, `wav` and `webm`
* @prop `showVisualizer` Displays a waveform visualization for the audio when set to `true`. Defaults to `false`
* @prop `classes` Is an object with attributes representing classes for different parts of the component
*/
const AudioRecorder: (props: Props) => ReactElement = ({
Expand All @@ -29,6 +31,7 @@ const AudioRecorder: (props: Props) => ReactElement = ({
audioTrackConstraints,
downloadOnSavePress = false,
downloadFileExtension = "mp3",
showVisualizer = false,
classes,
}: Props) => {
const {
Expand All @@ -39,6 +42,7 @@ const AudioRecorder: (props: Props) => ReactElement = ({
isRecording,
isPaused,
recordingTime,
mediaRecorder,
} =
recorderControls ??
// eslint-disable-next-line react-hooks/rules-of-hooks
Expand Down Expand Up @@ -106,14 +110,36 @@ const AudioRecorder: (props: Props) => ReactElement = ({
{Math.floor(recordingTime / 60)}:
{String(recordingTime % 60).padStart(2, "0")}
</span>
<span
className={`audio-recorder-status ${
!isRecording ? "display-none" : ""
} ${classes?.AudioRecorderStatusClass ?? ""}`}
>
<span className="audio-recorder-status-dot"></span>
Recording
</span>
{showVisualizer ? (
<span
className={`audio-recorder-visualizer ${
!isRecording ? "display-none" : ""
}`}
>
{mediaRecorder && (
<LiveAudioVisualizer
mediaRecorder={mediaRecorder}
barWidth={2}
gap={2}
width={140}
height={30}
fftSize={512}
maxDecibels={-10}
minDecibels={-80}
smoothingTimeConstant={0.4}
/>
)}
</span>
) : (
<span
className={`audio-recorder-status ${
!isRecording ? "display-none" : ""
} ${classes?.AudioRecorderStatusClass ?? ""}`}
>
<span className="audio-recorder-status-dot"></span>
Recording
</span>
)}
<img
src={isPaused ? resumeSVG : pauseSVG}
className={`audio-recorder-options ${
Expand Down
4 changes: 4 additions & 0 deletions src/components/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export interface Props {
* File extension for the audio filed that gets downloaded
**/
downloadFileExtension?: "mp3" | "wav" | "webm";
/**
* Displays a waveform visualization for the audio when set to `true`. Defaults to `false`
**/
showVisualizer?: boolean;
/**
* Custom classes to changes styles.
**/
Expand Down
9 changes: 5 additions & 4 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<AudioRecorder
onRecordingComplete={(blob) => addAudioElement(blob)}
audioTrackConstraints={{
noiseSuppression: true,
echoCancellation: true,
}}
// audioTrackConstraints={{
// noiseSuppression: true,
// echoCancellation: true,
// }}
onNotAllowedOrFound={(err) => console.table(err)}
showVisualizer={true}
/>
</React.StrictMode>
);
8 changes: 8 additions & 0 deletions src/styles/audio-recorder.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@
display: none;
}

.audio-recorder-visualizer {
margin-left: 15px;
flex-grow: 1;
align-self: center;
display: flex;
align-items: center;
}

@keyframes fading-ar-status {
0% {opacity: 1;}
50% {opacity: 0;}
Expand Down

0 comments on commit 135871c

Please sign in to comment.