RSpec.should be_easier

June 27th, 2009

In my last contract role, I encountered the ruby-based RSpec testing framework for the first time. For those who haven’t looked into it yet, it provides a testing framework for unit, functional, integration and view tests, using a nearly plain English style of test definitions. The title of this blog entry borrows from the typical usage: rather than writing assertions, as with traditional testing frameworks, RSpec steers towards specific expectations for methods, such as

response.should have_tag(div)

As far as I can tell, this code is rather like a wrapper around assert statements and spec tests inherit from the Test::Unit class, allowing traditional assert statements in tests. However, to follow the fanatic principles of BDD (Behavioural Driven Development), we should write tests using the RSpec format.

Why Test-Driven?

I’m a Java developer to begin with. I was drawn into the world of Rails because I was impressed with the ease of obtaining a working website in moments: the scaffold. I liked the fact that you didn’t need to know in advance every little detail about your system, because it was easy to change things afterwards. I liked the fact you could alter the code, press a refresh button on your browser, and instantly see your changes (you can’t do that with servlets, you have to re-start the container). This approach, known as agile programming, depends on this ease of changing your mind after you’ve built something. Writing tests is a very important part of agile programming, because tests are what tell us when we inadvertantly break something when making these ‘agile’ changes. Eventually, someone pointed out that the most correct way of programming therefore was starting with your test, and then implementing the code. That practice is undeniably the best way forward, but it tends to a pedantic style of Rails programming; the idea that there is a ‘correct’ way of testing that we ’should’ adopt.

With TDD, it feels like I’ve lost a little bit of that nice, agile approach, for in order to write the test for some code I need to know what the code does first, rather like a return to up-front designs. That’s OK- because I ought to know enough about what I want to write anyway: but in practice I’m never going to write tests in advance for anything that Rails generates. I’m probably only going to test things that I wrote, which are over a few lines of code long. In RSpec, I can write tests that check for elements of a certain ID or CSS class: I’d much rather create the page first and then test it afterwards: otherwise I have to decide these things in advance: rather than being able to change my mind easily afterward.

When deadlines are tight, or there isn’t some test manager watching you, tests are the first thing to go, because programmers don’t like writing tests, and writing tests is not as expressive or as fun as working with the real code and seeing it work in the browser.

But then comes along a crowd talking about BDD: behavourial-driven development.

Not TDD; We Need BDD: Behavioural-Driven Development

I’ve tried to see a practical different between TDD and BDD, but its essentially the same idea: writing tests against your code, ideally before you start. If you know the difference, please tell me. For someone or the other, the difference was so profound that another test framework was needed seperate from the Rails test framework: RSpec.

RSpec (and BDD) move away from assertion-led tests such as

assert_equal 50, my_variable

to a programming syntax that is closer to English, focussing on the expectation of that code:

my_variable.should == 50

If I had to say which was easier to read: I’d probably say that the RSpec version is marginally easier; but as I programmer I can read both and I’m used to the first one. Rather than writing real code and adding value to the project, I’m fishing around the appaulingly-designed RSpec website, looking for documentation on how to write something equivalent to a test I could have otherwise written in a few seconds.

The test definition is also different, allowing arbitary phrases as part of the test block, to try and be more readable:

it 'should complete the order and then deliver an e-mail' do

Inevitably, all of this plain-English code, while a nice idea, makes the tests verbose and longer to type. If I change the test expectation, I have to change the definition too, if I want to keep it accurate. Yet I don’t really see what benefit it brings: non-technical people are never going to read it, and apart from sticking in fancy HTML reports, again which no-one will read, the programmer is doing extra typing for no return.

Should Do More Work!

RSpec doesn’t just provide changes in syntax. The BDD crowd deem the rails functional test inadequate, for it invokes both controller and view code in order to create the response. From my perspective, the rails approach is just fine: I want to know that when you are routed to a controller action, that action runs successfully, things happen in the database and something is rendered down to the client. BDD says we’re skimping off work doing that; we should test controllers and views seperately. That is, your view should work even if your controller doesn’t and vice versa. Once you know you have a working view and a working controller, you can run integration tests to make sure they work together. However, I think this is overkill. If I can see my view working in a browser, and the test says that under this or that circumstance I get a HTTP 200, 404 or 500, I’m done. I’m never going to switch database engines or run my controllers separately from my views.

Furthermore, RSpec introduces mock objects to abstract-away from the database. As test concepts go, I’ve looked at several frameworks for mocking objects and the concept just seems crazy to me. If I’m writing a database-driven website, why do I want to abstract away from the database? Its database-driven! Why write complex, badly-documented, boring code that isn’t the actual thing? Its doubling the work, and is probably not worth it. If you’re getting a nice daily rate to write this stuff, fine; but I wouldn’t bother with it on my projects, and I can’t see how it delivers business value in the long-term.

Should be_easier

All of these opinions come back to this point: that test code should support the development process, not supplant nor hinder it. All the time spent on writing mocks, seperate tests, getting code coverage up to 100% has its value, but it certainly has a diminishing return. The first few tests that are written, covering the critical part of the codebase, are the most valuable and the easiest to do. Debugging a view test when you can see it working fine in the browser is frustrating and unhelpful.

I think my dislike also stems from the word ’should’; an interesting word, meaning something that isn’t, but we want or expect. Everywhere we say ‘it should be this way’, we implicity say ‘it should be this way, but it is not that way’. For example, how many records will be in the database after some action? It should be 5- so let’s assert that we have 5. As a friend of mine is fond of saying, “a should is a shit”, I’d rather assert something than bang on about what ought to be this and what ought to be that.

