About me
Blog
Analytics

Control music using voice

โณ 5 mins read time


I use a Raspberry Pi to control music in my house but the problem is that Iโ€™m tired of looking for my phone to change the music, or change the volume or search for a specific song. Instead I want to control my music using my voice and I have the following concerns:

  1. I want to use Snips assistant for voice recognition. It allows to have an offline voice recognition system and it has several available languages. Iโ€™m using an Spanish assistant, but Snips versatility allows to change the language assistant easily so my code can be used for different language assistants.

  2. Use a Bluetooth speaker. I use a snips starter kit which includes a passive speaker, but sometimes I like to hear loud music but since the microphone is near the speaker I prefer to use a Bluetooth speaker to avoid interference.

  3. I want to be able to control all sources of music. I follow podcasts but I also like to hear radio stations and stream music from online services like Soundcloud.

  4. Using javascript language for easy asynchronous code executing. Instead of using python and specially python2 to control snips.

My solution

Your browser doesn't support HTML5 video.

I will show I solve my problems:

  • My code uses only javascript. I got some inspiration from the snips documentation. So 4 point is checked.
  • To connect to Bluetooth I just paired my Raspberry Pi with a Bluetooth speaker using bluetoothctl. Whenever you have a problem pairing a bluetooth speaker, there are several resources available online. I personally found this one very useful. Then I used npm bluetoothctl library to ensure to connect to my devices every time they are available I use the following code to do it:
const blue = require("bluetoothctl");
  
/* Automatic Bluetooth connection */
blue.Bluetooth()
blue.on(blue.bluetoothEvents.Device, function (devices) {
  const hasBluetooth=blue.checkBluetoothController();
  if(hasBluetooth) {
    devices.forEach((device) => {
      blue.connect(device.mac)
    })
  }
})

A bluetooth speaker

  • I use mopidy to control music on the raspberry pi. As said in mopidy page:

Mopidy plays music from local disk, Spotify, SoundCloud, Google Play Music, and more. You edit the playlist from any phone, tablet, or computer using a range of MPD and web clients.

I use mopidy.js to control mopidy within my javascript code. I create some functions to add a song to the queue and play them, change the volume, search for tracks and change the song in the queue.

// set music
function connectMopidyRadio(radio) {
 const mopidy = new Mopidy({
   webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
 });
 mopidy.on("state", async () => {
   await setRadio(mopidy, radio);
 });
 mopidy.on("event", console.log);
}
  
async function setRadio (mopidy, radio) {
 await mopidy.tracklist.clear()
 await mopidy.playback.pause()
 await mopidy.tracklist.add({uris: radio})
 tracks = await mopidy.tracklist.getTlTracks();
 await mopidy.playback.play({tlid: tracks[0].tlid});
 mopidy.off();
}
  
function searchArtist (rawValue) {
 const mopidy = new Mopidy({
   webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
 });
 mopidy.on("state", async () => {
   console.log(`Searching for ${rawValue}`)
   say.speak(`Searching for ${rawValue}`)
   let result = await mopidy.library.search({'any': rawValue, 'uris': ['soundcloud:']})
   await setRadio(mopidy, result[0]['tracks'].map(item => item.uri));
 });
}
function nextSong () {
 const mopidy = new Mopidy({
   webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
 });
 mopidy.on("state", async () => {
   console.log('Next');
   say.speak(`Next`)
   await mopidy.playback.next();
 });
}
  
function volumeDown () {
 const mopidy = new Mopidy({
   webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
 });
 mopidy.on("state", async () => {
   console.log('Volume down');
   say.speak(`Volume down`)
   await mopidy.mixer.setVolume([5])
   mopidy.off();
 });
}
  • I also created a function to download the episodes from my favorite podcast whenever Iโ€™m connected to the internet.
async function downloadPostcast(url) {
  let feed = await parser.parseURL(url);
  console.log("RSS: ", feed.title);
  // Get existing local files
  const dir = '/var/lib/mopidy/media' 
  const files = fs.readdirSync(dir)
    .map((fileName) => {
      return {
        name: fileName,
        time: fs.statSync(dir + '/' + fileName).mtime.getTime()
      };
    })
    .sort((a, b) => b.time - a.time) // Sort decending order
    .map((v) => v.name);
  // If there are new episodes, download them
  feed.items.slice(0,5).forEach(async (item) => {
    let pieces = item.guid.split('/')
    console.log(`Checking : ${pieces[pieces.length-1]}`);
    if (files.indexOf(pieces[pieces.length-1]) === -1) {
      console.log(`Downloading ${item.title}:${item.guid}`)
      let { guid } = item; 
      await downloadFile(guid, pieces)
    }
  });
  // Delete old files
  if (files.length > 5) {
    files.slice(6, files.length).forEach((item) => {
      console.log(`Removing ${item}`)
      let path = Path.resolve(dir, item)
      fs.unlinkSync(path);
    })
  }
}

Outcome

Iโ€™m very happy with the results. Iโ€™m able to control my music with my voice and I donโ€™t even have to be near my phone. I uploaded a video that illustrates my results, my code is available on github.

My snips handler

In relation with ๐Ÿท๏ธ snips, raspberrypi, nodejs:

Christmas project: Control lights with the voice and Raspberry Pi

Imagine having interactive Christmas lights! This article will show you how to control lights with your Raspberry Pi and adding voice command superpowers.

Arduino MKR FOX 1200 for IoT and a serverless architecture using Sigfox API

Microcontrollers are adapted for simple task which don't need a lot of battery power. This post shows how to put in actions the Arduino MKR Fox for capturing temperature measurements, send them to Sigfox Cloud and expose the results in a serverless dashboard.

SSD object detection for video streaming using a Raspberry Pi

This post shows how to combine resources from a Raspberry pi with object detection algorithms in video streaming application.

Smart Compost Monitoring

An ESP8266 measures temperature and uses the Sigfox network to send the measurements into a web server to monitor a compost pile.

๐Ÿ“… Nov 9, 2019  Hackster.io   micropython   esp8266   nodejs   chartjs
Subscribe to my newsletter ๐Ÿ“ฐ

and share it with your friends: