All Projects → guipace → Tempo

guipace / Tempo

Licence: other
Tempo is a full-stack web application and a music sharing platform dedicated to electronic music inspired on SoundCloud. It is built on React and Redux in the frontend and with an Express.js backend utilizing the Sequelize ORM as an interface to a PostgreSQL database.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Tempo

react-audioplayer
A customizable HTML5 audio player for React.js
Stars: ✭ 69 (+430.77%)
Mutual labels:  audio-player
rAudio-1
Raspberry Pi audio player: AirPlay, Audio CD, Bluetooth, DAB radio, DSP, Internet rafio, Multi-room, Spotify Connect, UPnP
Stars: ✭ 151 (+1061.54%)
Mutual labels:  audio-player
flutter sound
Flutter plugin for sound. Audio recorder and player.
Stars: ✭ 727 (+5492.31%)
Mutual labels:  audio-player
snapos
Snapcast OS
Stars: ✭ 73 (+461.54%)
Mutual labels:  audio-player
react-808
808 Drum Machine built using React.js hooks API
Stars: ✭ 51 (+292.31%)
Mutual labels:  audio-player
violin
🎵 Minimalistic music player for desktop devices.
Stars: ✭ 40 (+207.69%)
Mutual labels:  audio-player
pushtape-player.js
Customizable JS audio page player with global playback controls and autoscan (mutationobserver), built on Soundmanager2.
Stars: ✭ 27 (+107.69%)
Mutual labels:  audio-player
shairport-sync
AirPlay audio player. Shairport Sync adds multi-room capability with Audio Synchronisation
Stars: ✭ 5,532 (+42453.85%)
Mutual labels:  audio-player
AudioAnchor
Android audio player that tracks the listening progress of your audio books and podcasts
Stars: ✭ 167 (+1184.62%)
Mutual labels:  audio-player
bPlayer
A great replacement for audio elements
Stars: ✭ 68 (+423.08%)
Mutual labels:  audio-player
JetTunes-Desktop-Music-Player
Material design music player made with javafx
Stars: ✭ 36 (+176.92%)
Mutual labels:  audio-player
MusicFolderPlayer
An elegant HTML5 web folder player for parties and/or private music collections, with playlist management that's just better.
Stars: ✭ 89 (+584.62%)
Mutual labels:  audio-player
VKAudioPlayer
VK Audio Player on Delphi
Stars: ✭ 16 (+23.08%)
Mutual labels:  audio-player
hermes-audio-server
An open source implementation of the audio server part of the Hermes protocol
Stars: ✭ 23 (+76.92%)
Mutual labels:  audio-player
roover
🐱 A lightweight audio library for React apps.
Stars: ✭ 70 (+438.46%)
Mutual labels:  audio-player
web-rpi-fm
Web interface for Raspberry Pi fm transmitter. Made using Vue.js and Python.
Stars: ✭ 33 (+153.85%)
Mutual labels:  audio-player
Miza
A multipurpose Discord bot.
Stars: ✭ 61 (+369.23%)
Mutual labels:  audio-player
arduino-stoerbert
MP3 player for small children - firmware & PCB schematic
Stars: ✭ 31 (+138.46%)
Mutual labels:  audio-player
android-audio-sensei
High-level library to make android audio recording and playing more simple by handling boring stuff like runtime permissions and by completely abstracting audio playback controller
Stars: ✭ 41 (+215.38%)
Mutual labels:  audio-player
facet
Facet is a live coding system for algorithmic music
Stars: ✭ 72 (+453.85%)
Mutual labels:  audio-player

Tempo

Tempo

Description

Tempo is a full-stack web application and a music sharing platform dedicated to electronic music inspired on SoundCloud.

Links

Primary Languages

  • JavaScript
  • HTML5
  • CSS3
  • SQL

Technologies Implemented

Developing

Below are instructions to run the application on a local development environment.

Pre-installed requirements:

  • Node.js
  • PostgreSQL

Instructions:

  1. Clone this repository

    git clone https://github.com/guipace/Tempo.git
  2. Change directory

    cd Tempo && cd backend
  3. Install node modules

    npm install
  4. Create your own environment variables files (.env) based on the provided examples (.env.example) in the backend directory.

  5. Create a user in your PostgreSQL that matches your environment variables configuration.

  6. Use Sequelize to create the database

    npx dotenv sequelize-cli db:create
  7. Apply migrations to the database

    npx dotenv sequelize-cli db:migrate
  8. Seed the database

    npx dotenv sequelize db:seed:all
  9. In another terminal, change directories into the frontend directory

    cd frontend
  10. Install node modules

    npm install
  11. Run backend application in first terminal

    npm start
  12. Run the frontend application in second terminal

    npm start
  13. The application should open in your default browser.

Challenges

