I play a lot of music. I mean a lot of music. Guitar, Bass, Piano, Drums, Harp – what ever I can get my hands on, I’ll give it a go. So, the neurons in charge of keeping my technical side in check may have made their way into the creative side of my brain.
The net result was me creating a project that mashes mathematics, data analysis and music theory into a few classed called musica.
So what?
Yeah, basically.. But, I am who I am - so it’ more of a matter of “why not?”.
I’d previously tried building a Ruby on Rails application to give me graphical representations of musically related elements on screen. A scale is a pattern of intervals realised once a root note is put in place. This scale can then be harmonised at every step of the scale by employing every second note from the specific step. How complex these harmonised chords are will depend on how many steps you include in the chords that you build.
The most interesting part of this library, I think, is its distinct lack of database. It has made the code quite verbose in parts but I intend to fix this, even if it does mean employing an intermediary database at a later stage.
What can it do?
The major, harmonic & melodic minor scales (and all of their modes) are statically provisioned. You can use these in code to perform operations like voicing a scale when used in conjunction with a Note object.
Immediately, we can get information about notes:
>>> Notes.by_distance(0)
<musica.notes.Note object at 0x10f961090>
>>> Notes.by_distance(0).__unicode__()
'c'
Information about scales:
>>> Scales.scales[0]
<musica.scales.Scale object at 0x10f963090>
>>> Scales.scales[0].name
'Ionian'
>>> Scales.scales[0].intervals
[<musica.intervals.Interval object at 0x10f961950>, <musica.intervals.Interval object at 0x10f9619d0>, <musica.intervals.Interval object at 0x10f961a50>, <musica.intervals.Interval object at 0x10f961a90>, <musica.intervals.Interval object at 0x10f961b10>, <musica.intervals.Interval object at 0x10f961b90>, <musica.intervals.Interval object at 0x10f961c10>]
Voicing a scale (in this instance voicing Ionian (major) over C)
>>> steps = Scales.scales[0].voice(Notes.by_distance(0))
>>> for s in steps:
... print 'note: ' + s['note'].__unicode__() + ', interval: ' + s['interval'].short_name
...
note: c, interval: PU
note: d, interval: M2
note: e, interval: M3
note: f, interval: P4
note: g, interval: P5
note: a, interval: M6
note: b, interval: M7
Still so much to do …
Still, we need to get chords harmonising from these voiced scales. These are just patterns after all. An intelligent chord builder would also be of value I think. Something where we don’t have to explicitly map out chord names to interval sets statically. Just knowing that a root, major third and perfect fifth are a major chord.
In a previous post, I spoke about calling assembly language routines from C in 32-bit land. In this post, I aim to show you the same technique only this time using a 64 bit architecture.
I’ll be using the same technology stack as last time with NASM as my assembler and GCC as my C compiler. The code snippets that you’ll see in this post have been compiled and linked together on the linux platform.
Alright then. On with the code!
The C-code is not different from the 32-bit version as mentioned in my previous post. Now that’s portability for you!
#include<stdio.h>/** Forward declaration for our add function */intadd(int,int);intmain(){/* add some numbers */intx=add(5,4);/* print the result out */printf("5+4=%d\n",x);return0;}
The assembly language module has changed somewhat though.
globaladdsection.textadd:movrax,rdi; get the first parameteraddrax,rsi; add the second parameter; leaving the return value in raxret
Immediately you can see that a new set of registers are being used and the stack is no longer being used to take parameters in from external calls.
The change in calling convention can be studied in further detail here, however it’s just important to mention this:
Once arguments are classified, the registers get assigned (in left-to-right order) for passing as follows:
If the class is MEMORY, pass the argument on the stack.
If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used
So, the first argument is passed in RDI and the second in RSI. The return value remains the same being passed back to the caller using the accumulator register (RAX in 64-bit land). There are many resources to read up on when it comes to the 64 bit architecture; Intel and Wikipedia are both excellent resources.
Finally, when it comes to building these files together, it’s (again) very similar to its 32bit counterpart.
intsockfd,new_fd;structaddrinfohints,*servinfo,*p;structsockaddr_storagetheir_addr;socklen_tsin_size;structsigactionsa;intyes=1;chars[INET6_ADDRSTRLEN];intrv;/* fill out the address structure */memset(&hints,0,sizeofhints);hints.ai_family=AF_UNSPEC;hints.ai_socktype=SOCK_STREAM;hints.ai_flags=AI_PASSIVE;/* get the address information */getaddrinfo(NULL,PORT,&hints,&servinfo);/* open the socket */sockfd=socket(p->ai_family,p->ai_socktype,p->ai_protocol);/* allow the socket to be re-used */setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int));/* bind the socket to the address */bind(sockfd,p->ai_addr,p->ai_addrlen);/* free up the address structure */freeaddrinfo(servinfo);/* start the socket listening */listen(sockfd,BACKLOG);/* accept the first connect */new_fd=accept(sockfd,(structsockaddr*)&their_addr,&sin_size);/* send the client some data */send(new_fd,"Hello, world!",13,0);/* finished with the client & server */close(new_fd);close(sockfd);
The following snippet outlines the skeleton of a client socket application. It’s the bare bones of what is needed to establish the client connection.
intsockfd,numbytes;charbuf[MAXDATASIZE];structaddrinfohints,*servinfo,*p;intrv;chars[INET6_ADDRSTRLEN];/* fill out the address info */memset(&hints,0,sizeofhints);hints.ai_family=AF_UNSPEC;hints.ai_socktype=SOCK_STREAM;/* create the actual server address */getaddrinfo("www.remoteplace.com",PORT,&hints,&servinfo);/* create the socket file descriptor */sockfd=socket(p->ai_family,p->ai_socktype,p->ai_protocol);/* perform the network connect */connect(sockfd,p->ai_addr,p->ai_addrlen);/* free up the addres structure */freeaddrinfo(servinfo);/* receive some data on the socket */recv(sockfd,buf,MAXDATASIZE-1,0));/* close the socket off */close(sockfd);
Bundled with the GNU toolset is a full featured debugger in GDB. This blog post aims to be a cheatsheet to get yourself around this tool quickly.
The example program
intmain(intargc,char*argv[]){/* some local variables */intx=1,y=2,z=0;/* something that will go bad */intans=x/z;return0;}
Compile your code with debug info
You need to use the -g switch with GCC in order to compile debug symbols. This helps the feedback that GDB will give you a great deal.
$ gcc -g test.c -otest
Loading your program into the debugger
So, in our example above the name of our executable would be “test”. So, we just tell gdb to load test by passing it in.
$ gdb test
You can even start gdb with a text user interface, so I’ve just discovered.
$ gdb test-tui
It looks like this - not bad, eh?
Now we instruct gdb that we’d like to run the application
(gdb) run
Starting program: /home/michael/Development/gdb-tute/test
Program received signal SIGFPE, Arithmetic exception.
0x00000000004004c3 in main (argc=1, argv=0x7fffffffe4d8) at test.c:9
9 ans = x / z;
So you can see here that dividing by zero wasn’t the best career move for this program. But It nicely let us know that there was an arithmetic exception on line 9!
Examining data
To get just the call stack information, we issue the “backtrace” instruction
(gdb) backtrace
#0 0x00000000004004c3 in main (argc=1, argv=0x7fffffffe4d8) at test.c:9
Examining data with print. We can view the value of variables by passing them to the print statement.
(gdb) print x
$1 = 1
(gdb) print y
$2 = 2
(gdb) print z
$3 = 0
Print also supports printf style specifiers. Examining data at an address. We can view the value of data at a memory location by using the x command.
Setting variables while attached is done with set. We can stop the error in the program at runtime using this mixed with a breakpoint.
Breakpoint 1, main (argc=1, argv=0x7fffffffe4d8) at test.c:6
6 int x = 1, y = 2, z = 0;
(gdb) next
7 int ans = 0;
(gdb) set (z = 5)
(gdb) print z
$1 = 5
Working with breakpoints
To set a breakpoint in gdb, just pass the name of what you’d like to break on to the break command.
(gdb) break main
Breakpoint 1 at 0x40049f: file test.c, line 6.
(gdb) run
Starting program: /home/michael/Development/gdb-tute/test
Breakpoint 1, main (argc=1, argv=0x7fffffffe4d8) at test.c:6
6 int x = 1, y = 2, z = 0;
You can set a breakpoint at a specific source code line number:
(gdb) break 7
Breakpoint 1 at 0x4004b4: file test.c, line 7.
Finally, you can make a breakpoint using a combination of source code file name and line location:
(gdb) break test.c:7
Breakpoint 3 at 0x4004b4: file test.c, line 7.
View your existing breakpoints with info breakpoints
(gdb) info breakpoints
Num Type Disp Enb Address What
3 breakpoint keep y 0x00000000004004b4 in main at test.c:7
You can clear any set breakpoint with clear.
(gdb) clear main
Deleted breakpoint 1
You can step into code by issuing the step command
(gdb) step
7 int ans = 0;
(gdb)
9 ans = x / z;
(gdb)
Program received signal SIGFPE, Arithmetic exception.
0x00000000004004c3 in main (argc=1, argv=0x7fffffffe4d8) at test.c:9
9 ans = x / z;
You step over code by issuing next. Its usage is the same as step.
That’s all for now. As I come across other useful bits from GDB, I’ll certainly post them here. The items above have been lifesavers for me from time to time.