Search this site


[prev]  Page 4 of 4

Metadata

Articles

Projects

Presentations

(?:Perl|Pretty)i?\sMusic\sPlayer and Tic

So I've been busy the past two days working furiously on both tic and pimp. Pimp has been resurrected.

It previously was a silly ncurses frontend to various media players (mplayer, mpg123, xmms, etc). It worked for the most part, but was limited by the dependency on 3rd party programs to run and die on whim. I needed to play mp3s and such from within perl to make this work the way I wanted.

Enter Audio::Ao and Audio::Mad. The former is an interface to libao, a library that talks dirty with your sound devices. The latter is an interface to libmad, a library that decodes mpeg audio decoding.

Right now, I've got a player/server set running. It supports client connections (telnet to port 3242) which supports the following:
   * play/stop/next/pause commands
   * info command, tells you what's playing
   * set command, lets you change the ID3 tag of the currently-playing song.

Everything works so far pretty well. Current problems are:
   * reads the entire mp3 initially, then tosses it to mad. This should be addressed by slowly reading the file (buffered reading) - see below
   * no playlist support! *cry*

So, I decided I had a good idea as to how to read slowly over time, this went along the lines of:
1) Read X bytes, throw it over to Audio::Mad
2) After the stream's empty ($frame->decode($stream) returns -1), repeat step 1

This works, kinda... What happens is you get effective streaming, however there are blips and errors in the sound output. Why, you ask? Because I'm reading a specific number of bytes and completely ignoring the size of each frame in the mp3. What's a frame? Mp3's are split into frames, much like video. If you take half of the data out of a frame, it won't sound right - much as if you were to take half of the data from a video frame, it wouldn't look right.
I have an idea how to read the proper number of bytes so that I always end at the end of a frame, but this will only work for fixed bitrate mp3s; VBR will be another challenge unto itself, but that's a problem to be solved another day.

I don't have streaming incorporated into PiMP yet, but I do have a demo script that does it without concern for the mp3 frames - It's over there on the right.


I also picked up work again on tic, my aim client. It's back up to good 'n working condition. I fixed up a few of the bugs (erroneous output, etc) but found a few more (hurray!). Anyhoo, tab completion now works better.
I'll release tic soon, only a few more features need to be added.

Array enumeration in perl

I got bored and thought this atleast marginally useful:

my @foo = qw(just another perl monkey);
my $x = 0;
print join("\n",map { $x++ . ": $_" } @foo);

The output is:

0: just
1: another
2: perl
3: monkey
If you don't know how to use map() then learn, it makes doing large operations on hashes or arrays brutally simple.

tic update.

tic is almost ready for the real world, I added a *ton* of features to it today/yesterday (eh, I'm still awake and it's 8am...)

- Tab completion
- Aliases
- Logging
- Timestamps
- Customizable output

It also supports minimal line editing. That is, you can use the arrow keys to cursor around within the input line and edit as you please.

tik, tac... tic!

So I got bored and started working on an aim client written, you guessed it, in perl. It's console-based and will eventually be very similar to tac, but better. Eventually once I get some bugs and basic features nailed out I'm going to attempt to write both Gtk2 and Curses::UI front-ends for it.

Right now it supports the most basic of features including logging in, messaging, receiving messages, get user info, and aliases. Aliases can be nested, that is you can do:

/alias foo /msg psikronic
/alias bar /foo Hello!
and then call /bar and it will call /foo Hello! which will in-turn call /msg psikronic Hello!. Huzzah.

I also added a /default command which will set the default target to send messages to. You can also do ; some message text to message the person who messaged you most recently (prefix the line with semi-colon). You can also do /default ; to set the default to the person who most recently messaged you.

Whew! More updates.

More mason madness happening. Debugged some things I found wrong with, well, everything. I also *finally* added commenting. Thread support was also added (yay recursion).
Feel free to, well, post comments!

Mason rocks me sideways...

After browsing through the online Mason book (which is free!) I set to work on converting this site from PHP. Oh man is it simple. Doing things in perl is often much simpler than a similar solution in PHP, so this makes me happy.

PHP -> perl HTML::Mason

I'm going to have a go learning HTML::Mason and in the process of doing so will convert this entire site to mason. I'll be posting updates and neat things I learn here, stay tuned...

perl's CGI module

I have overlooked some of the coolest parts of perl's CGI module for the longest time - I've known it can generate HTML but I've always shrugged it off as thinking it can't do what i want it to, i couldn't have been more wrong.

What I'm specifically referring to is form generation. The rest of the HTML generating methods are useless to me (like the h1() method), but I'll focus on the cool form generating ones.
Why are they cool? They simplify your life and make code cleaner - For instance, lets say oyu have this fugly line of code:

$poop = "email_address";
$default = "[email protected]"
print 'Email address: <input type="text" name="' . $poop .  
      '" value="' . $default . '"><br>';

This prints out happy html that looks like this:
Email address:

Now, that print line is pretty damn ugly, but we can easily make it pretty once more by doing:
use CGI qw/:standard/;
print "Email Address: " . textfield($poop, $default) . "<br>";

And the output is:
Email Address:

Neat? Yeah.. What next? More neatness! You have an array you want to turn into a group of checkboxes...

use CGI qw/:standard/;
@foo = ("check1", "foo", "bar", "baz", "poopie", "hello", "Coke!", "Pepsi?");
@def = ("foo", "bar", "poopie");
print 'Checkbox listing:<br>';
print checkbox_group(-name => "options", -values => \@foo, 
                     -columns => 3, -defaults => \@def);
print '<br>';
What does this look like?

Checkbox listing:
check1bazCoke!
foopoopiePepsi?
barhello