Last update Mon Aug 22 21:57:50 2011
www.walterbright.com
Home

Products
· D Programming Language
· D Compiler
· C/C++ Compilers
· DMDScript Compilers
· Empire

Other
· Vintage Computer Magazines
· Vintage PC Magazines
· Vintage Magazines
· Garage Sale
· Audiotron

Walter's Turtlebeach Auditron

The Turtlebeach Audiotron is an appliance that streams music from internet radio stations or a shared folder on your computer to your stereo. It's been abandoned by Turtlebeach, which is a shame as it's still the best streamer out there. I like it so much I've got three of them. What's great about the Audiotron:

  • Inexpensive
  • Low power consumption
  • High quality sound
  • Will play mp3, wav, or wma files
  • Does not require any software to be installed on your server machine, just a shared directory where the music files are placed
  • Does not interfere with using your server machine
  • No fan, no spinning disk, no noise

The Audiotron still has a dedicated following, and I've done some things to contribute.

Here's my Output.txt which is a list of radio stations in the Audiotron format. Here is the same data in a readable format.

The Audiotron format is a pain to work with, so I've written a couple programs to read and write it. The first is a program written in the D programming language to convert the list of radio stations in the file to a readable and editable format:

import std.stdio;
import std.file;

int main(string[] args)
{
    string filename;

    foreach (arg; args)
    {
	filename = arg;
    }

    string input = cast(string)std.file.read(filename);
    dump(input);
    return 0;
}

void dump(string s)
{   int i = 0;
    int indent = 0;

    char get()
    {
	if (i == s.length)
	    throw new Exception("done");
	return s[i++];
    }

    void tag(char c)
    {	string stag;

	stag ~= c;
	while (1)
	{
	    auto d = get();
	    if (d == '>')
		break;
	    stag ~= d;
	}

	foreach (i; 0 .. indent)
	    write(' ');
	writef("%s=", stag);
	bool any = true;

	while (1)
	{   auto d = get();

	    if (d == '<')
	    {	d = get();
		if (d == '/')
		{
		    while (get() != '>')
		    { }
		    if (any)
			writeln();
		    break;
		}
		else
		{
		    if (any)
			writeln();
		    indent++;
		    tag(d);
		    indent--;
		    any = false;
		}
	    }
	    else
	    {	write(d);
		any = true;
	    }
	}
    }

    try
    {
	while (1)
	{   auto c = get();

	    if (c == '<')
		tag(get());
	    else
		write(c);	
	}
    }
    catch (Exception e)
    {
    }
}

And a corresponding program to convert the output of the former into to be loaded back into the Audiotron:

import std.stdio;
import std.file;
import std.string;

int main(string[] args)
{
    string infilename;
    string outfilename;

    foreach (arg; args[1..$])
    {
	if (!infilename)
	    infilename = arg;
	else if (!outfilename)
	    outfilename = arg;
    }

    string input = cast(string)std.file.read(infilename);
    string output = process(input);
    std.file.write(outfilename, output);
    return 0;
}

string process(string s)
{
    struct Tag
    {
	Tag* parent;
	Tag* sibling;
	Tag* child;
	string key;
	string value;
    }

    Tag* ptags;
    Tag* pstart;
    int m = 0;
    int stationcount = 0;

    auto lines = splitlines(s);
    foreach (line; lines)
    {
	int n;
	while (line.length && line[0] == ' ')
	{
	    line = line[1..$];
	    n++;
	}
	auto t = new Tag;
	auto i = indexOf(line, '=');
	if (i == -1)
	    continue;
	t.key = line[0..i];
	if (t.key == "station")
	    stationcount++;
	t.value = line[i + 1 .. $];
	if (!ptags)
	{
	    ptags = t;
	    pstart = t;
	    continue;
	}
	if (n == m)
	{
	    ptags.sibling = t;
	    t.parent = ptags.parent;
	}
	else if (n < m)
	{
	    ptags.parent.sibling = t;
	    t.parent = ptags.parent.parent;
	    m = n;
	}
	else if (n > m)
	{
	    ptags.child = t;
	    t.parent = ptags;
	    m = n;
	}
	ptags = t;
    }

    // Compute total length
    int totallength;
    Tag* tlength;

    void process(Tag *t)
    {
	while (t)
	{
	    if (t.key == "length")
	    {
		tlength = t;
		t.value = "";
	    }
	    if (t.key == "stationcount")
	    {
		t.value = std.string.format("%d", stationcount);
	    }
	    totallength += 1 + t.key.length + 1;
	    totallength += t.value.length;
	    process(t.child);
	    totallength += 2 + t.key.length + 1;
	    t = t.sibling;
	}
    }

    process(pstart);
    if (tlength)
    {
	string len;
	int i = totallength;
	while (1)
	{
	    len = std.string.format("%d", i);
	    if (totallength + len.length == i)
		break;
	    i = totallength + len.length;
	}
	tlength.value = len;
    }

    string r;

    void append(Tag* t)
    {
	while (t)
	{
	    r ~= "<" ~ t.key ~ ">";
	    r ~= t.value;
	    append(t.child);
	    r ~= "</" ~ t.key ~ ">";
	    t = t.sibling;
	}
    }

    append(pstart);
    r ~= "\r\n";

    return r;
}