Thoughts on Freelancing in Brighton and London

May 18th, 2009

Hunting around for a Ruby on Rails contract in the current economic climate has proved quite a trial. Even with four years web development experience, a degree in Computer Science from a top University and some on-line case studies, I looked for about ten weeks before finally landing a contract. I’m working on a large project with a major retail client, bringing in Ruby on Rails expertise to a department new to the technology. As it happens, I have now have two contracts on the go, which proves that the freelance / contract lifestyle is very unpredictable, and probably wouldn’t suit everyone.

The project was on and off for about a month. In the current environment, clients are jittery; shopping around for cheaper deals and able to hold-on for more experienced developers. In the end, a bit of perseverance, a rate-cut and an offer to try-out for a day was what secured the deal.

During the drought, I had been considered for about five Ruby on Rails contracts, all of which fell-through. In hindsight, I’m sure I was pitching in a bit too high: the guys I was standing against in interviews were consultants who ran their own Ruby on Rails companies; and everyone is feeling the pinch. I wonder whether many I.T. workers actually receive the remuneration that ithotjobs.co.uk says they should, but its still high and there are some innovative projects out there.

In the meantime, I spent some time on my entrepreneurial music project, in which I worked on a method of collaborative image manipulation for use on album cover art. I tried a co-working space, and spent a few days at the Skiff in Brighton.

For those who haven’t tried, or are considering trying a co-working environment, I shall relate some of my experiences. The Skiff is a little office in the middle of the North Laine area in Brighton, the part with all the funky shops that looks a little bit like Camden highstreet. It used to be the offices of Linden Labs, the creators of Second Life, but now houses a flux of freelancers, consultants and developers, most of whom are working on a freelance basis. It is adorned with bright IKEA furniture, beanbags and reeks of geek. Before the end of my first day I was persuaded into obtaining a Twitter account, and now a score of followers know that I’m on my way home.

The friendly and open atmosphere is positive. I’m meeting and greeting, sitting in on frivolous free workshops and even getting a little work done. Every time I return, some new innovation is attempted. Wipe-clean wallpaper, the ambient background noise of the Star Trek enterprise on speaker (which is noisy) and the various relationships you can be: a crew-member, a mate.

I paid a pricey £150+VAT for the privilege of a desk that I could visit up to some limit; imagining that I would spend a great deal of time there procuring new contracts. In the end, I had a near-miss (one of the five) due to the client opting for another agency, and a pack of Moo cards. Not bad for one week, but perhaps still an unproven concept. Its the sort of thing I think you have to try yourself to see whether it benefits or not.
My experience overall having been six months working for myself is that contracting is not easy. The importance of networking, building up a list of contacts and being visible on the Internet are vital. In hindsight, I hadn’t expected to invest so much effort in finding contracts; and its a constant activity. If its updating the C.V., to uploading it to the various job sites, responding to job alerts or talking to the I’m-your-new-best-friend recruitment agent: its not the creative or logical task I want to be doing.

So why am I doing it? Ultimate flexibility. I am organising an audition this weekend for a singer, to find musicians to collaborate with on a music project. I spent awhile recently preparing for it, and it couldn’t have happened if I was on a permanent job. Working for myself somehow gives me the feeling, even if it might be only an illusion, that I am steering my own ship, and that feels right compared to being a crewman on someone else’s. Fortunately, I don’t have any commitments or depdendents, which would change things; and I’m not in debt (apart from my student loan). It’s refreshing to work for a professional agency, with competent people, and not having to be involved in the politics nor the wranglings over the trivial details of projects. With contracting, its like a gig: I turn-up, perform, go home. With a permanent job, you inevitably get caught up in notions of careerism: having an influence or a legacy.

I can say that one big mistake that I’ve made in the past is allowing the concept of independence to cause the grave error that you can do everything by yourself. One of the reasons why I haven’t actually launched my music subscriptions website is that I have been director, developer and artist. To put only one hand on something isn’t wise and doesn’t usually lead to results. Whether its their parents or a major hedge fund, the people who seem to truly succeed are those who have some kind of backing. With contracting, I’m temporarily joining a group of people who collaborate with one another. With co-working, I’m immersed in an environment of like-minded people, like a support-group. On my music and entrepreneurial projects, I have been too solitary: my hope is that stemming from contracting, free-lancing and co-working, there will be the right people to finish the job.

I wonder whether any other freelancers have similar experiences and perspectives? Anyway, off to bed because I’ve got to get up in the morning.

Conic Bellophone in X3D, Part Two

April 8th, 2009

I reached the second milestone of my project to create a virtual reality model of the Conic Bellophone, an instrument comprised of 144 cone-shaped bells being developed for a PhD project. Moving on from the early prototype, which has six bells, I have managed to complete a version that has 144 bells, creating a ghostly harmonic when played.

Wide shot of Conic Bellophone in Xj3D

Wide shot of Conic Bellophone in Xj3D

The first challenge was dealing with the size and complexity of the model. I was supplied VRML97 exported from CATIA, describing a much more complicated and detailed model. In this model, the author had gone to the detail of individual screws, brackets, stands and bells, and rather than defining the geometry as primitive shapes, the exporter program naively creates large numbers of IndexedFaceSets; defining each point on a plane individually. Consequently, the supplied VRML97 was about 15MB in size, some 40,000 lines of code. This instantly presented problems with the tools I was using; Netbeans would regularly crash and the load-up time was taking about 4-5 minutes, even on my MacBook. At any rate, to deliver such a file on the web would be useless. So my first task, before I could really begin, was to reduce the filesize of the model. To accomplish this, I had to first depart from the arcane VRML97 format and into X3D, an XML version of VMRL that I could work with.

I noticed from inspecting the file that the exporter had introduced a large number of seemingly useless group nodes, such as:

<Group>
  <Group>
    <Group>
      <Group USE="somegroup">
        ...
      </Group>
    </Group>
  </Group>
</Group>

I decided to remove them with a simple parser written in Java. I created an application that read in the XML file, performed a recursive operation to remove the nodes and write out the result.

private void deleteUseless(Node n)
{
     Node parent = n.getParentNode();

     NodeList children = n.getChildNodes();
     for(int p = 0; p < children.getLength(); p++)
     {
       Node child = children.item(p);

       if(!child.getNodeName().equals("#text"))
       {
         deleteUseless(child);
       }
     }

     if(n.getNodeName().equals("Group")
             && n.getAttributes().getNamedItem("USE") == null
             && n.getAttributes().getNamedItem("DEF") == null)
     {
       for(int p = 0; p < children.getLength(); p++)
       {
         Node child = children.item(p);
         if(!child.getNodeName().equals("#text"))
         {
             parent.insertBefore(child, parent.getFirstChild());
         }
       }
       parent.removeChild(n);
       replacecount++;
     }
}

This method removed 2,500 unnecessary nodes. This still wasn’t enough to make the scene workable, so I began to simplify the scene by replacing IndexedFaceSets with primitive geometry.

The most important element in the scene were the bells themselves. I created a new node to represent a bell, that would be scaled to the desired size and re-used multiple times. In X3D jargon, this new node is called a prototype. A prototype defines a new node, and has its own scope for ROUTEs and DEFs. A prototype can be parametrised by defining a number of fields, which permit re-use, towards a component-based method of building complex scenes.

At this stage each bell had three requirements, other than rendering the bell in 3D. Firstly, the bell had to sound when clicked, as if the bell were stuck in real-life. Secondly, the bell had to change colour when clicked, to visualise what parts of the instrument were playing. Thirdly, the bell had to be able to play when the mouse was hovering over the bell, so that a run of bells could be played in a glissando effect. The behaviour between a single-bell sound and a glissando would be toggled by pressing the ‘G’ key on the keyboard.

Single sound of AudioClip

The first requirement is the most straightforward to implement. It is a text-book use of the TouchSensor node, along with a Sound and AudioClip node. Keeping all the nodes grouped together, it is important that the TouchSensor is a sibling of the grouping node of the geometry, for the TouchSensor acts upon the child nodes of its parent. Thus:

<Group>
  <TouchSensor />
  <Sound>
    <AudioClip />
  </Sound>

  <!-- Geometry -->
  <Shape>
    ...
  </Shape>
</Group>

The AudioClip defines the sound to play with its url parameter. X3D allows multiple URLs to be specified, to allow for local and remote access. ROUTEs are used to implement the sound behaviour:

<ROUTE fromNode="singleTouch" fromField="touchTime" toNode="chime" toField="stopTime"/>
<ROUTE fromNode="singleTouch" fromField="touchTime" toNode="chime" toField="startTime"/>

N.B. I include both stopTime and startTime as I had desired the bell-sound to restart when clicked again, much like a bell would if hit successive times. According to the X3D specification, passing the same time event for the stop and the start should result in the audio clip restarting. However I found mixed results with this, and mostly I see start/stop behaviour instead.

Colour Highlight with ColorInterpolator

Like all complicated concepts, using interpolators in X3D is straightforward once you understand it. I wanted to choose a colour for the bell’s material, which would change like a roll-over in CSS. In X3D, its easier to consider the problem as charting the node’s material to pass through a series of colour values, which is precisely what ColorInterpolator does. In this sense its more akin to a robot walking between waypoints than a roll-over paradigm.

An interpolator (or the similar sequencer nodes) have two main variables. The key, which defines the points in the series, and the keyValue, which define the corresponding values at those points. The key is always between 0 and 1, representing the start and end of the cycle, with any number of fractions in between, seperated by whitespace. For my roll-over I defined 0, 0.5 and 1, so that I can pass through three colours, finally returning to the original colour at the end of the cycle. For the corresponding values, in this case a colour, I would need three-pairs of RGB values to correspond to the colours at 0, 0.5 and 1.

In order to cause succession between the points, in X3D a TimeSensor is used to generate time events, so that the browser moves through the series, like a sequencer. When used alongside the touchsensor, these nodes can now be routed to achieve the roll-over effect.

<TimeSensor DEF="colourTimer" />
<ColorInterpolator DEF="flash" key="0 0.5 1" keyValue="0 1 0 1 1 1 0.8 0.8 0.8"/>
<TouchSensor DEF="glissTouch" enabled="false">

<ROUTE fromField='touchTime' fromNode='singleTouch' toField='set_startTime' toNode='colourTimer'/>
<ROUTE fromField='fraction_changed' fromNode='colourTimer' toField='set_fraction' toNode='flash'/>
<ROUTE fromField='value_changed' fromNode='flash' toField='set_diffuseColor' toNode='material'/>

Glissando effect with AudioClip

The best result of the model was the glissando, simultaneously playing several samples of micro-tonal bells, creating a haunting and harmonic sound when the mouse cursor passes over a bell. This effect was a slight change from the single-touch, using a different field to drive the behaviour. touchTime would be too late; for this is the time value when the touch sensor’s geometry was clicked. Instead, TouchSensor provides an isOver event, which is set to true when the mouse cursor intersects the geometry. As I required a time value rather than a boolean value, I needed another node to convert the values, called TimeTrigger. TimeTrigger is an invisible node that acts like a black-box; accepting a boolean input and returning a timestamp output, triggerTime. I used this to route between the TouchSensor and the AudioClip to obtain the glissando effect, and could even use this to drive the colour flash.

<ROUTE fromNode="glissTouch" fromField="isOver" toNode="gliss" toField="set_boolean" />
<ROUTE fromNode="gliss" fromField="triggerTime" toNode="chime" toField="set_startTime" />
<ROUTE fromField='triggerTime' fromNode='gliss' toField='set_startTime' toNode='colourTimer'/>

Toggle play mode with keyboard button press

Finally, I needed to switch between glissando and the single-click modes by pressing a keyboard key. To keep the behaviours seperate, I defined two seperate TouchSensors, each routed differently to achieve the different behaviours. I defined the TouchSensor associated with the glissando effect to be disabled, with the enabled=”false” attribute on the touch sensor. The process of toggling thus became an alternation of the enabled attribute of the TouchSensor. The current state of the toggle is stored using a BooleanToggle node.

The browser picks up keyboard events when you define a KeySensor within your scene. The KeySensor can then be routed to a script node, for processing. Below I wrote a short script to detect whether the letter ‘G’ had been pressed, and routed the result to the touch sensor.

<KeySensor DEF="glissMode" />
<BooleanToggle DEF="playMode" />

<Script DEF="logic" directOutput="true">
  <field name='keyInput' type='SFString' accessType='inputOnly'/>
  <field name='toggleGliss' type='SFBool' accessType='outputOnly'/>
  <![CDATA[ecmascript:
  function keyInput (inputValue)
  {
    if(inputValue == 'g' || inputValue == 'G')
    {
      toggleGliss = true;
    }
  }
  ]]>
</Script>

<ROUTE fromNode="logic" fromField="toggleGliss" toNode="playMode" toField="set_boolean" />
<ROUTE fromNode='glissMode' fromField='keyPress' toNode='logic' toField='keyInput'/>
<ROUTE fromNode="playMode" fromField="toggle_changed" toNode="glissTouchSensor" toField="enabled" />

Putting it all together

Now I could define a prototype and re-use the bell logic and geometry. I would embed each prototype inside a transform element, so that I could scale and translate each individually. The only alteration I needed to make was with the button toggle; for the state of the toggle had to be held within the main scene, not within each prototype, because each prototype has its own scope. I modified the prototype to accept the boolean value of the BooleanToggle as a field, as well as the URL for the sound to play.

<ProtoDeclare name='Bell'>
  <ProtoInterface>
    <field accessType='initializeOnly' name='soundURL' type='MFString' />
    <field accessType='inputOnly' name='playMode' type='SFBool'/>
  </ProtoInterface>
  <ProtoBody>
    <Group DEF="BellMain">
      <TimeSensor DEF="colourTimer" />
      <ColorInterpolator DEF="flash" key="0 0.5 1" keyValue="0 1 0 1 1 1 0.8 0.8 0.8"/>
      <TouchSensor DEF="glissTouch" enabled="false">
        <IS>
          <connect nodeField='enabled' protoField='playMode'/>
        </IS>
      </TouchSensor>
      <TouchSensor DEF="singleTouch" />
      <TimeTrigger DEF="gliss" />
      <Sound maxFront="100000" maxBack="100000">
        <AudioClip DEF="chime">
          <IS>
            <connect nodeField='url' protoField='soundURL'/>
          </IS>
        </AudioClip>
      </Sound>

      <!-- Bell Geometry -->

     <BooleanToggle DEF="playMode">
       <IS>
         <connect nodeField='set_boolean' protoField='playMode'/>
       </IS>
     </BooleanToggle>

     <!-- Single-touch sound -->
     <ROUTE fromNode="singleTouch" fromField="touchTime" toNode="chime" toField="stopTime"/>
     <ROUTE fromNode="singleTouch" fromField="touchTime" toNode="chime" toField="startTime"/>

     <!-- Glissando -->
     <ROUTE fromNode="glissTouch" fromField="isOver" toNode="gliss" toField="set_boolean" />
     <ROUTE fromNode="gliss" fromField="triggerTime" toNode="chime" toField="set_startTime" />
     <ROUTE fromField='triggerTime' fromNode='gliss' toField='set_startTime' toNode='colourTimer'/>

     <!-- Colour flash -->
     <ROUTE fromField='touchTime' fromNode='singleTouch' toField='set_startTime' toNode='colourTimer'/>
     <ROUTE fromField='fraction_changed' fromNode='colourTimer' toField='set_fraction' toNode='flash'/>
     <ROUTE fromField='value_changed' fromNode='flash' toField='set_diffuseColor' toNode='material1'/>
  </ProtoBody>
</ProtoDeclare>

Rather than rigging up 144 route statements to pass each prototype the playmode value, I picked up this neat trick from the X3D mailing list to dynamically add routes via the SAI. In order for the script to work, all of the prototypes were grouped together in a single group, so that they could be passed to the script.

<Script DEF="logic" directOutput="true">
   <field name="touchs" type="SFNode" accessType="initializeOnly">
     <Group USE="Touchable"/>
   </field>
   <field name="playMode" type="SFNode" accessType="initializeOnly">
     <BooleanToggle USE="playMode" />
   </field>

   <![CDATA[ecmascript:
   function initialize()
   {
    scene = Browser.currentScene;

    for (i = 0; i < 144; i++)
    {
      bell = touchs.children[i].children[0].children[0];
      scene.addRoute(playMode, 'toggle_changed', bell, 'playMode');
    }
   }
  ]]>
</Script>

Next steps

I was left only to rig-up the geometry for the stands and the bases. Overall, the model is working well. After the optimisations, the file was reduced to 1,500 lines of code, and renders at an acceptable framerate. The next challenge will be to reduce the file-size of the audio-clips: currently 10 second .wav files, before it can be delivered onto the web proper.

The remaining area of functionality for this project is to work with MIDI to read-in compositions and play them using the new instrument, in effect, writing a basic MIDI sequencer in X3D. I’m currently working on this now, so watch this space! You can listen to a sample of the sounds being played on my music blog.

Thanks to all those in the X3D Mailing List whose comments have helped me progress with this project.

Close up of Bells playing glissando

Close up of Bells playing glissando

Ruby on Rails Music Blog Launched

April 2nd, 2009

As if one blog could ever be enough. I decided to finally get my act together and create a web presence for my musical aspirations- http://www.dangarland.me.uk .

The website is a beta version of a music-community website I’m developing for Vibey Subscriptions Ltd. (watch this space). The software has many features, including:

  • Track uploading – takes a PCM, uploads it to a web-server, encodes it on the fly, generates mp3, ogg and flac and creates a webpage for them to go on.
  • Music streaming – using flash or Java applets the software streams files down to clients so that they can instantly hear songs
  • Video uploading / stream – Same idea as above, but with videos!
  • User management – Users can login and edit the band’s their assigned to, but no more. Punters can sign-up and interact with less privileges than full-users.
  • Subscriptions- Full integration with SecureTrading’s XPay subscription module (although this is disabled for my blog, which is absolutely free!)
  • Blogging – OK maybe not as fully-featured as wordpress, but that makes it simpler to use!

The full version is close to completion. I have some user interface improvements to make, but hopefully it will be ready within weeks. I’ll be picking out some of the features and writing about how they work over the next few days.

In the meantime, take a look at my music blog and let me know what you think! Don’t forget to comment / rate!

Tell the world what music you are listening to with Icecast and Ruby on Rails

March 27th, 2009

I had just resurrected some old music from my music collection; some good, some very, very bad; but I wanted to be honest and display the information on my music blog. After all, it would show I have good taste in music ;)

I was streaming music using the excellent Icecast streaming server, and I wanted to display the currently playing track on my rails-based music blog as a link, which when clicked would feed the artist and track info into Google in a new window to help others find out about artists they might not have heard of. Fortunately, the current track information is provided by Icecast and is used by iTunes to display the current track information while I’m listening. The information is hosted on the admin section of the icecast server, /admin/stats.xml, so actually the simple solution would be to grab that XML file, parse it, and obtain the track information. The element I was interested in was called ‘Title’, under the source element, which contained the Artist – Track Title information, presumably from the mp3’s ID3 tag.

The first step was to obtain the XML file and read in the value of the Title element. I created a method named currently_playing in the application_helper.rb file, which would enable the method to be available to any view in the application.

Net::HTTP.start('hostname.co.uk' , 8888) {|http|
      req = Net::HTTP::Get.new('/admin/stats.xml')
      req.basic_auth 'admin', ICECAST_ADMIN_PASSWORD
      response = http.request(req)
      xml = REXML::Document.new response.body
      xml.elements.each('icestats/source/title') { |title|
          return title.text
      }
    }

Note that I used a constant value for the Icecast admin password, controlled via the constants.rb file in the config folder. This nice block of code HTTP gets the XML file, takes care of the basic HTTP authentication and turns the result into an XML DOM, using XPath to retrieve the value of the Title element.

I decided that I wanted to display this information in the top-right of my header, so I found that component in rails and added a link:

<% cl = currently_listening
   unless cl.empty? %>
<div id="currentlylistening">
   Currently listening to : <%= link_to cl, { :controller => 'referrals', :action => 'redirect_google',
        :title => CGI.escape(cl)}, :target => '_blank' %>
</div>
<% end %>

Finally, I added a method in my referrals controller, called redirect_google. That way, I don’t lose page rank having a link to Google and instead redirect the user where I want them to go.

def redirect_google
    redirect_to 'http://www.google.co.uk/search?q=' + params[:title] + '&ie=utf-8&oe=utf-8&aq=t'
end

Now, whenever the user visits a page, they can see what I’m actually listening to in iTunes. Time to delete my embarrassing Simply Red, Eternal and Cher tracks…

Creating your own private mp3 jukebox with Icecast Streaming, Ices and Debian

March 27th, 2009

I like to think that I stay ahead of the times. In 2000, I used to think that my Creative Nomad jukebox with 6GB of hard-disk space was the most incredible thing ever, and I took mine to University, proud of its ability to reduce a shelf-load of CDs into an object no larger than one or two discs. It was cool how you could take a bunch of music, let them all get strung together into a continuous stream, and have them played back in a random order, like your own personal radio station without the ‘personalities’. Back then, Creative had to market them as jukeboxes- they were still too bulky to be used like iPod shuffles are now. But that was nearly ten years ago, and times must move on.

I have found that the biggest problem after moving to mp3s is keeping up with my collection. I stopped collecting after around 20GB and began to just have smaller collections here and there: some music on my PC laptop, some on my Mac, some on my PC, some on a mp3 player. Overall, it became difficult to keep it all in one place, and so whenever I’d buy a CD, download an album or mix one of my own tracks my collection would become increasingly fragmented. Its got to the stage now where I haven’t actually listened to parts of my collection for many months, so I decided to do something about it.

I wanted to setup my own jukebox, streaming music over the web, so that I could access it wherever I was, from any platform, at any time. That way, all my music is in one place and I save heaps of disc space on my local computers.

So I decided to setup Icecast, an open-source streaming server. It works by receiving an audio stream from somewhere, and converting it into itty-bitty-bytes that are downloaded to clients over the Internet, such as iTunes. The audio stream can be a live feed from a soundcard, or taken from a playlist running off your hard drive. I used the latter approach, because I have a large directory of mp3 files that I want to listen to. This involves using another piece of software called Ices, which is responsible for building the audio stream sent to Icecast. Its a handy piece of software; working from a playlist, it can randomly choose a track, re-sample it to a lower bitrate (to save your bandwidth costs and keep the music playing smoothly) and even cross-fade between tracks.

While I was busy rsyncing my music collection to my server, I downloaded and installed icecast 2.3.2 and ices 0.4 from source. I chose the older version of ices, because it deals with mp3s, whereas the newer version can only read ogg Vorbis files, and my collection consists mainly of mp3 files. I needed to install a couple of dependencies thrown up by configure, specifically libxslt, which I did using apt-get. So far so good.

The first configuration step was configuring Icecast. By default, icecast creates a configuration file in /usr/local/etc/ called icecast.xml which you can edit. The file is commented with examples, and can be tweaked as needed. Don’t forget as this is an XML file that it should be well-formed with matching opening and closing tags, as well as opening and closing comments (and no nesting comments!). I reduced the number of clients (it is a private stream for me!), set the hostname/port, log directory and the source, relay and admin passwords (they’re ‘hackme’ by default!). Following that, I was able to test the server was working by running icecast and checking the error.log file:

icecast -c /usr/local/etc/icecast.xml
tail /var/log/icecast/error.log

I could also visit the admin pages at the hostname and port I had configured, which show a basic admin interface.

The next step was to provide audio for Icecast by configuring Ices. Similarly, the default install created an example configuration file in /usr/local/etc/ called ices.conf.dist. I moved this to ices.conf and began to edit. I changed:

  • <File> – I set this to be the playlist file I wanted for the stream. The playlist file is simply a text file with a path to an mp3 file on each line, so I generated it automatically from the music files I kept in /music.
    find /music -name *.mp3 > /usr/local/etc/playlist.txt
  • <Randomize> – I set this to 1 so that Ices jumped around the list, creating a radio station style mix, rather than playing through sequentially.
  • <Crossfade> – I set this to 5 so that each song fades-in/fades-out over the course over five seconds, resulting in nice, continuous play.
  • <BaseDirectory> – I set this to be the same as the log directory of Icecast so that the logs were nearby each other.
  • <Hostname> – I set this to match the hostname I configured in Icecast.
  • <Port> – Ditto…
  • <Password> – Same…
  • <Name> – I set this to “Dan’s Jukebox”, which is what the stream is listed under in iTunes.
  • <Genre> – I set this to “Anything”.
  • <Description> – This also appears on the web interface and iTunes so I wrote something in there too.
  • <URL> – This URL is a page used to describe the stream, and appears on rotation in the iTunes interface so I used my website URL.
  • <Public> – I set this to 0 so that the stream isn’t listed publicly and I get subpoenaed by the RIAA…
  • <Bitrate> – Very important! This is the setting that Ices uses to determine what quality to send the audio in, and has implications on the amount of bandwidth you use; which in turn determines the financial cost and smoothness of your stream. If your stream is available to multiple users, you have to consider that this figure would be multiplied by the number of listeners, so be careful not to set it too high. 64kbps is about the quality you get listening to MySpace and is low-quality; but you won’t really notice if listening on a laptop speaker anyway. Bearing in mind that the mp3s were mostly encoded at 128kps originally, I decided to keep my bandwidth use down and started out with 64kbs. It sounds alright to me, maybe I’ll ramp it up to about 80-something later if I feel like it.

Once configured, I tested Ices by running it without any options:

ices

By default, Icecast and Ices run in the foreground, which means that once you start running them they don’t return the console back to you and you have to open another to keep using Linux. I wanted them to run in the background as daemons so that when my server boots up / restarts, or I log-out, the music keeps going. I so put together two init.d scripts, starting from /etc/skeleton, to start/stop Icecast and Ices. Below is the icecast init.d script I’m using, and Ices is similar.

