element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog Raspberry Pi Party DJ
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Raspberry Pi to participate - click to join for free!
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
GPIO Pinout
Raspberry Pi Wishlist
Comparison Chart
Quiz
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: oneleggedredcow
  • Date Created: 16 Jan 2014 2:02 AM Date Created
  • Views 1218 views
  • Likes 4 likes
  • Comments 5 comments
Related
Recommended
  • rpiintermediate

Raspberry Pi Party DJ

oneleggedredcow
oneleggedredcow
16 Jan 2014

Trying to come up with a good playlist for a party can be a real challenge.  Are the guests going to be more into Metallica or Rise Against? Is everybody going to be bored when the third Tool song comes on in a row, or are they feeling it?

 

Well, what if the guests could vote American Idol style for the next song that they want to hear?  This way the music of the party could be set by the guests and match their current mood. Everyone would be given the choice between three songs as to what they want to hear next.  The song that receives the most votes is played and three new song choices are picked for the guests to vote on.

 

Web Sockets

 

To build the project, I’m going to use a fairly new technology called web sockets.  Web sockets allow for two way, asynchronous communication between the browser and the server.  This is great news for our program because this means that the browser can notify the server of any votes that the user casts and the server can notify the browser when the song choices have changed.

 

Using the python tornado web socket server, the basic set up of a program looks like this:

 

class WSHandler(tornado.websocket.WebSocketHandler):

def open(self):

print 'new connection'

 

def on_message(self, msg):

print 'message received'

 

def on_close(self):

print 'connection closed'

 

application = tornado.web.Application([

(r'/ws', WSHandler)

])

 

if __name__ == "__main__":

http_server = tornado.httpserver.HTTPServer(application)

http_server.listen(8888)

tornado.ioloop.IOLoop.instance().start()

 

The basic program is pretty self- explanatory.  We start by defining a class that is going to respond to the various events that are going to occur: open a new connection, receive a message, and close a connection. Next we specify the location that we will be listening to “/ws” and the port that we will be listening on (8888). Finally, we go into an infinite loop, waiting for one of the events to happen.

 

On the browser, we can connect to the server with a little bit of javascript:

 

var host = "ws://192.168.1.108:8888/ws";

var socket = new WebSocket(host);

 

socket.onopen = function() {

alert('Connection Opened');

}

 

socket.onmessage = function(msg) {

alert(‘Message Received’)

}

 

socket.onclose = function() {

alert('Connection Closed');

}

 

This code is fairly similar to the server code.  We start by specifying the location of the server and then we handle the various events that can happen: opening a new connection, receiving a message, and closing a connection.

 

Sending a message from the server is pretty easy (from within the WSHandler class):

 

self.write_message(‘message’)

 

Sending a message from the client is also really easy:

 

socket.send(‘message’);

 

Sending Song Choices

 

The first step is that we need to determine what songs are in our library.  To do this, we take in a path and then read all of the files in that directory and call that our list of songs:

 

class Song(object):

def __init__(self, path):

self.path = path

self.name = os.path.splitext(os.path.basename(path))[0]

 

class SongLibrary(object):

def __init__(self, path):

self.songs = {}

for file in os.listdir(path):

song = Song(path + '/' + file)

self.songs[song.name] = song

 

songLibrary = SongLibrary('/home/pi/Music')

 

Now we can randomly select 3 songs and send them out to the clients:

 

def set_choices(self, choices = 3):

self.votes = {}

self.voted = {}

                              

names = list(self.songs.keys())

while len(self.votes) < choices:

idx = random.randint(0, len(self.songs) - 1)

name = names[idx]

if not name in self.votes:

self.votes[name] = 0

                              

for client in self.clients:

client.send_songs()

 

Then on the client, we can receive and display those songs:

 

socket.onmessage = function(msg) {

var data = JSON.parse(msg.data);

                                                              

switch (data.type) {

case 'update':

displaySongs(data.songs);

break;

default:

displayHeader('Unknown result from server');

break;

}

}

 

function displaySongs(songs) {

displayHeader('Which song would you like to hear next?');

$.each(songs, function(idx, song) {

$('<button>' + song + '</button><br/>').click(function() { vote(song); }).appendTo('#info');

});

}

 

