I am into all types of synthesizers, old and new, and recently I’ve taken to the sound of older video game sound chips. I recently desoldered the NES’s 2A03 processor off its mainboard and have it in partial communication with an Arudino, but rewind, do I really know enough about composing music on that chip? Not yet. So there’s only one thing to do about that.
The NES was programmed in 6502 assembly language, and lucky for me, it actually has a really straight forward instruction set, but still, last month I was still not familiar with it enough to make anything. Now, usually when I don’t understand something, I write a program that somehow involves whatever topic I’m learning. You can’t write a program like an assembler without understanding how the processor for that assembler works, so I wrote my own assembler for the NES called n65.
This is the assembler I will be using in this article, and to help me compose music on the NES.
You can easily install n65 through RubyGems.org:
gem install n65
Since they are my favourite, let’s learn something neat about matrices, something that can also serve as the first post on this new blog of mine about math, programming, and DSP.
Last year I built a small MIDI controlled polyphonic synthesizer called KittySynth using a 72MHz LeafLabs Maple microcontroller board, an Audio Codec Shield from Open Music Labs, and some C++. I had originally had some ideas to try to build something like this by abusing the timers and PWM duty cycles on a 16MHz Arduino Mega I have, but quickly realized there was no way on earth I could build what I wanted to with the small amount of resources on an Arduino. The ARM based STM32 chip on the Maple had just enough resources available to create an 8-voice polyphonic wavetable synth, which I should write about sooner or later.
Anyway, while researching for that project I found out that someone actually has created a perfectly viable synthesizer based around a 20MHz ATMega chip (as in the Arduino) called the Shruthi-1. I thought this was a perfect opportunity to go through the steps of actually building a proper synth of the sort I would someday like to design, so I ordered the Shruth-1 4-Pole Mission Kit, and decided to put it together from scratch.
This is part 6 of a 6 part tutorial
The IO Monad
In pure functional programming, all functions are supposed to be referentially transparent, and that means that each time you call a function with the same arguments, it should give you the exact same result. When functions are referentially transparent, you have a lot less worries about whether or not it will always work correctly.
A mathematical function is never going to give you a different answer no matter how many times you give it the same argument. The reason for that is pretty much that it cannot get any values from anywhere other than what you passed it, so it can never be any different.
This is part 5 of a 6 part tutorial
The Haskell list type is also an instance of the
Monad typeclass. There are four functions
defined for a monad, but you only need to implement 2 of them:
>>= (pronounced bind) and
The Monad Typeclass
1 2 3 4 5
The easiest function is
return. It just wraps a value in the monad container, and it is exactly
the same thing as
pure from the Applicative class. The bind function takes a monad holding a
value of type
a, and a function which can change an
a into the same type of monad holding something of type
MyList an instance of Monad, it might be easier to see what happens if we make
something simpler like
Container from part 1 an instance first.
Making Container a Monad
1 2 3 4 5 6
This is part 4 of a 6 part tutorial
A Haskell list is also an Applicative Functor. If we want to make
MyList one too, we can
look at the interface for the Applicative class, and implement the right functions.
Interface for the Applicative Typeclass
1 2 3 4
So, it looks as though we need to implement the functions
<*> in order to be an
instance of Applicative. This also says that whatever is Applictaive has the prerequisite of
also being a Functor. The function
pure must take any type
a and wrap it in the container MyList.
This is also called lifting
a into the Functor. Implementing
pure is easy enough, because it
is the same thing as our data constructor,
This is part 3 of a 6 part tutorial
It turns out that cons lists can be more than just a Functor, it can be a Monoid. A Monoid is a object with a single associative binary operation, and an identity element. This means that things like addition and multiplication form a monoid.
The identity element for addition is the number $0$, because $x + 0 = x$. An identity element and any other element, when operated on by the single associative binary operation, is one that does not change the other element. Basically you can add $0$ to any number and you just get the same number. The identity element for multiplication is $1$, because $x \cdot 1 = x$ for every number.
The binary operation should be one which can combine two of the objects, and for a list that happens to be
appending them using the function
[1, 2, 3] ++ [4, 5, 6] == [1, 2, 3, 4, 5, 6] Easy enough, so that means the identity element, the
element you can combine with a list that will return the same list is:
, the empty list.
[1, 2] ++  == [1, 2]
The ghci command
:info shows that to be an instance of a monoid you must implement the functions
mempty which returns the identity element, and either
mconcat. Typeclasses can
sometimes have default implementations for some functions, and it’s often the case that two functions
are actually defined by default in terms of one another, meaning you only have to implement one of them
and the other will automatically work. Here
mconcat are defined in terms of each other
so we just decide to implement the easier of the two,
Looking at the type signatures below we can see
mappend :: a -> a -> a, where in our case
be the type
MyList. This means
mappend receives two lists and returns a third in which they are
combined. For addition this would have been receiving two numbers that need to be combined, but for
a list it just means to stick them together end to end.
This is part 2 of a 6 part tutorial
How can we modify or transform a value or values that are contained in a data structure such as
say we have a
Container holding the integer 4, and we want to add 1 to it. The problem is that
Container doesn’t have addition defined for it, and really, it shouldn’t considering that any possible
type could be stored inside it, any number of which have no meaningful way to respond to addition.
Let’s look at a similar situation in C++:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The extreme generality of this C++ class means that it would be a mistake to define
it, as any number of types
T also cannot meaningfully respond to addition. Now we find ourselves
in a similar situation in Haskell:
1 2 3 4 5 6 7 8 9
This is part 1 of a 6 part tutorial
Data Structures as Containers
In a language like C, you can think of data structures as containers which hold one or more objects.
1 2 3
int_container_t type is now something which holds one int. To make the same sort of data structure in Haskell you would
Int container in Haskell
Ignoring for a moment the suffix
deriving Show, this looks a lot like a function declaration, because that is essentially
what it is. The identifier
IntContainer appears on both sides, but the two are actually in two different namespaces. It is
not necessary for these two identifiers to have the same name, but people will often do this by convention.
The left hand side of this declaration names a new type
IntContainer, and the right hand side is defining a data constructor
for this type, essentially a function named
IntContainer which takes one
Int as argument which it uses to create an instance of this type.
Using the data constructor in ghci
1 2 3 4 5 6 7 8 9 10
If I pass the data constructor a
4, it returns something which is of type IntContainer. The ghci command
:t can be used
to get type information about just about anything in Haskell.
IntContainer :: Int -> IntContainer is read “IntContainer is
a function which accepts an Int and returns an IntContainer”.
i :: IntContainer is read “i is of type IntContainer”.