#! /bin/sh
# Author: Dan Garland dan@NOSPAMdangarland.co.uk>

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Icecast Server"
NAME=icecast
DAEMON=/usr/local/bin/$NAME
DAEMON_ARGS="-b -c /usr/local/etc/icecast.xml"
ICES=/usr/local/bin/ices
USER=$NAME
GROUP=$NAME
PIDFILE=/var/run/$NAME.pid
ICES_PIDFILE=/var/run/ices.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started

        start-stop-daemon --start --quiet --chuid $USER:$GROUP --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
                || return 1

        start-stop-daemon --start --quiet --chuid $USER:$GROUP --pidfile $PIDFILE --exec $DAEMON -- \
                $DAEMON_ARGS \
                || return 2
        # Add code here, if necessary, that waits for the process to be ready
        # to handle requests from services started subsequently which depend
        # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        # Wait for children to finish too if this is a daemon that forks
        # and if the daemon is only ever run from this initscript.
        # If the above conditions are not satisfied then add some other code
        # that waits for the process to drop all resources that could be
        # needed by services started subsequently.  A last resort is to
        # sleep for some time.
        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
        [ "$?" = 2 ] && return 2
        # Many daemons don't delete their pidfiles when they exit.
        rm -f $PIDFILE
        return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
        #
        # If the daemon can reload its configuration without
        # restarting (for example, when it is sent a SIGHUP),
        # then implement that here.
        #
        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
        return 0
}

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  #reload|force-reload)
        #
        # If do_reload() is not implemented then leave this commented out
        # and leave 'force-reload' as an alias for 'restart'.
        #
        #log_daemon_msg "Reloading $DESC" "$NAME"
        #do_reload
        #log_end_msg $?
        #;;
  restart|force-reload)
        #
        # If the "reload" option is implemented then remove the
        # 'force-reload' alias
        #
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
        exit 3
        ;;
esac

:

Note the -b option to run in the background and the –chuid option to run the program as the icecast user and group (Icecast doesn’t run as root). If you don’t have a icecast user or group, create them as root with the adduser and addgroup commands:

adduser icecast
addgroup icecast

I could then tell Debian to run these scripts at start-up using update-rc.d:

update-rc.d icecast defaults
update-rc.d ices defaults

Once running, I could point iTunes to the stream by choosing Advanced -> Open Audio Stream, and typing in the full url to the mointpoint. Now I’m listening to some track I swear I haven’t heard since the mid 90’s, and I want to tell the world.

Publishing photos to a web gallery with JAlbum

March 25th, 2009

An aside. I’m not much of a photographer; I agree with my namesake Alex Garland’s opinion that rather than photographing momentous events you are better off simply witnessing them. This conviction has resulted in some neglect of my digital camera which I got for Christmas last year, but I did have a few snaps rattling around in its SD card. I decided to publish them on the web; why not after all? But rather than using some corporate ad-based solution like Flickr I wanted to know whether there was some software lying around on the web that would allow me to create a web gallery for my photos instantly and effortlessly.

That software is called JAlbum. One of the more impressive Java desktop applications I’ve seen recently, I had the photos off my camera and onto the web in five minutes, looking good, with a slideshow option and it even handled mov files.

Once you’ve downloaded the software and verified your e-mail, you will have an application called JAlbum. When you fire it up, you’ll see a large window just waiting for photographs. I dragged + dropped all the photographs from the camera, mounted as a USB drive, straight into the JAlbum window.

The first screen you see in JAlbum

The first screen you see in JAlbum

Once you drag+dropt the photographs, JAlbum asks you to create an album and to name it. This name is used as part of the URL which the album will be hosted later.

The new album dialog

The new album dialog

Then, your photographs appear as a grid of thumbnails for you to review. This is the point to re-order photographs, strip-out those red-eyes and drop those embarrassing photos of you drunk and trying to smoke the cigarette on a camel advertisement. Use the ‘exclude’ button to drop photographs from the album.

At this point, you can begin to consider how you want the gallery to be presented on the web. The software is going to generate a bunch of static HTML and CSS files, but you can decide what they look like using the range of built-in skins. On the left-hand side, choose a skin, and then an appearance; for each skin comes in a variety of colours. A pop-up instantly demonstrates what the album will look like, so you don’t have to wait to see the results.

Once you have decided on your flavour, its time to upload. For those without a webserver, perhaps the majority, JAlbum provide webspace to host your album on a subdomain matching your username. Luckily for me, I have a webserver, so I decided to use that.

Punch the ‘Make JAlbum’ button, the one marked with a frog. The software then resizes your imagery down ready for uploading and generates all of the webpages used to display them.

The software resizing the imagery

The software resizing the imagery

Once complete, if you press the ‘publish’ button, I trust the software when it says it will upload the album to your allotted webspace on jalbum.net. I however wanted to use my own server, so I cancelled that and pressed the arrow next to ‘Publish’ to choose ‘manage / delete published albums’. From there I could add the user account on my Linux box and configure it to access my server.

Configure JAlbum to publish to my linux box

Configure JAlbum to publish to my linux box

I checked the box ’secure’ to use scp to copy the files, and provided my username/password. There is also a nifty feature to ’show full server directory tree’, so that you can rummage around your server’s directories to find the best place to upload your album. I created a sub-folder photos from my web server’s DocumentRoot and placed the album there.

JAlbum allows you to choose the location on your server for your gallery

JAlbum allows you to choose the location on your server for your gallery

The main thing to remember is that JAlbum doesn’t know how your webserver is configured: where DocumentRoot is. So in order for everything to work properly, you have to select the DocumentRoot folder (normally /var/www) and press the ‘Mark as web root’ button. This allows JAlbum to figure out where URLs should point, relative from the DocumentRoot. Make an album directory for your gallery, and then press ‘Upload’.

And that is really as simple as that. I was very impressed by the slick design, the effortless process and the flexibility to ‘just work’ with my existing setup. And its free!

You can see an example album here: http://www.dangarland.co.uk/photos/France2008

Conic Bellophone in X3D, Part One

March 18th, 2009

One of the projects I’m working on right now is an ambitious attempt to realise a 3D-model of the Conic Bellophone, an experimental musical instrument under developed as part of a PhD project. The requirements were to develop a 3D model that can be viewed from any angle, and when a bell is ’struck’ to sound a sample captured from the real thing.

I hoped to dust-off my Xj3D knowledge from hacking around at University during my thesis, and despite some wrestling I managed to get as far as a 3D model with sounding bells, and a glissando effect when you run the mouse cusor over the bells (press the red box).

Conic Bellophone in X3D

Conic Bellophone in X3D

Still to do: I have to figure out how to persuade the time/event model to accept restarting sound. Currently, the spec says that passing the current time to both the startTime and stopTime of an AudioNode should restart the node, but I am finding this not to be the case, and I’m trying workarounds with script nodes. After that’s solved, I will be working with MIDI to allow the instrument to play arrangements made in MIDI; all in 3D.

The instrument uses the applet-launcher Java web start program, to wrap an applet which renders the Xj3D browser and the scene. I’ve found this has issues when used in windows, so there is still some work to do.

But take a sneak preview: http://www.dangarland.co.uk/virtualinstrument . Don’t forget to press ‘trust’ on the security prompts that appear.

CV Update

February 25th, 2009

I’ve decided to update my CV to reflect the time I’ve spent as Director of Vibey Subscriptions, nearly three months officially, but around six months of development. We’re nearly ready for a beta prototype, so watch this space!

My latest CV is available to download here, as well as an expansive section on my project work so far in more-depth. Please get in touch if you are interested in working with me on short-term contract or fixed-fee web development.

Running SecureTrading XPay client on Debian/AMD 64-bit

February 24th, 2009

This post is about running the XPay client provided by SecureTrading for on-line e-commerce payment processing, but it might also be useful for anyone trying to run a java application on a Debian server, particularly if they require it to be 32-bit compatible, such as running a JRE 1.4.2, or to start-up on boot.

SecureTrading’s payment processing solution provides a Java application responsible for all the encryption and secure communication with their payment gateways, leaving the application developer only responsible for forming an XML document and transmitting it on an unsecured, local socket. I have recently completed an integration using Ruby on Rails, and things were going too smoothly; something had to be problematic!

And it was this: I was running Debian Etch on a 64-bit server, and the XPay client requires Java runtime 1.4.2, which is no longer supported by Sun and only has a 32-bit linux version (unless you’re running Intel). I thought I was stuck: SecureTrading even offered to refund me at one point. I was certain there had to be solution other than getting hold of another 32-bit box, and it was, thanks to the excellent Debian o/s.

Some boffin has packaged the libraries necessary to run 32-bit apps in the ia32-libs package, so that older 32-bit applications can run alongside up-to-date 64-bit ones. It is installed in one command:

apt-get install ia32-libs

I could then download and run the binary installer for the Java runtime environment. I could then follow the instructions to setup the client certificate in the keystore and run xpay.

/usr/local/java/j2re1.4.2_19/bin/keytool -import -alias xpay -file /var/whereever/xpay/securetradingxpay.cer \
-keystore /usr/local/java/j2re1.4.2_19/lib/security/cacerts

This leaves the task of having XPay run at startup, as an init.d script. Typically, Java doesn’t play nice with init.d scripts, but I managed to get it running with Debian’s start-stop-daemon script. Starting from the /etc/init.d/skeleton file, I trimmed most of it away to end up with:

#! /bin/sh
# Author: Dan Garland <dan@dangarland.co.uk>
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
JAVA_HOME=/usr/local/java/j2re1.4.2_19
CLASSPATH=/var/whereever/xpay/XPay.jar
PATH=$JAVA_HOME/bin:/sbin:/usr/sbin:/bin:/usr/bin
DESC="Xpay Client"
NAME=XPay
DAEMON=$JAVA_HOME/bin/java
DAEMON_ARGS="-classpath $CLASSPATH -Djava.security.manager -Djava.security.policy=/var/whereever/xpay/xpaypolicy XPay "
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
  start-stop-daemon --start --background -p $PIDFILE -m --exec $DAEMON -- $DAEMON_ARGS
  echo "$NAME started..."
}

#
# Function that stops the daemon/service
#
do_stop()
{
  start-stop-daemon --stop -p $PIDFILE
  echo "$NAME stopped..."
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
        #
        # If the daemon can reload its configuration without
        # restarting (for example, when it is sent a SIGHUP),
        # then implement that here.
        #
        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
        return 0
}

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  #reload|force-reload)
        #
        # If do_reload() is not implemented then leave this commented out
        # and leave 'force-reload' as an alias for 'restart'.
        #
        #log_daemon_msg "Reloading $DESC" "$NAME"
        #do_reload
        #log_end_msg $?
        #;;
  restart|force-reload)
        #
        # If the "reload" option is implemented then remove the
        # 'force-reload' alias
        #
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
        exit 3
        ;;
esac

:

This script then runs XPay on boot. Make sure that the paths to the jar and the policy files are correct, and that the policy file has the correct path to the Java 1.4.2 installation directory.