A challenge faced in the development of SoarView includes the following:

  • In order to improve the user experience I wanted to have an audio player that persisted as the user navigated across the application and visually show a waveform representing the track being played. In order to have the waveform on both the persistent player and on the track page with a visual representation if audio is playing and at what point in the track it is, I had to synchronize two instances of the audio player. While according to the wavesurfer.js documentation it was not specifically intended for this use, I developed a solution that allowed for this by using React components and Redux for state management.

Code Highlight

  • Implementation of Wavesurfer.js library with integration with Redux to synchronize with two audio player instances and control state of audio track.

    const formWaveSurferOptions = (ref) => ({
        container: ref,
        waveColor: "#BFC0C0",
        progressColor: "#EA5C1F",
        cursorColor: "transparent",
        barWidth: 4,
        barRadius: 1,
        responsive: true,
        height: 50,
        normalize: true,
        partialRender: true,
        hideScrollbar: true,
    });
    
    export let wavesurfer;
    
    export function Player() {
        const dispatch = useDispatch();
        const sessionUser = useSelector(state => state.session.user);
        const currentTrack = useSelector(state => state.player.currentTrack);
        const isPlaying = useSelector(state => state.player.isPlaying);
        const waveformRef = useRef(null);
        wavesurfer = useRef(null);
        const [playing, setPlay] = useState(false);
        const [volume, setVolume] = useState(0.5);
    
        let url;
        if (currentTrack) {
            url = currentTrack.awsUrl;
        }
    
        if (!url) {
        url =
            "https://www.mfiles.co.uk/mp3-downloads/brahms-st-anthony-chorale-theme-two-pianos.mp3";
        }
    
        // Create new WaveSurfer instance on component mount and when url changes
        useEffect(() => {
            setPlay(false);
            const options = formWaveSurferOptions(waveformRef.current);
            wavesurfer.current = WaveSurfer.create(options);
            wavesurfer.current.load(url);
            wavesurfer.current.on("ready", function () {
                wavesurfer.current.play();
                setPlay(true);
    
                // Make sure object still available when file loaded
                if (wavesurfer.current) {
                    wavesurfer.current.setVolume(volume);
                    setVolume(volume);
                }
            });
    
        // Removes events, elements and disconnects Web Audio nodes when component unmounts
        return () => wavesurfer.current.destroy();
        }, [url]);
    
        useEffect(() => {
            setPlay(isPlaying);
        }, [isPlaying]);
    
        const handlePlayPause = () => {
            if (isPlaying) { dispatch(stopTrack()) }
            else { dispatch(playAudioTrack()) }
            wavesurfer.current.playPause();
        };
    
        const handleStop = () => {
            dispatch(stopTrack());
            dispatch(unloadTrack());
        }
    
        const onVolumeChange = (e) => {
            const { target } = e;
            const newVolume = +target.value;
            if (newVolume) {
                setVolume(newVolume);
                wavesurfer.current.setVolume(newVolume || 1);
            }
        };
    
        return (
            <>
                {sessionUser &&
                <>
                    <div id='placeholder-for-player' className='bottom-0 h-20 bg-space-cadet'></div>
                    <div className='fixed w-screen z-10 h-20 bottom-0 bg-space-cadet bg-opacity-80 px-10 text-silver flex flex-row items-center'>
                        <div className='w-1/6 flex flex-row items-center'>
                            <Button
                                onClick={handlePlayPause}
                                className='text-white hover:text-mandarin font-bold h-10 w-10 rounded-full focus:outline-none'
                            >
                                {!playing ? <i className="fas fa-play"></i> : <i className="fas fa-pause"></i>}
                            </Button>
                            <Button
                                onClick={handleStop}
                                className='text-white hover:text-mandarin font-bold h-10 w-10 mr-5 rounded-full focus:outline-none'
                            >
                                <i className="fas fa-stop"></i>
                            </Button>
                            <div className='flex flex-col items-center flex-grow mr-5'>
                                <div>Volume</div>
                                <input
                                    className="slider w-36 mt-2"
                                    type="range"
                                    id="volume"
                                    name="volume"
                                    min="0.01"
                                    max="1"
                                    step=".025"
                                    onChange={onVolumeChange}
                                    defaultValue={volume}
                                />
                            </div>
                        </div>
                        <div id="waveform" ref={waveformRef} className='flex-grow' />
                        <div className='w-3/12 pl-5 flex flex-row items-center'>
                            <div className='flex-initial'><img src={currentTrack.imageUrl} alt='Track' className='w-10 h-10 shadow-2xl rounded'></img></div>
                            <div className='flex flex-col pl-5'>
                                <div>{currentTrack.User.username}</div>
                                <div>{currentTrack.title}</div>
                            </div>
                        </div>
                    </div>
                </>
                }
            </>
        );
    }
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].