subscribe

C# developer by day, Ruby and budding Erlang enthusiast by night. Father, husband and all around good guy.

August 19th, 2009

I need how much space?

image

Maybe I’m dense.  But I had to read this window not once or twice … but 5, yes 5, times before I realized that it was giving the “Required” units in “KB” and “Available” units in “MB”.

Please … unless your UX is a “convert unit X to Y” window, stick to one unit.

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:

August 15th, 2009

I’m may not be the brightest bulb in the pack but I do know a couple-a-things about a buncha-stuff.  One of those things is that when I plug a keyboard into my computer and open Cakewalk Sonar (8 Producer Trial) I expect to hear sounds.  The other is that when I finally hear those sounds they shouldn’t be punctuated with a loud (louder than the audio being played) click ever half second or so.

Not even exaggerating – it was like a slightly off-beat metronome was overpowering what I was playing.

Getting the Sound…

I plugged my Alesis Photon x25 into my Windows 7 laptop and then started Sonar 8.  I’m immediately greeted with the message that either the Photon is not supported or in use.  I’m going to assume it’s in use by Windows and just move on … click “Use Anyway”

Create a new project … delete all the audio tracks … add a MIDI track … hit a key.  Whoa!  Hmmm … no sound.  Oh!  Forgot to add a synth (I came across this when doing “Tutorial 1” in the Sonar help file … yeah … I read it.  I read the Readme too).  So I add a synth.  Now I hit a key and … still nothing.  The signal indicator is peaking so I know I’m getting the input from the keyboard to the DAW.  Time to try some random things and then hit the tubes looking for an answer.

Let me save you the trouble:

http://www.cakewalk.com/Support/FAQ/MIDI2Audio.aspx

Read the whole thing.  It was section three I cared about.  Specifically to check “All Synth Audio Outputs: Stereo” and to map the outputs to the synth.

But still no sound – oh crap – it’s playing through the Photon and not my sound card!  Awesome!  I plugged in a set of head phones and I’m off.  This is great.

But it sounds horrible …

clicks and pops like mad.

Again … let me save you the trouble:

http://www.cakewalk.com/support/FAQ/SR_FAQ.aspx#9

Adjusting my buffer to “Safe” made it better so I knew I was on the right track – but changing my driver from WDM to MME was the key (ASIO didn’t work – no sound … I’ll look into that some other time).  Once I was switch to MME I was able to drop my latency back to 10ms.  At 10ms I get an occasional pop.  At 30ms almost none.  At 90 – I’ve yet to hear any.  Beauty!

Now to find some free VST synths because the ones in the Trial are … just horrible.  It’s like they are punishing you for using the trial.  Give me a drum kit or piano please!  Some congas and a shaker … anything.  Jeez.

(they are probably there and I just don’t know how to use them yet … but the forums I read all said things like “the trial has crap sounds … get free VSTs”).

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:
, , , ,

August 14th, 2009

I’ve made a pretty firm commitment to not get too deep into buying gear before I’ve really figured out what it is that I want – but I had a chance to pick up an Alesis Photon x25 MIDI controller with Cubase LE for about $40 today.  The controller was purchased new about 2 months ago, returned in favor of another model and has sat in the “Used Equipment” window since then.  I’ve watch the price fall and fall and today sniped it for a fifth of it’s street price a few months ago.

But why?

Creating a home studio is as much about software as hardware – and testing what DAW I like requires two things:

  1. A DAW
  2. An input device to do something useful in said DAW

This unit comes with Cubase LE and Sonar 8 Producer is available for a 30 day trial … so there I go.  I have the software and a crazy cheap way to test it out.  And when I’ve made up my mind I’ve also got a nice little MIDI controller.

That’s how I rationalized it to myself.  Did it work for you too?

My contented feeling was short lived though.  After picking it up I went out to dinner with a few of my kids and got to spend a few hours fretting over whether or not this device would be compatible with Windows 7.  The M-Audio KeyRig isn’t (more) – would this device be?  It’s not the newest unit on the block – discontinued in fact.

But I plugged it in and …

image

Now … I haven’t done anything beyond this.  So does it work?  I’m installing Cubase LE now …

Hmmm.

Well.  Plan has hit a kink.  The previous owner claimed he never registered Cubase but apparently he took the registration code.  So I have 30 days to decide if I want to keep this or not.  Let’s see how Sonar likes it… (next time).

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
2
Comments

Tags:
, , ,

August 14th, 2009

I learned something about myself this week.  I can’t stand it when people refer to an externally connected (FireWire or USB) audio device a “sound card”.

audio-cards

One of these things is not like the other.  Know which one?  The one that’s actually a card.  The other are boxes.

I’m going to start referring to printers as “printer card”.  That’ll show’em.

Moving on…

Let me get you up to speed.  I have more time than money ($1000) and I want to put together an inexpensive home recording studio.

The first decision I made after several days of researching: I’m not using a digital-recorder-mixer combination plate.  At first I thought I was.  I had even figured out which one – the Zoom HD8CD.

zoom-hd8cd

This seemed ideal on the surface.  Buy one thing and just be done with it – even a CD burner.  It can communicate with a DAW to do further processing and mixing on the computer.  What’s not to like?

Well … it comes down to several factors.  Things like only being able to record 2 tracks at once … and those tracks are 44/1Khz 24 bit (mixed down to 16 bit mono).  Very limited EQ means I’ll spend a lot of time in the DAW anyway.  Questionable preamps (the only question is “how bad are they?”).  I don’t need a CD writer but I’m still paying for it (instead of paying for something I do need).

So at the end of the day I get a highly convenient device (a card?) of that leaves me disappointed on pretty much every front but which does get the job done.  Sure – I could spend more and get a better device but the price jump between “crappy” and “nice” is well outside of my budget.

So what are my options?  Well – there is a PCI card or an external device connected by USB or FireWire.

pci-audio-card

I’m using a laptop so PCI is out (and even if it were an option I wouldn’t necessary want it).  And since I’m using a lower-end laptop I don’t want to use USB since it puts more pressure on the CPU and has lower real-world transfer rates compared to FireWire.  I want to get everything I can out of what I have.

There.  I just saved you three days of reading and thinking.

You want an external device audio input device connected to your computer via FireWire.

That’s what I want and that’s what you want.

Next time I’ll look at some of the options I’m considering.

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:
,

August 13th, 2009

I’m in the planning stages of putting together a home recording studio for capturing the musical ideas that no one else wants to hear.  In high school I spent my junior year at the Minnesota Center for Arts Education (I spent my senior year preparing to have my first child but that’s another story for another time) – while at MCAE I had the opportunity to spend my afternoons (and many many nights) in a very nice production studio.  Many many thousands of dollars of gear – much of which you couldn’t give away today.  The point being that I’m familiar with what a high-end home studio would have looked like 15 years ago – unfortunately that knowledge does not do me a whole lot of good.

What I have

  1. A 6’x10’ space to work with.
  2. A laptop computer (Acer Extensa 5620Z – jealous much?)
  3. $1000 (my wife may disagree with this assertion but she is out of town)

What I want

  1. To be able to capture my guitars (electric and acoustic) and vocals
  2. A MIDI input keyboard
  3. Gear that is not crap and can grow into better things

Something like this

wheremusiccomesfrom

That’s one hell of an expensive question mark.

So over the next few posts (or weeks … who knows) I’ll be going over what I’m thinking about, what I decide, and why I changed my mind just minutes after making a decision after days of thinking.

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:
,

July 8th, 2009

Update: The definition has been updated to include support for atoms, variables and function names as well as additional file extensions.  Screen shot and downloadable content have been updated.

Thus far I’ve done all of my Erlang development on Fedora using vim or KWrite (which does a decent job in Ruby mode).

But today I found myself on a windows box and wanted a basic syntax highlighting editor for Erlang that was free and worked on Windows. Oh – and not Eclipse+Erlide. I wanted something small and fast.

I grabbed the “free as in beer” and “free as in speech” editor NotePad++ and created a simple syntax file that is a bit hokey but will serve my needs fine.

Here’s a screen shot …
Windows Erlang Syntax Highlighting Editor

NotePad++ has pretty weak syntax highlighting but was sufficent to do most of what I wanted.  Some regex based rules would make this a more robust.

Highlighted entities include

  • Erlang reserved words (and named operators)
  • Variables
  • Atoms
  • function names (same coloring as atoms)
  • Operators
  • Comments
  • Kernal, stdlib, mnesia and odbc modules.
  • Support for *.erl, *.hrl and *.htp extentions

I’ve probably missed several things.

Looks a lot better than nothing and it took all of 10 15 minutes.

If you are using NotePad++ here is the file:

http://www.roberthorvick.com/wp-content/uploads/2009/07/erlangSyntaxDefinition.zip

And here are the instructions on how to install it:

http://sourceforge.net/apps/mediawiki/notepad-plus/index.php?title=Syntax_Highlighting_Sharing

And here’s the instructions on modifying or creating your own:

http://sourceforge.net/apps/mediawiki/notepad-plus/index.php?title=User_Defined_Languages

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
7
Comments

Tags:
,

July 6th, 2009