function displayHeader(header) {

$('#info').empty();

$('#header').html('<h1>' + header + '</h1>');

}

 

Which will look like this:

image

 

Voting for a Song

 

Next we need to handle when someone votes for a song.  To do this, we will add some javascript that will notify the server when the user clicks on one of the buttons:

 

function vote(song) {

displayHeader('You voted for: ' + song);

socket.send(song);

}

 

We already tied this into the click event of the button in the displaySongs method above.

 

Then on the server, we need to handle a client voting:

 

class WSHandler(tornado.websocket.WebSocketHandler):

def send_songs(self):

songs = ','.join(['"%s"' % song for song in self.library.get_choices()])

self.write_message('{ "type" : "update", "songs" : [ %s ] }' % songs)

 

def send_results(self):

results = ','.join(['{ "name" : "%s", "count" : "%s"}' % (name, count) for (name, count) in self.library.get_results()])

self.write_message('{ "type" : "vote", "results" : [ %s ] }' % results)

                              

def vote(self, song):

ip = self.request.remote_ip

response = self.library.vote(song, ip)

                              

if response:

self.send_error(response)

else:

self.send_results()

 

def on_message(self, msg):

self.vote(msg)

 

class SongLibrary (object):

def vote(self, song, ip):

if song in self.votes:

if ip in self.voted:

return 'You have already voted'

else:

self.voted[ip] = song

self.votes[song] += 1

 

return ""

else:

return 'Unknown song - %s' % song

 

def get_results(self):

return self.votes.items()

 

This will tally up the votes that are received from the client.  Also, it will send the current results to the client, so they can see how their favorite song is doing:image

 

Playing the Song

 

The last problem is actually playing the most popular song.  This is pretty easy to accomplish with the pygame library:

 

class SongLibrary(object):

def get_next_song(self):

return max(self.votes.iterkeys(), key=(lambda key: self.votes[key]))

              

def play_song(self, song):

print 'Playing: ' + song

 

pygame.mixer.music.load(song)

pygame.mixer.music.play()

 

while pygame.mixer.music.get_busy():

pygame.time.delay(100)

              

def main_loop(self):

pygame.init()

pygame.mixer.init()

self.set_choices()

                              

while 1:

song = self.get_next_song()

self.set_choices()

                                              

self.play_song(self.songs[song].path)

 

The full code is attached.

 

Summary

 

We created an automated DJ for our next party that allows the guests to vote on their favorite song and determine what is going to be played next.  The website can be accessed by any browser that supports web sockets.

Attachments:
vote.zip
  • Sign in to reply
  • Former Member
    Former Member over 9 years ago

    Ive been trying for quite a while to get this working but with no luck. The python file server.py is running and playing random songs perfectly but I cannot seem to get the html file and .js file running to allow one to vote?

    Any help much appreciated, thanks,

    James

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • oneleggedredcow
    oneleggedredcow over 10 years ago in reply to Former Member

    Probably should have added some more background.  My apologies.

     

    To install tornado:

     

    > sudo apt-get install python-pip

    > sudo pip install tornado

     

    Once that is installed, you should be able to run the python script.  While that script is running, go to another computer (or I guess you could do it on the Pi as well), and fire up a browser.  Navigate the browser to:

     

    <IP Address>/vote.html

     

    Where you can get the ip address of the Raspberry Pi by doing:

     

    > sudo ifconfig

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Former Member
    Former Member over 10 years ago

    Hey I have been trying the code that you have uploaded in the file and I have try t excute it in LMX terminal but its says for "vote.js" file

    File "vote.js", line 1

    $(document).ready(function()     {

    ^

    SyntaxError: invalid syntax

     

    and for the server.py it says

    File "server.py", line 1 in <module>

        import tornado.httpserver

    ImportError: No module named tornado.httpserver

     

     

    can you please help I would really like to try this

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • oneleggedredcow
    oneleggedredcow over 10 years ago in reply to Former Member

    Not that kind of a DJ.  More like a DJ at a wedding.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Former Member
    Former Member over 10 years ago

    What about for perfectly mixing the songs so the beats match.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube