JavaScript Audio Synthesis Part 2: Interactive Sound

Sep 28 2013

Send to Kindle

In yesterday’s post I covered the bare bones basics of creating audio with the Web Audio API. In this post, I’ll demonstrate one way to start creating some interactivity.

One of the simplest and most dynamic ways to capture interactivity on a computer is by simply reading the mouse position. The strategy for this next experiment is to use the mouse’s y-position to control the frequency of a single oscillator. The code for this is super simple:

window.onload = function() {

	var context = new window.webkitAudioContext(),
		osc = context.createOscillator(),
		h = window.innerHeight;

	osc.connect(context.destination);
	osc.start(0);

	document.addEventListener("mousemove", function(e) {
		osc.frequency.value = e.clientY / h * 1000 + 300;
	});
};
 

Create an AudioContext and an oscillator, get the window dimensions, connect and start the oscillator and listen for mousemove events.

In the mousemove handler, e.clientY / h will be a number from 0 to 1. Multiply this by 1000 and add 300 and you’ll have a frequency from 300 to 1300. This gets assigned to the oscillator’s frequency value. Move your mouse around the screen and get different pitches. Simple.

Remember, the above has only been tested in the latest version of Chrome at the time of this writing. Other configurations may work; some may require some changes.

Now what about they x-axis? Yesterday you had two oscillators going. Let’s try to hook the mouse’s x-position to that second oscillator.

window.onload = function() {

	var context = new window.webkitAudioContext(),
		osc = context.createOscillator(),
		osc2 = context.createOscillator(),
		gain = context.createGain(),
		w = window.innerWidth,
		h = window.innerHeight;

	osc.frequency = 400;

	osc.connect(context.destination);
	osc.start(0);

	gain.gain.value = 100;
	gain.connect(osc.frequency);

	osc2.frequency.value = 5;
	osc2.connect(gain);
	osc2.start(0);

	document.addEventListener("mousemove", function(e) {
		osc.frequency.value = e.clientY / h * 1000 + 200;
		osc2.frequency.value = e.clientX / w * 30 + 5;
	});
};
 

This is much the same as the final code from yesterday, but now you’re using the mouse x- and y-positions to control the frequencies of both oscillators. Move your mouse all over the screen now and you’ll get all kinds of science-fictiony sounds. I picture a 1950′s flying saucer taking off, or maybe an alien ray gun. Mess with the frequency ranges of both oscillators and try changing the oscillator types for both – mix and match square, sawtooth and triangle waves for all kinds of interesting results.

Send to Kindle

No responses yet

Audio Synthesis in JavaScript

Sep 27 2013

Send to Kindle

This is something I’ve wanted to play with for a long time. So the other day I buckled down and started searching around.

Yes, you can create sound in JavaScript. In some browsers. Supposedly, it works in Chrome 14, Firefox 23, Opera 15 and Safari 6. Not IE. But, I’ve only tested this in Chrome. So for now, consider this something experimental and fun to lay with, not for your super awesome works-in-every-browser game.

I found several sites that had build up complex libraries based on the Web Audio API. These weren’t the greatest things to learn the basics from, but I eventually was able to pare some of the code down to the bare minimum needed to create some sounds in the browser. There’s also the MDN documentation here: https://developer.mozilla.org/en-US/docs/Web_Audio_API, which is a great reference, but not a step-by-step tutorial for creating sounds. There are a few tutorials linked to from there as well, but none really covered what I was interested in.

So, to get down to it, let’s create some noise.

First you need to create an AudioContext object. This is similar in concept to HTML5′s 2D graphics context for canvas. The context is the overarching object that you’ll use to create all the pieces that will create the sound you’re going to make. For Webkit-based browsers, you get an AudioContext like so:


var context = 
    new window.webkitAudioContext();

The AudioContext has a few properties, the most important one being “destination”. The destination is basically the output of the context, where the sound goes. You can think of it as your speakers.

audiocontext

The next thing you need to know about the Web Audio API is that it is a node based system. You use the AudioContext to create various nodes that are used to create and shape sounds. Nodes have inputs and outputs that you can use to hook various nodes together into different configurations.

The most direct way to create a sound is to create an oscillator node. An oscillator node has zero inputs and one output. You can hook that output to the destination of your context. You’ll also need to specify a frequency for the oscillator. 440 hz will create the musical note, A. Here’s the code:

var context = new window.webkitAudioContext();

var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);
 

And here’s how this looks from a node view:

oscillator

Yeah, it says “frequency: 500″. My goof. Not changing it. Live with it.

You have an oscillator node with a frequency of 440 connected to the destination of the AudioContext. Call start(0) and you should get an annoying sound coming out of your speaker.

The oscillator node has a couple of other properties. One is “type”. This is the type of wave it uses to generate the sound. It defaults to “sine”. But, you can try “square”, “sawtooth” or “triangle” and see how they sound by doing this:

osc.type = "sawtooth";

There’s also a “custom” type, but that involves creating and setting a custom wave table. If you’re into it, go for it.

Anyway, wasn’t that easy? Let’s expand on it and create another oscillator that messes with the first one.

To do this, you’ll create two new nodes, an oscillator node and a gain node. A gain node is usually used to change the volume of a sound, but you’ll be using it here to alter the frequency of the original oscillator node. You’ll also create another, slower oscillator node. This new oscillator node’s output will be connected to the gain node. A gain node has a single input and a single output. As the new oscillator goes up and down at a frequency of 1 hz (once per second), it will affect the output of the gain node. A gain node also has a value property. If you set that to 100, then the gain node’s output will cycle from +100 to -100 as the new oscillator slowly cycles.

Now you need to hook this +/- 100 gain node output to the original oscillator. But remember that oscillator nodes don’t have any inputs, so you can’t connect it directly to the oscillator node. Instead, you connect it directly to the frequency property of the node. Now that gain output will change the original frequency of 440 hz + or – 100 hz as it cycles. A picture is worth several hundred words.

oscillator2

One oscillator is connected to the gain node, which is directly connected to the other oscillator’s frequency. That oscillator is connected to the destination. Here’s the code:

var context = new window.webkitAudioContext();

var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);

var gain = context.createGain();
gain.gain.value = 100;
gain.connect(osc.frequency);

var osc2 = context.createOscillator();
osc2.frequency.value = 1;
osc2.connect(gain);
osc2.start(0);

Run that and you should hear a siren like sound.

You can also change the type of the second oscillator. Try making that a square wave:

osc2.type = "square";

square

Now, instead of cycling smoothly from +100 to -100, the gain’s output will be exactly +100 for half the cycle than jump to exactly -100 for the second half. The result is more like a siren you’d hear in Europe or the UK. It also drives my dog crazy.

Anyway, that’s the bare minimum. Check out the API at the link mentioned previously. There’s a lot more you can do with it from here.

Send to Kindle

No responses yet

Playing With Chaos is Published!

Sep 20 2013

Send to Kindle

At long last, the book is available for sale. It took a few days to get through all the copy edits and then a few last minute tweaks, then I hit the big old publish button. A few hours later, it was live … except in the US, Japan, India and Canada. I’m not sure if there is just some lag in the system for certain countries. I contacted support, they said they’d look into it and I never heard back, but the book soon went live on the US and Canadian stores. As of this writing it’s still listed as unavailable for purchase in India and Japan. It may resolve itself, but I’ll keep pushing on it anyway.

As mentioned previously, the whole process was a great experience and feels like a big accomplishment to have pulled it off from inception to being in the store, all under my own steam.

Anyway, go get it if this is the kind of thing you’re interested in. I hope you enjoy it. If so, it would be really nice to start seeing some good reviews stacking up there. :)

Send to Kindle

5 responses so far

Playing With Chaos, August Update

Aug 22 2013

Send to Kindle

The book is done! Well, not done, done, as in out-the-door done. But I finished all the chapters and all the code and all the images. I’ve worked over every chapter 2-3 times myself and now the book is over to a team of tech reviewers and a professional copy editor. This will give the book the final polish in both the technical sense, making sure the explanations are correct and the code works, and also in a spelling/grammar/style sense, making me look more literate than I am. I’m already getting some great feedback from the reviewers, and while my ego always takes a huge hit at this stage of the game, it’s all going to mean a higher quality book that hits your hands. I’m hoping to wrap up this stage of things in the next couple of weeks and have the book ready on Kindle by mid-September.

I just wanted to make a quick comment on the activity of self-publishing. It’s been an amazing experience! I’ve written or co-written something like 12 books before this, which has been extremely helpful during the process of writing my own book. I have a pretty good idea how to structure things, what voice to use, the importance of consistency, how the various workflows go, etc. But doing the whole thing by myself … the analogy that comes to mind, though it may not make sense to you, is that it’s like the first time you go on a big trip by yourself. Not Disneyland with your parents, or those school or maybe even business trips, but the first time you decide you want to go somewhere, you choose where you’ll go, book the flight, book the hotel, rent the car, pay for everything, put it on the calendar, pack your own bags, make it out the door on time without forgetting anything vital, arrive at your destination, have fun, and make it back home alive. It’s all you, and there’s a sense of pride that you handled it all yourself. OK, to be honest, I still feel that way when I book a trip myself, but anyway…

That’s what this experience was like. I decided to write the book, came up with the subject, didn’t have to get approval from anyone at any stage of the process. Came up with an outline, started writing, came up with my own workflows, got my own reviewers and editor. When working for a publisher, as edits come in, I always felt like, “OK, whatever. They want it that way, we’ll do it that way.” Particularly in the late stage copy edits. I’d get a marked up manuscript with a bunch of corrections and some questions for clarification. I’d answer the questions and for the most part just blindly sign off on the rest of it. This time around, it’s so intimately my own creation that there’s a very different feeling that goes along with it. Any change I make that’s based on someone else’s advice is something I closely scrutinize. That’s not to say that I’m rejecting stuff outright, but I’m still 100% mentally involved in the process at this point and 100% focused, which is not always the case in the late stages of a publisher-controlled book.

Anyway, I guess it’s neither here nor there, but personally, it’s such a huge difference for me that I wanted to say something about it. At this point, I couldn’t imagine going back to a traditional publisher. Not that my experiences with them were bad – in particular, I always had a great time with the folks at Friends of ED – but being in charge of the process myself is so much better.

Send to Kindle

5 responses so far

Playing with Chaos – July Update

Jul 26 2013

Send to Kindle

Since my last post, I’ve been focusing almost all of my free time on writing this book. Mostly because I’m having so much fun writing it. I’ve finished a whopping six chapters since I last posted here. So yeah, it’s going pretty well. Here’s the current table of contents:

Chapter 1: Introduction
Chapter 2: What is a Fractal
Chapter 3: Symmetry and Regularity
Chapter 4: Fractal Dimensions
Chapter 5: Order from Chaos
Chapter 6: Diffusion-Limited Aggregation
Chapter 7: The Mandelbrot Set
Chapter 8: The Julia Set and Fatou Dust
Chapter 9: Strange Attractors
Chapter 10: L-Systems
Chapter 11: Cellular Automata
Chapter 12: Fractals in the Real World

I’m through Chapter 8 and heading into Chapter 9 now. Chapters 4 – 8 are first drafts, while 1 – 4 have been worked over a bit and are pretty close to final. I’d like to think I could be done with the writing by the end of August. Then another week or two for personal review and editing. After that I’ll need to have some other people review it and I’m considering how to handle copy editing – whether to hire someone or consider other alternatives.

One stroke of personal brilliance was that the utility library that is used in each example contains a method to pop out a bitmap image of the canvas that can be saved to disk. Built-in screenshots! So all the images for the book are easily created while I’m writing the text and code. Sometimes some cropping is needed, but I’ve got a good flow going for that as well. At this point, I’m up to 155 images. It’s a pretty graphics-heavy for a Kindle book, but I’ve been checking every image on a real Kindle and they all look decent.

If you want to get a feel for what’s coming, I’ve set up a site for the book at http://playingwithchaos.net. It’s got every image in the book, plus a video of the presentation I did at Beyond Tellerand/Play! that sparked my thoughts about writing this book.

Send to Kindle

2 responses so far

Playing With Chaos, revisited

Jun 30 2013

Send to Kindle

A little over a year ago, I announced that I would be writing a book about fractals, entitled “Playing With Chaos”, based on a few presentations I did that went over really well. I set about writing the book and got almost two chapters in before fizzling out. The problem with self publishing is that you don’t have an editor breathing down your throat, asking for the next chapter some time around the next deadline. Other things come up and before you know it, a year has gone by and you haven’t looked at the book.

Several people have asked me about the progress of the book in the past few months. I’m really grateful for your interest in the book and your faith in me. It’s kept the book from going too far into the back of my mind and being completely abandoned.

Recently, as you may have noticed, I’ve been getting more into hardware and electronics. I’ve also felt the urge to write again and started putting together an outline for a book on that subject. However, as I contemplated announcing my intentions, I felt like the boy who cried “book”. I couldn’t announce a new self-published book project while people are still apparently waiting for my last one. And so I dug up the project, dusted it off and took a look.

Usually, when you (or at least when I) revive a semi-abandoned, half-done project and look it over, it’s all too easy to say it’s all crap and you might as well start over. I opened up the files with that very expectation. But as I read through the first couple of chapters, I was really surprised. It was pretty solid stuff. I needed to finish up chapter 2 and fix up a few minor things in the text. The outline looked good and the code held up 100%. Throughout the course of Saturday, I finished up chapter 2 and began chapter 3.

The best news is that I’m really excited about the project again. I’m not even sure why I drifted away from it in the first place. It’s too soon to have a good time estimate, but I’d hope to be done by the end of the summer. Feel free to hound me on progress. I really want to get this done.

Send to Kindle

4 responses so far

Simple Arduino Motor Control

May 29 2013

Send to Kindle

WP_20130529_001

One thing you might want to do with an Arduino or even a Raspberry Pi is control a motor. Of course, the GPIO pins on this board are really just designed to send and receive informational signals, not drive the load of something that’s going to draw any significant current like a motor. An LED is fine, but much beyond that and you really need to look at a different solution.

I simply wanted to control a motor from my Arduino. I have a little hobby motor. I measured that at 3 volts it draws 150 mA (milliAmps). The Arduino’s GPIO pins are rated at around 40 mA. So that wasn’t going to cut it. I know there are various motor controller shields that you can hook up to your Arduino for this purpose, but I didn’t think I needed to go that route. Those boards offer a lot of functionality and are great if you have a specific project in mind and need all that control without going through the hassle of figuring out how to do it. But they are also the very definition of a “black box”. You put some input into them and get some input out of them. There’s all kinds of components and chips and traces on the boards, so you don’t really have any idea what’s going on between the input and output.

150 mA - too high for Arduino's GPIO

150 mA – too high for Arduino’s GPIO

For me, it was far more important to know exactly what was going on at this stage. So I grabbed a breadboard, some components and wire, and got busy.

All you really need is a transistor, a resistor and a separate power supply for the motor. I’m not going to go into a deep explanation of transistors, because there are about 73 million deep discussions about them on the net. Basically, it’s an electronic switch with three leads called the emitter, base, and collector. You put the emitter/collector combo between the external power and your load, in this case a motor. By default, it acts as an open switch, so the motor does not run. But when you supply a small current between the base and emitter, this “closes the switch”, allowing the current to flow from collector to emitter, and your motor runs!

The important thing is that it only takes a very small control signal at the base to allow a much larger current to flow through the emitter/collector. So you can use the GPIO output signals to control the transistor, and use a separate power supply to control the motor itself without taxing your delicate little Arduino.

WP_20130529_002

The transistor I used is a PN2222 series. These are very common, general use transistors. You can get 10 of them for under $2. I checked the data sheet for this transistor and found it can handle a maximum of around 50-60 volts on the emitter/collector. (There are a few different varieties of these, so I’m just reporting averages.) So my 3 volt motor should be fine. It can also handle a peak load of 1 amp – again fine for my 150 mA motor. Motors do draw a lot more current when the first start, but this would allow me more than 6x the running current as a peak. The base/emitter voltage is around 5-6 volts max. The Arduino outputs are 5 volts, which is cutting it close, so I threw in a 1000 ohm resistor. This results in just a few milliamps being drawn from the GPIO pin, through the base of the transistor and back out the emitter.

motorcontrol

motorcontrol_bb

Then I hooked up the motor to a separate 3 volt power supply, passing it through the emitter/collector. With this setup, when the GPIO pin I choose is HIGH, the motor will run. When it’s LOW, the motor will stop. Despite the motor drawing at least 150 mA, the Arduino’s GPIO pins will only be serving up 2-3 mA about 4 mA by actual measurement – way below the 40 mA limit.

For software, I set up a simple sketch as follows:

void setup() {
    pinMode(7, OUTPUT);
}

void loop() {
    digitalWrite(7, HIGH);
    delay(1000);
    digitalWrite(7, LOW);
    delay(1000);
}

Obviously, I’m using GPIO pin 7 as an output. This will set it HIGH for one second, then low for one second, switching the motor on and off for that amount of time. And it works! And as far as I can tell, everything is within safe ranges.

So there you go. Of course, this isn’t going to give you all the features of a dedicated motor control shield, such as variable speed with pulse with modulation, multiple motors, forward/reverse, etc. But now you know exactly what’s going on and can build on it if you want. Or at least have some concept on what’s going on inside that fancy shield.

Of course, it goes without saying to be VERY careful when wiring up a circuit like this. You are hooking up an external power source to the same board that your Arduino is hooked up to. A wrong move and you could send electrons flooding into where they have no business being. That’s another advantage to using shields, which buffer the Arduino’s connections and add a layer of protection. But don’t worry too much. A little smoke won’t kill you. :)

WP_20130529_004

Send to Kindle

4 responses so far

Pull-up and Pull-down Resistors

May 22 2013

Send to Kindle

Working a lot with Raspberry Pi and Arduino stuff lately. The concept of pull-up and pull-down resistors came up quickly and confused me a little at first. So I thought I’d do a little demo of how they work and why they are needed. Doing this helped to clarify it for me, so maybe it’ll help you too.

Common scenario. You want to set up something that reads an input of a GPIO pin. Say, you want to know when the user is pressing a switch. You set up a simple circuit like so:

circuit_1

And here that is wired up:

WP_20130523_002

When you press the button, pin 25 goes high. No press, no high, must be low, right? Well, let’s see…

We’ll set up a simple Python script to read the status of pin 25:

#! /usr/bin/python

import RPi.GPIO as GPIO
import time

PIN = 25

GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.IN)

while True:
        if GPIO.input(PIN) == GPIO.HIGH:
                print("pin is high")
                time.sleep(.1)
        else:
                print("pin is low")
                time.sleep(.1)

When I run this, I get 20-30 lines saying pin 25 is high, then 20-30 saying it’s low, back and forth, without touching the button. Sure enough when I press the button, it stays high, but apparently the definition of “low” is not “not high”.

After too many years in the highly binary world of software programming, some of us delving into hardware may be surprised to learn that a lot of electronics operate on “tri-state logic” as opposed to simple binary. Here, an input can be high, low, or floating. In this particular circuit, high means connected to 3.3 volts, low means connected to ground, and floating means… neither or somewhere in between. Actually, due to the sensitive nature of tiny electronics, system components can pick up various signals that create slight fluctuations in what it is reading. It’s rarely if ever going to pick up exactly 0.000 volts just because it’s not connected to 3.3 volts.

So we need to force the issue and say, “Yo! You are LOW!” My first thought on how to do this would probably have been to do something like this:

circuit_2

When the switch is in one position, pin 25 is connected directly to ground, sending it solidly low. When the switch is changed, it connects 25 to 3.3 volts, making it high. This will work just fine, but it’s a bit overengineered as it turns out.

How about if we go simpler and just connect pin 25 to ground and leave it that way, like so:

(Note: DO NOT ACTUALLY BUILD THIS CIRCUIT!)

circuit_3

Now, when the switch is open, pin 25 is undoubtedly low. But we have a problem that when you do hit the switch, you now have a short circuit directly between 3.3 volts and ground. Not good. Again, do not do this. The solution? Throw a resistor in there:

circuit_4

And in the real world:

WP_20130523_003

Now, when the switch is open, pin 25 is connected to ground through the 10K resistor. Even with the resistor though, it’s enough of a connection to make it solidly low. It’s not going to fluctuate.

Then we hit the switch, connecting the lower part of the circuit to the 3.3 volts. Because we have a fairly high resistance there, most of the current is going to go to pin 25, sending it solidly high. Some of it is also going to go to ground via R1. But Ohm’s Law tells us that 3.3 volts divided by 10,000 ohms will let about 0.33 milliamps in. That’s not going to break the bank.

So in this circuit, R1 is called a pull-down resistor because in its default state it pulls the signal down to 0 volts or a low state.

Now let’s swap things around a bit:

circuit_5

Now pin 25 is hard-wired to 3.3 volts through R1, making its default state high. However when the button is pressed, pin 25 will be directly connected to ground, sending it low. Because the resistor pulls pin 25 up to 3.3 volts and a high state, it’s now known as a pull-up resistor.

So, which one do you use? It depends on whether you want your default signal to be high or low.

Hope that helps.

Send to Kindle

11 responses so far

Raspberry Pi Mail Checker

May 21 2013

Send to Kindle

WP_20130521_001

I was looking for some Raspberry Pi project to do that not only used external hardware (even if that means only an LED for now), but also reached out into the net to deal with some kind of real time data. I ran into this tutorial on adafruit about checking your gmail with a Pi and lighting up an LED based on whether or not you have new mail. This was along the lines of what I wanted to do, but had two drawbacks. One, I don’t use gmail anymore, and two, it uses a python library called feedparser, which is actually an RSS parser. It only works because apparently you can access your gmail as an RSS feed or something. I wanted to do the same thing, but with any email service that supports, say, IMAP4.

A bit of digging around and I found that Python has an imaplib library that can directly access any IMAP4 based 12mail account. This is included by default in the Python distro that comes with Raspbian. So no further setup there. It took a bit of fiddling around with the docs, both of the library itself and the IMAP4 specs, but I figured out the basic sequence.

The library docs are here: http://pymotw.com/2/imaplib/

And the IMAP4 spec is here: http://tools.ietf.org/html/rfc3501.html

First, you create an IMAP object with one of the following lines, depending whether you need SSL or not. My server does need it.

imap = imaplib.IMAP4(server, port)

or

imap = imaplib.IMAP4_SSL(server, port)

Then, you log in:

imap.login(user, password)

You then need to go into select mode to select IMAP folders and messages.

imap.select()

Then you can do a search. By default, you’ll be searching in your inbox, but there are methods to change folders as well. Search criteria are pretty powerful, but I just wanted to see how many unread messages I have. This does that:

type, data = imap.search(None, "UNSEEN")

The first parameter is the encoding. Using None will return messages with any encoding. Second param is the search criteria. See the IMAP4 spec linked above for a comprehensive list on what you can search for.

This will return a type, data tuple of strings. The type will be “OK” or “NO” depending on success of the call. Note, even if it returns no unread messages, you’ll still get “OK” here, with an empty string in the data.

The data will be an list of strings. Actually, it seems to generally be an list containing a single string. This string is a space delimited list of numbers. These numbers are ids of the messages returned by the search. It’ll be something like this: “1 2 3 4 5″.

You can split this into a list of individual ids like so:

messages = data[0].split()

And the length of this list tells you how many messages the search returned. Zero means no new mail. One or more and you have new mail! Fire up an LED!

Here’s the full program I wrote:

#! /usr/bin/python

import imaplib, time
import RPi.GPIO as GPIO

GREEN_PIN = 25
RED_PIN = 24

class MailChecker:
	def __init__(self, server, port):
		GPIO.setmode(GPIO.BCM)
		GPIO.setup(GREEN_PIN, GPIO.OUT)
		GPIO.setup(RED_PIN, GPIO.OUT)
		GPIO.setwarnings(False)

		try:
			self.m = imaplib.IMAP4_SSL(server, port)
		except:
			self.do_error("Unable to contact server")

	def do_error(self, error):
		# maybe flash another error LED
		print(error)
		exit()


	def log_in(self, user, password):
		try:
			self.m.login(user, password)
		except:
			self.do_error("Unable to log in")

	def check_mail(self):
		type, data = 0, 0
		try:
			self.m.select()
			type, data = self.m.search(None, "UNSEEN")
		except:
			self.do_error("Unable to check messages")

		if type == "NO":
			self.do_error("Problem checking messages")

		self.report(data)

	def start_checking(self, interval):
		while True:
			self.check_mail()
			time.sleep(interval)

	def report(self, data):
		message_count = len(data[0].split())
		if message_count > 0:
			print("You've got %i new messages" %
			message_count)
			GPIO.output(RED_PIN, GPIO.LOW)
			for i in range(1, 100):
        			GPIO.output(GREEN_PIN, GPIO.LOW)
        			time.sleep(.2)
        			GPIO.output(GREEN_PIN, GPIO.HIGH)
        			time.sleep(.2)
		else:
			print("No new mail right now")
			GPIO.output(GREEN_PIN, GPIO.LOW)
			GPIO.output(RED_PIN, GPIO.HIGH)

if __name__ == "__main__":
	user = "your_user_name"
	password = "your_password"
	server = "your_email_server_url"
	port = 993 
	# or whatever port you need to use

	checker = MailChecker(server, port)
	checker.log_in(user, password)
	checker.start_checking(60)

This creates the IMAP object and logs in. Then the start_checking method sets up an infinite loop that searches once every minute. If it finds there are unread messages, it blinks a green LED a bunch of times then leaves it on. No new mail, red LED. The rest is basic GPIO code.

You can change the behavior however you want, maybe remove all the non-error print lines. Then move it to your Pi, do a chmod +x on it to make it executable and run it as root:

sudo ./checkmail.py &

The trailing & character will fork the process and allow you to close the terminal session while keeping the program running – especially useful if you’re sshing into your Pi.

Send to Kindle

No responses yet

The Ridiculous Raspberry Pi Winamp Remote – Part II

May 14 2013

Send to Kindle

Recap

As stated in my previous post, the plan was to hit a button that’s connected to my Raspberry Pi, which will trigger Winamp running on my pc laptop to play/pause. This without the Pi being physically connected to the pc – all via wifi and my local home network.

The hardware setup

Raspberry Pi with USB wifi, a small breadboard, 100k ohm resistor, a pushbutton and some hookup wire.

GPIO pin 25 goes to one side of the switch, 3.3 volts to the other. You hit the switch, pin 25 gets juice and goes HIGH. The 100k ohm resistor is also hooked to pin 25 on one side and ground on the other, connecting 25 to ground when the switch is not connected, ensuring it is in a LOW state. For those of you in the know, this is a basic pull down resistor. If you’re not familiar with the concept, as I was not last week, this is a good explanation: http://www.resistorguide.com/pull-up-resistor_pull-down-resistor/

The Python

The Raspberry Pi is running a simple program written in Python:

import urllib
import RPi.GPIO as GPIO
import time

BTN = 25
GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN, GPIO.IN)


while True:
        val = GPIO.input(BTN)
        if val == GPIO.HIGH:
                urllib.urlopen("http://192.168.1.14:9000")
                time.sleep(1)

This just sets up pin 25 as an input and starts an endless loop which reads the value of pin 25. If it’s high, it pings a url and sleeps for a second. The sleep is so you don’t get multiple calls at once. There are more robust ways of handling this, but this was quick and dirty and works as long as I’m the only user and I know not to hold the button down too long.

So what is this url?

The Node

On my laptop where Winamp is playing, I started a simple node server. When a client connects to the server, it calls a function called playPause. This executes an external program called MediaControllerConsole.exe via child_process.

function playPause() {
	var path = "MediaControllerConsole.exe";

	var exec = require('child_process').exec;
	var child = exec(path, function( error, stdout, stderr) 
	{
	   if ( error != null ) {
	        console.log("err: " + stderr);
	        // error handling & exit
	   }
	});
}

var net = require("net");
var server = net.createServer();
server.on("connection", function(client) {
	playPause();
	client.end();
});

server.listen(9000);

So what is MediaControllerConsole.exe?

The C#

I had the connection from the Pi to my laptop. Now I needed Node to control Winamp. There may be some way to do this more directly, but I found that I could write a really simple C# console application that called SendKeys.Send() to trigger key presses on the machine. I looked in Winamp’s options and saw that CTRL-ALT-HOME is a global keyboard shortcut to Winamp’s pause function. It turns out that this actually acts as a play/pause toggle, which is even more perfect for my use case. Here’s the C# app I wrote:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MediaControllerConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Windows.Forms.SendKeys.SendWait("^%{HOME}");
        }
    }
}

Since this was a console app and not a Windows Forms app, I had to add system.windows.forms.dll as a reference to the Visual Studio project and call SendWait instead of Send (which has more hooks into the forms stuff). The string “^%{HOME}” means that while holding the CTRL key (^) and the ALT key (%), press the HOME key.

Final recap

Pressing the button connected to the Pi sends pin 25 to HIGH which triggers Python to call across the wifi network to the Node server which starts a child process running the C# program which sends keystrokes into the system which Winamp is listening for, causing it to play or pause. All so I don’t have to reach over and press two keys.

Ridiculous! But it works!

Send to Kindle

3 responses so far

« Newer posts Older posts »