I’ve got the basic grasp on Erlang but before I can do anything meaningful I need to learn how to test my code  EUnit is the de-facto test framework.  There are a ton of great sites that talk about testing with EUnit – I have linked to several at the end of this post.  I’m going to focus on the problem I ran into – needing to run some startup and cleanup code around the test suite.

I started by writing a very simple dictionary that lived in it’s own process.  The interface is:

start() -> ok
stop() -> ok
write(Key, Element) -> ok
delete(Key) -> ok
read(Key) -> {ok, Value} | not_found

Calling start() spawns and registers the process the dictionary lives in.  Calling stop ends the process.  The rest do what you expect.

I started by writing some basic tests for each function but I didn’t really think it through.  The start test ran somewhere in the middle so all the tests prior to start either failed or timed out (because I was waiting on a receive that would never come since the process wasn’t started).  Very quickly I smacked my forehead and said “I need the test suite to have a pre and post function to start and stop the process”.

It took about 15 minutes of reading to realize that I needed to create a test generator with a setup tuple that defined the startup, cleanup and list of tests to run.

Conceptually it was easy to understand but getting the syntax right was a royal pain.  Basically you do this (I’m not sure if giving the function arity is the preferred method but it saved some keystrokes so I went with it):

my_db_test_() ->
  {spawn,
    {setup,
      fun start/0,
      fun stop/1,
      [
        fun write_new/0,
        fun write_existing/0,
        fun read_existing/0,
        fun read_missing/0,
        fun delete_existing/0,
        fun delete_missing/0
      ]
    }
  }.

The test methods are exactly what you’d expect so I won’t repeat them.  The syntax feels a little foreign and uncomfortable but it’s very easy to understand and I totally get why it’s written this way.  I’m just so used to MSTest attributes and RSpec that this new way is going to take a night or two to feel like an old friend.

Some Eunit resources

Prag Dave – Test-First Word Wrap in Erlang

EUnit – a Lightweight Unit Testing Framework for Erlang

EUnit Reference Manual

Getting Started: No Consoles!

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:
,

July 3rd, 2009

One last iteration through my learning exercise of building a word frequency list. In this last post I’m moving away from a dict and to an ets table. I was pleasantly surprised how easy the conversion was. For example printing the output was just converting from dict:fold to ets:foldl. The one parity fail was that dict:update can take an initial value when the key is missing but ets:update_counter (nor any other ets function) has this benefit. This required that I write a little wrapper function to call from the list:foldl (instead of having a multi-line inlined fun).

No point in getting too deep into this – here’s the code:

-module(wordets).
 
-export([print_word_counts/1]).
 
words(String) ->
  {match, Captures} = re:run(String, "\\b\\w+\\b", [global,{capture,first,list}]),
  lists:append(Captures).
 
%% reads the next line from the file.  If there is data then...
%% split the data into a list of words and add to the word table
process_each_line(IoDevice, Table) ->
  case io:get_line(IoDevice, "") of
    eof -> 
      file:close(IoDevice),
      Table;
    {error, Reason} ->
      file:close(IoDevice),
      throw(Reason);
    Data ->
      NewTable = lists:foldl(
        fun(W, T) -> update_word_count(W, T) end, Table, words(Data)),
      process_each_line(IoDevice, NewTable)
  end.
 
update_word_count(Word, Table) ->
  case ets:lookup(Table, Word) of
    [{Word, _}] ->
      ets:update_counter(Table, Word, 1); 
    [] ->
      ets:insert(Table, {Word, 1})
  end,
  Table.
 
print_words(Words) ->
  ets:foldl(fun({W,C}, AccIn) -> 
    io:format("~s: ~w~n", [W, C]), AccIn end, void, Words).
 
%% opens the indicated file, processes the contents and prints
%% out the word/count pairs to stdout
print_word_counts(Filename) ->
  {ok, IoDevice} = file:open(Filename, read),
  Words = process_each_line(IoDevice, ets:new(words, [])),
  print_words(Words).

The ets implementation feels a bit forced (which it was – the point was to learn another module). I don’t think I’d have gone this way in practice unless I wanted to persist the frequency data to a file or if the word data were more complex (for example if I were storing information about where in the file the word was, word neighbors, etc).

Enough of this sample. On to something more substantial.

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:
,

July 3rd, 2009

To make getting to the Erlang docs a bit quicker I added a custom protocol handler to firefox so when I go to:

erlang://lists

I get redirected to

http://www.erlang.org/doc/man/lists.html

To do this I first created a little shell script that would take the address and spawn firefox with the appropriate url. (insert caveat about this being the first bash script I’ve written in 10 years here …).

