Saturday, December 31, 2011

Monday, December 26, 2011

youtube upload #4

This time, it is Korean heavy metal.

Kim Kyungho, "Judgement Day"

Thursday, October 27, 2011

Hard to keep up the blog, thanks to twitter, G+, facebook.

Thanks to those easy to use social media, I forget my blogs more often.  I hope to get something interesting to post.  These days, I don't have any specific subjects.  Other than work and music, I don't run my side projects and researches.

Maybe I can put my "type slow" practice.  I definitely get benefit from that practice.

Thursday, September 8, 2011

My third youtube upload.

Tuesday, August 2, 2011

Classical piece

Uploaded Bach BWV 997, on clean tone with my practice guitar.
Classical sounds lovely, but following music is different from playing, even in technical perspective.

Friday, June 24, 2011

Code browsing (ETAGS vs. Eclipse)

I am an Emacs enthusiast, and I always try to resolve my problems in Emacs.
However, today, I gave up Etags. I don't compile codes on Eclipse, yet. For code browsing capability, Eclipse is far better and intuitive. I can't clearly distinguish/categorize properties of "This is better on Emacs" vs "This is better on Eclipse". Truely, editing task is better on Emacs, but, code browsing is better on Eclipse.

The nature of code browsing is different from actual coding.
When writing a project, the author of the project knows details up front, such as where to look, how these variables/functions are used. When modifying someone else's project, initially readers don't have a clue. The readers will collect details by asking many questions (in browsing terms, querying symbol/usage chain/see declaration/see definition/ etc... ). On emacs, interface is too flat. I use Etags often, but still I have to look up, though. On Eclipse, interface is hierarchic, and grouped based on situation.

I can't describe better than this. Sorry for rough explaining. At this point, I remember that someone mentioned "Eclipse vs. Emacs is facing the same argument of Emacs vs. Vi when Emacs got attentions first time. One example is that "Eclipse is heavy". Emacs was heavy when it appeared for the first time.

One nice tip, to browse through history, use ALT-left and ALT-right.

Tuesday, May 31, 2011

Metronome for Linux in Python

I changed my metronome.c in python to work with Windows. ( Initially, I made a mistake which errored in Windows.) I didn't distinguish binary/text mode in Windows, which doesn't matter in Linux. After adding sys.platform condition, it works, but looks a little clumsy.

To use this,
$ python [sample_file] [bpm] [duration in sec]

For example, this command will generate "a.wav" which has 120 BPM beat for 15 sec. s3.wav is a simple beep wav in 44100 wav encode.
$ python s3.wav 120 15

Here is the code:
#!/usr/bin/env python

import os
import sys
import struct

empty_sound = struct.pack('bbbbbbbb', *( 4,0,0,0,6,0,6,0 ))

class WavHeader(object):
def __init__(self, rawdata):
self.tup = struct.unpack("iiiiihhiihhii", rawdata)
self.chunk_id = self.tup[0]
self.chunk_sz = self.tup[1]
self.format = self.tup[2]
self.sub_chunk1_id = self.tup[3]
self.sub_chunk1_sz = self.tup[4]
self.audio_format = self.tup[5]
self.num_channel = self.tup[6]
self.sample_rate = self.tup[7]
self.byte_rate = self.tup[8]
self.block_align = self.tup[9]
self.bits_per_sample = self.tup[10]
self.sub_chunk2_id = self.tup[11]
self.sub_chunk2_sz = self.tup[12]

def pack(self):
return struct.pack("iiiiihhiihhii", self.chunk_id, self.chunk_sz,
self.format , self.sub_chunk1_id,
self.sub_chunk1_sz , self.audio_format,
self.num_channel , self.sample_rate ,
self.byte_rate , self.block_align ,
self.bits_per_sample, self.sub_chunk2_id,
self.sub_chunk2_sz )

ONE_SEC = 88200
def bytes_for_beat(bpm):
ratio = bpm/60.0
bytes_per_beep = ONE_SEC / ratio
return int(bytes_per_beep)

def main():
sample_fname = sys.argv[1]
tempo = int(sys.argv[2])
if tempo < 40:
print >> sys.stderr, "Invalid tempo: Make it between 40 - MAX"
print >> sys.stderr, " * longer the sample length, smaller the MAX"
dura = int(sys.argv[3])
if dura <= 0:
print >> sys.stderr, "Invalid duration: Make it greater than 0"

# Reading sample header
if sys.platform == 'win32':
rd = open(sample_fname, "rb")
rd = open(sample_fname, "r")
sample_hdr = WavHeader(
sample_data =

# Generating Beat data as WAV, storing temp file 't.wav'
if sys.platform == 'win32':
bdata = open("t.wav", "wb")
bdata = open("t.wav", "w")
tot_beats = dura * (tempo/60.0);
bps = bytes_for_beat(tempo);
tot_bytes = 0;
for i in range( int(tot_beats)):
bdata.write( sample_data )
tot_bytes += sample_hdr.sub_chunk2_sz;
for j in range( (bps - sample_hdr.sub_chunk2_sz)/8):
bdata.write( empty_sound )
tot_bytes += len(empty_sound)

# Overwrite new size, and Generate output wav file 'a.wav'
sample_hdr.sub_chunk2_sz = tot_bytes
if sys.platform == 'win32':
outf = open("a.wav", 'wb')
outf = open("a.wav", 'w')
outf.write( sample_hdr.pack() )
if sys.platform == 'win32':
outf.write( open('t.wav', 'rb').read() )
outf.write( open('t.wav').read() )

if __name__ == '__main__':

Sunday, May 29, 2011

Metronome for Linux

A solution for "Metoronome" is a very simple algorithm

 def metronome(bpm, how_long):  
while how_long > 0:
time.sleep( 60.0 / bpm )
how_long -= 60.0/bpm

Unfortunately, this wouldn't work on regular OS like Linux or Windows on PC, since they are not real time OS. To make the matter worse, sleep() operation will definitely context switch out the process, and coming back will not be in consistent interval.

I needed a metronome. I knew that there are softwares doing "Metronome", mostly commercial.

So, dig through, and found one open source solution (open metronome), written in MFC. Since my computer for music is Linux, I just read and learned its brilliant idea. It generates WAV file for beeping. I wrote a program, doing so.

 #include <stdio.h>  
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
char empty_sound[8] = { 4, 0, 0, 0, 6, 0, 6, 0 };
struct wav_header {
// "RIFF" chunk descriptor
int32_t chunk_id;
int32_t chunk_sz;
int32_t format;
// "fmt (header)" sub-chunk
int32_t sub_chunk1_id;
int32_t sub_chunk1_sz;
int16_t audio_format;
int16_t num_channel;
int32_t sample_rate;
int32_t byte_rate;
int16_t block_align;
int16_t bits_per_sample;
// "data (easily, music)" sub-chunk
int32_t sub_chunk2_id;
int32_t sub_chunk2_sz;
char *data;
#define ONE_SEC 88200 // bytes
static void print_header(struct wav_header *hdr)
printf("(0) chunk id : %x\n", hdr->chunk_id);
printf("(4) chunk size : %d\n", hdr->chunk_sz);
printf("(8) format : %x\n\n", hdr->format);
printf("(12) sub chunk1 id : %d\n", hdr->sub_chunk1_id);
printf("(16) sub chunk1 size : %d\n", hdr->sub_chunk1_sz);
printf("(20) audio format : %d\n", hdr->audio_format);
printf("(22) num channels : %d\n", hdr->num_channel);
printf("(24) sample rate : %d\n", hdr->sample_rate);
printf("(28) byte rate : %d\n", hdr->byte_rate);
printf("(32) block align : %d\n", hdr->block_align);
printf("(34) bits per sample : %d\n\n", hdr->bits_per_sample);
printf("(36) sub chunk2 id : %d\n", hdr->sub_chunk2_id);
printf("(40) sub chunk2 size : %d\n", hdr->sub_chunk2_sz);
printf("(44 -- ) DATA\n\n");
static int bytes_for_sec(int bpm)
float ratio = bpm/60.0;
float bytes_per_beep = ONE_SEC / ratio;
return (int)bytes_per_beep;
int main(int argc, char **argv)
char *sample_fname;
int tempo, dura, bps;
int rfd; // Sample file descriptor
int wfd; // Output file descriptor
int rc, i, j, tot_beats;
char buf[512 + 1]; // Sample hdr buffer
char *sample_buf, *ptr;
struct wav_header *hdr;
struct wav_header new_hdr;
if (argc < 3) {
printf("USAGE: %s <sample_wav> <tempo in BPM> <duration in sec>\n", argv[0] );
printf(" * sample_wav must be aligned by sample. Random clip of data may make a noise.\n");
printf(" example: $ %s s3.wav 120 60\n", argv[0]);
printf(" This will make an output of 'a.wav', using s3.wav as sample, 120 bps for 60sec.\n");
sample_fname = argv[1];
tempo = atoi(argv[2]);
if (tempo < 40) {
printf("Invalid tempo: Make it between 40 - MAX, which is the fastest from sample\n");
dura = atoi(argv[3]);
if (dura == 0) {
printf("Invalid duration: Make it greater than 0.\n");
rfd = open(sample_fname, O_RDONLY);
rc = read(rfd, buf, 44);
if (rc < 0) {
perror("Sample read error\n");
hdr = (struct wav_header *)buf;
if ( NULL == (sample_buf = malloc( hdr->sub_chunk2_sz )) ) {
perror("Mem alloc failed (1)\n");
// copying sample data
ptr = sample_buf;
while ( 0 < (rc = read(rfd, ptr, 512)) ) {
ptr += rc;
wfd = open("t.wav" , O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (wfd < 0) {
perror("Error opening write file");
tot_beats = dura * (tempo/60.0);
bps = bytes_for_sec(tempo);
int tot_bytes = 0;
for (i =0; i<tot_beats; ++i) {
write(wfd, sample_buf, hdr->sub_chunk2_sz);
tot_bytes += hdr->sub_chunk2_sz;
for (j = 0; j< (bps - hdr->sub_chunk2_sz)/8; ++j) {
write(wfd, empty_sound, 8);
tot_bytes += 8;
memcpy(&new_hdr, hdr, 44);
wfd = open("h.wav", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
write(wfd, &new_hdr, 44);
system("/bin/cat h.wav t.wav > a.wav");
return 0;

Finally, I generated 30 sec of each speed (40, 44, 48, .... 208), and converted them into mp3. For example, 160 bpm wav (160.wav) is converted to 160.mp3 in 128 bit encoding.

 $ lame -h -b 128  160.wav  160.mp3

Now, if I need 5 min of 160 bpm, I just feed this 10 times in mpg123.

My favorite application of this was "speed trainer." For example, made 30 secs of 160, 161, 162, 163, 164 bpm and played it.

$ mpg123 16[0-4].mp3

Or making a 15 minute mp3 beat file isn't bad. Roughly 1 meg for 1 min, so 15 min is less than 15 meg byte. If it is encoded 64bit, the size will be even smaller.

Friday, February 11, 2011

First Youtube upload

Yesterday, I stayed home. Enjoyed a relaxed day, with a little excuse of my son's school meeting. During 1 spare hour before the meeting, I made this. I always wish that I have more time to practice my guitar.

Monday, January 17, 2011

python unittest skipping test.

I just found this feature, and I love it.