#!/bin/bash
ERLANG_TOPIC=`echo $1 | sed 's/erlang:\/\///'`
exec firefox http://www.erlang.org/doc/man/$ERLANG_TOPIC.html

Next I marked it as executable:

chmod +x erlang.protocol

Finally I followed these directions and added the following config settings in firefox:

Adding custom protocol to firefox

Since the Erlang/OTP doc pages match their module names this works pretty well.

For queries where I’m not sure what I want I added a Erlang specific google search to my Erlang Resources page.

Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
No
Comments

Tags:

July 2nd, 2009

Sean Cribbs was nice enough to point out a pair of changes I could make to my word frequency counter from last time.

Based on his feedback I made three changes. First – the regular expression code has changed from this:

matches(H,{match,M}) -> matches(H,M,[]).
matches(_,[],Acc) -> Acc;
matches(H,[{I,L}|T],Acc) ->
    matches(H,T,[lists:sublist(H,I,L)|Acc]).
 
words(String) -> matches(String,regexp:matches(String, "[A-Za-z0-1]+")).

to this:

words(String) ->
  {match, Captures} = re:run(String, "\\b\\w+\\b", [global,{capture,first,list}]),
  [hd(C) || C<-Captures].

That last line took me a bit to grok. It’s a list comprehension (if you are reading Joe Armstrong’s thesis it is section 3.3.13. In Erlang Programming it is chapter 9.3). Basically it’s saying “for each list in the list of matches take the head of the list” – a-gigga-wah?

Ok. Let’s go to erl.
7> re:run("foo foo bar", "\\b\\w+\\b", [global,{capture,first,list}]).
{match,[["foo"],["foo"],["bar"]]}

Observe that re:run returns a nested list (i.e. a list of lists) – and each list has exactly one element (the string [which is itself a list but I'll cal them strings]). What we want to do is take that list-of-lists-of-strings and turn it into a list-of-strings.

That’s what “[hd(C) || C<-Captures].” does – it pulls every capture (a word wrapped in a list) from the match list and runs it through erlang:hd which pulls the word from the list – then it gets added to the resulting list. So we end up with a list strings.

It’s un-nesting the list.

Next Sean suggested “Then I’d probably use some kind of key-value structure, like a proplist or dict, to count the words using a lists:foldX function.”

so I fired up “erl -man lists” to learn what foldX meant (actually “foldl” “foldr” depending on whether you want to fold from the left or right.

In a nut shell folding is iterates over a list calling a fun that takes the current value and an accumulator and which returns the new accumulator. An example from the man page is:


> lists:foldl(fun(X, Sum) -> X + Sum end, 0, [1,2,3,4,5]).
15

I spent some time thinking and after some trial and error came up with this:

lists:foldl(fun(W, Dict) -> 
    dict:update(W, fun(C) -> C + 1 end, 1, Dict) end, dict:new(), 
    ["foo", "foo", "bar"]).  %% sample input

In a nutshell – for every word in the list update the dictionary by calling the fun which increments the count value, setting the initial count to 1 if the value does not already exist in the dictionary (and starting with an empty dictionary).

After these three changes the new program is about half the size of the previous and really only has a few interesting lines surround by nearly error and flow control.

Thanks Sean!

The new code …

-module(wordlist).
 
-export([print_word_counts/1]).
 
words(String) ->
  {match, Captures} = re:run(String, "\\b\\w+\\b", [global,{capture,first,list}]),
  [hd(C) || C<-Captures].
 
%% reads the next line from the file.  If there is data then...
%% split the data into a list of words and add those to the word dict
process_each_line(IoDevice, Dict) ->
    case io:get_line(IoDevice, "") of
        eof -> 
            file:close(IoDevice),
            Dict;
        {error, Reason} ->
            file:close(IoDevice),
            throw(Reason);
        Data ->
            NewDict = lists:foldl(
                        fun(W, D) -> dict:update(W, fun(C) -> C + 1 end, 1, D) end, 
                        dict:new(), 
                        words(Data)),
            process_each_line(IoDevice, NewDict)
    end.
 
print_dict(Dict) ->
    dict:fold(fun(Word, Count, AccIn) -> 
        io:format("~s: ~w~n", [Word, Count]), AccIn end, void, Dict).
 
%% opens the indicated file, processes the contents and prints
%% out the word/count pairs to stdout
print_word_counts(Filename) ->
    case file:open(Filename, read) of
        {ok, IoDevice} ->
            Dict = process_each_line(IoDevice, dict:new()),
            print_dict(Dict);
    end.
Share and Enjoy:
  • Print this article!
  • Twitter
  • Digg
  • Reddit
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • StumbleUpon
1
Comment

Tags: