text to speech
Sat, 21 May 2011 02:44 categories: onelinerI'm planning to go biking and swimming again in the summer. What bugs me about it, is that during both activities I can't do much more than just that. I can't work on my projects or read a book. What I could do is listen to music or to a audio book. But what I would really like to do most is to continue reading my Perry Rhodan books. There are audio recordings of them but unfortunately those are edited and not a 1:1 copy of the books. But since my goal was to really read all of the books without leaving anything out this was unacceptable.
My idea was to see how far we are in terms of text to speech synthesizers. To increase the requirements I was looking for a good German synthesizer since the Perry Rhodan novels are written in German. After some search I found out that apparently a company called ivona is currently providing the best possible solution for my problem.
But of course there were additional issues. First, this company of course doesn't release their product for linux so I had two options: installing windows in qemu and running their software there or seeing if I could find out how I could find a new purpose for their online demo application.
While I was setting up an emulated Windows XP in the background I tried to figure out how the webfrontend of ivona.com was working. After a few hours of trial and error I got the solution which in contrast to my initial believe did not even require any reverse engineering of flash binaries.
string="Wenn die Testpiloten und Spezialisten des Linearkommandos von dem
neuartigen Kompensationskonverter zur Errichtung eines aus Sechsdimensional
übergeordneten Feldlinien bestehenden Kompensatorfeldes sprachen, dann gab sich
niemand mehr die Mühe, die zungenbrecherischen Begriffe exakt auszusprechen.";
mplayer `curl --data-urlencode "tresc=$string" --data synth=1
--data chk=\`echo -n $string | perl -pe 'use MIME::Base64;
$_=MIME::Base64::encode($_);tr/\+\/=/-_./;s/\n//g'\` --data voice=20
--header "X-Requested-With: XMLHttpRequest"
http://www.ivona.com/index.php | sed "s/.*loadAudioFile('\(.*\)').*/\1/"`
The X-Requested-With header is required and instead of 20, the voice POST parameter can become 21 for a female German voice. Other numbers are for other languages.
Interestingly enough, the 250 character limit seems to be only enforced on the client side. As one can see with the request above it is no problem at all to convert phrases with more characters as well. Instead the server will just stop converting at a random point. It will be around 23-26 seconds of speech or 180-200 KB. But maybe this is useful anyways for somebody.
dudle
Thu, 19 May 2011 09:33 categories: codeIn my quest to minimize the external third party services I rely on in my daily life, I stumbled over dudle which is an online poll system like doodle only better :)
The problems with giving your availability for a meeting or preferences over a subject to third party services like doodle are obviously the entailed privacy issues. Since I thought that doing stuff like a simple poll can also be handled by software running on my machine I firstly just wanted something like doodle running on one of my servers. This way, whenever me or anybody else would vote, they would no longer be depending on trusting someone like doodle but they would only have to trust me, who I own the server. (and hopefully they trust me more than a unknown money making instance)
But one can do even better than that! Benjamin Kellermann implemented an online poll platform where the availability or preferences of the participants are not even known by the server itself (nor by the other participants) and only when everybody voted a sum of all the votes can be calculated to decide for a timeslot or choice of subject. Hence, the user doesn't even have to trust the server he uses that runs dudle. All the server and the other participants get to see are encrypted availability vectors from which nobody can infer the original choice of options of the user. Only when combining all of them, a sum can be calculated which represents the overall availability of all users at a given time.
By its usage dudle is as simple as doodle. The only thing that might sound tedious is the private key each user has to take care of after his registration (which of course works without giving away any private detail like email) but this is greatly solved by using a bookmarklet to enter his private key into a poll field. I was showing the setup and what its advantages are to some non-CS people and was very pleased by the positive responses I got. A big kudos to Benjamin for his great work on this piece of software!
I am running thttpd on mister-muffin.de and by design it chroots into the www directory to increase security. A result of this is, that the only cgi scripts that can be run are statically compiled executables. Dudle is written in ruby and uses git as the database backend. Hence I had to setup a minimal chroot environment inside my www directory so that dynamically linked executables like git and ruby would work. I could've bothered with compiling both statically but was not up for the trouble (yet). A requirement of this environment was of course that it was very small and only included stuff that was necessary for git and ruby to run: dynamic libraries and ruby modules. Another requirement was that there were no setuid programs that could be used by an attacker to break out of the chroot environment by becoming root.
One way to do that would be to do a normal debootstrap including git and ruby and then manually removing everything that was not needed. It turned out that a normal debootstrap creates lots of overhead in retrieving lots of things that are not needed anyways and result in also having to delete lots of things afterwards, which is not worth the hassle.
My idea was to retrieve the git and ruby debian packages and all its dependencies and all the dependencies of those recursively and then just extract those packages into a directory. Since I didnt want to do the dependency resolution manually I let myself be inspired by multistrap and used apt to do that. Using apt for this task (as well as for multistrap) is possible because one can specify a custom target directory for apt in the commandline.
Since my final setup did not contain /bin/sh which ruby needed to call git, I had to patch dudle. I also proposed a way to get rid of the htdigest dependency to Benjamin and he included that and my /bin/sh patch into dudle. ☺
#!/bin/sh -ex
# check for fakeroot
if [ "$LOGNAME" = "root" ] \
|| [ "$USER" = "root" ] \
|| [ "$USERNAME" = "root" ] \
|| [ "$SUDO_COMMAND" != "" ] \
|| [ "$SUDO_USER" != "" ] \
|| [ "$SUDO_UID" != "" ] \
|| [ "$SUDO_GID" != "" ]; then
echo "don't run this script as root - there is no need to"
exit
fi
# modify these
ARCH="amd64"
DIST="squeeze"
MIRROR="http://127.0.0.1:3142/ftp.de.debian.org/debian"
DIRECTORY="`pwd`/debian-$DIST-$ARCH-ministrap"
# re-execute script in fakeroot
if [ "$FAKEROOTKEY" = "" ]; then
echo "re-executing script inside fakeroot"
fakeroot $0;
rsync -Phaze ssh $DIRECTORY/ mister-muffin.de:/var/www/
ssh mister-muffin.de "chown -R www-data:www-data /var/www/dudle.mister-muffin.de/"
exit
fi
# apt options
APT_OPTS="-y"
APT_OPTS=$APT_OPTS" -o Apt::Architecture=$ARCH"
APT_OPTS=$APT_OPTS" -o Dir::Etc::TrustedParts=$DIRECTORY/etc/apt/trusted.gpg.d"
APT_OPTS=$APT_OPTS" -o Dir::Etc::Trusted=$DIRECTORY/etc/apt/trusted.gpg"
APT_OPTS=$APT_OPTS" -o Apt::Get::AllowUnauthenticated=true"
APT_OPTS=$APT_OPTS" -o Apt::Get::Download-Only=true"
APT_OPTS=$APT_OPTS" -o Apt::Install-Recommends=false"
APT_OPTS=$APT_OPTS" -o Dir=$DIRECTORY/"
APT_OPTS=$APT_OPTS" -o Dir::Etc=$DIRECTORY/etc/apt/"
APT_OPTS=$APT_OPTS" -o Dir::Etc::SourceList=$DIRECTORY/etc/apt/sources.list"
APT_OPTS=$APT_OPTS" -o Dir::State=$DIRECTORY/var/lib/apt/"
APT_OPTS=$APT_OPTS" -o Dir::State::Status=$DIRECTORY/var/lib/dpkg/status"
APT_OPTS=$APT_OPTS" -o Dir::Cache=$DIRECTORY/var/cache/apt/"
# clean root directory
rm -rf $DIRECTORY
# initial setup for apt to work properly
mkdir -p $DIRECTORY
mkdir -p $DIRECTORY/etc/apt/
mkdir -p $DIRECTORY/etc/apt/sources.list.d/
mkdir -p $DIRECTORY/etc/apt/preferences.d/
mkdir -p $DIRECTORY/var/lib/apt/
mkdir -p $DIRECTORY/var/lib/apt/lists/partial/
mkdir -p $DIRECTORY/var/lib/dpkg/
mkdir -p $DIRECTORY/var/cache/apt/
# apt somehow needs this file to be present
touch $DIRECTORY/var/lib/dpkg/status
# fill sources.list
echo deb $MIRROR $DIST main > $DIRECTORY/etc/apt/sources.list
# update and install git and ruby
apt-get $APT_OPTS update
apt-get $APT_OPTS install ruby git-core libgettext-ruby1.8 libjson-ruby1.8
# unpack downloaded archives
for deb in $DIRECTORY/var/cache/apt/archives/*.deb; do
dpkg -x $deb $DIRECTORY
done
# delete obsolete directories
rm -rf $DIRECTORY/usr/share/
rm -rf $DIRECTORY/usr/lib/perl/
rm -rf $DIRECTORY/usr/lib/gconv/
rm -rf $DIRECTORY/usr/lib/git-core/
rm -rf $DIRECTORY/usr/sbin/
rm -rf $DIRECTORY/var/
rm -rf $DIRECTORY/bin/
rm -rf $DIRECTORY/sbin/
rm -rf $DIRECTORY/selinux/
rm -rf $DIRECTORY/etc/*
# delete all setuid programs
find $DIRECTORY -perm -4000 -delete
# delete all binaries except for "git" and "ruby"
find $DIRECTORY/usr/bin/ -type f -o -type l | egrep -v "ruby|git$" | xargs rm -rf
# git needs /etc/passwd otherwise git says: "You dont't exist, go away!"
cat > $DIRECTORY/etc/passwd << __END__
www-data:x:33:33:www-data:/var/www:/bin/sh
__END__
# dont forget to create /tmp directory for dudle
mkdir -m 777 $DIRECTORY/tmp
# get latest dudle
bzr branch https://dudle.inf.tu-dresden.de/unstable/ $DIRECTORY/dudle.mister-muffin.de
( cd $DIRECTORY/dudle.mister-muffin.de; make; )
bzr branch https://dudle.inf.tu-dresden.de/unstable/extensions/dc-net/ $DIRECTORY/dudle.mister-muffin.de/extensions/dc-net/
( cd $DIRECTORY/dudle.mister-muffin.de/extensions/dc-net/; make; )
# fix shebang
find $DIRECTORY/dudle.mister-muffin.de/ -type f -regex ".*\.cgi\|.*\.rb" \
| xargs sed -i 's/#!\/usr\/bin\/env ruby/#!\/usr\/bin\/ruby/'
The above code will compile a minimal chroot environment, delete everything that is not needed, fetch dudle and deploy it to my server. The comments in the code should explain everything.
rxvt-unicode font size
Wed, 11 May 2011 16:03 categories: blogIt is simple to change the font size of rxvt-unicode via an entry in ~/.Xdefaults:
URxvt*font: xft:DejaVu Sans Mono-8
But it is also possible to change the font on the fly via this escape sequence:
printf '\33]50;%s\007' "xft:DejaVu Sans Mono-8"
While playing around with that I also found out that it is very simple to change the font of any other terminal you know the PID of, by just doing something like:
printf '\33]50;%s\007' "xft:DejaVu Sans Mono-8" > /proc/$pid/fd/0
where $pid is the process id of the shell you are running.
putting debian on the notion ink adam
Sun, 01 May 2011 01:01 categories: debianIntroduction
I recently put Debian Sid on my Notion Ink Adam and since I wouldnt have managed to do that alone I want to thank the guys in ##adamroot on freenode - especially RaYmAn who initially assembled a boot.img to put ubuntu on the adam and also wrote the hack to use the multitouch touchscreen as singletouch. IntuitiveNipple was also very helpful and you should check out his great personal wiki.
Quick Solution
Just download my pre-assembled boot.img
You will flash it to the adam from your linux host with a proprietary tool called nvflash that you can grab here for your specific version of adam:
unzip it and find out the partition number you want to flash the image to. For each invocation of nvflash you have to put your adam into apx mode recovery by holding down the volume down button and the power button until the orange charge LED and the red CPU LED light up.
./nvflash --bl bootloader.bin --getpartitiontable parts.cfg
In parts.cfg the SOS partition is the recovery partition (most likely partition 8) and LNX is the boot partition (most likely partition 9). Flashing boot.img to the recovery partition will give dual boot capabilities but destroy the recovery image. Flashing it to the boot partition has the advantage that it boots per default. I flashed it to the boot partition which was partition 9 for me.
./nvflash --bl bootloader.bin --download 9 boot.img
Once that finished the adam can be switched off an on again. The adam will now boot some /sbin/init from the first partition on an SD card.
I prepared a debian rootfs you can just extract to your SD. It comes with e17 and you best select illume in the welcome screen: debian-sid-multistrap.tar.xz
The rootfs also includes the proprietary broadcom module and firmware for the bcm4329: modules.tar.gz
The rootfs was created using this script: rootstock.sh
Modifying boot.img
If you want to make changes to the boot.img (specifically recompile the kernel) it works the following:
To extract and create the boot.img use the android BootTools (local copy)
git clone https://github.com/AndroidRoot/BootTools.git
cd BootTools
make
With this tool you can already unpack the boot.img and look what's inside. The boot.img will unpack into a ramdisk and the kernel and a textfile that specifies additional parameters like the kernel cmdline arguments. The ramdisk can be examined and changed as usual with cpio.
./BootTools/bootunpack boot.img
gunzip boot.img-ramdisk.cpio.gz
mkdir ramdisk
cd ramdisk
cpio -id < ../boot.img-ramdisk.cpio
Ramdisk
The ramdisk is good for two things: work around the setfont bug and introduce a delay before the root partition from the SD is mounted. I tried to boot without a ramdisk, using the rootdelay kernel commandline option but it didnt work. I have no idea what is going wrong due to the setfont bug. This bug means that the framebuffer console will only output anything else than the initial blank, black screen when a KDFONTOP ioctl is done to one of the ttys.
The ramdisk contains an /init that mounts the root partition from the SD card after a delay of three seconds or falls back to a shell if there is no /sbin/init on it and statically compiled busybox and setfont. Setfont is a program that will do the ioctl and load the font Lat15-Fixed16 to the tty specified by its first command line argument. The sourcecode is included in the ramdisk itself as setfont.c.gz and can also be downloaded here: setfont.c.
Cross compiling a kernel for ARM
To compile the kernel you need a cross build toolchain that is easiest installed via the emdebian repository.
apt-get install emdebian-archive-keyring
echo deb http://www.emdebian.org/debian/ squeeze main >> /etc/apt/sources.list
apt-get update
apt-get install gcc-4.4-arm-linux-gnueabi
clone the notionink kernel sources:
git clone https://github.com/notionink/adam-kernel.git
put my config into it
curl http://mister-muffin.de/adam/config > adam-kernel/.config
the following patch will change the multitouch driver into a singletouch one that is supported by the current Xorg evdev driver and will also add the accept4 system call that is needed for udev >= 168.
cd adam-kernel
curl http://mister-muffin.de/adam/kernel.diff | git apply
build the thing
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j5
create the boot.img from the new kernel and the ramdisk
./BootTools/mkbootimg --kernel adam-kernel/arch/arm/boot/zImage \
--ramdisk linux_boot.img-ramdisk.cpio.gz \
--cmdline 'mem=256M@0M nvmem=256M@256M mem=512M@512M vmalloc=384M video=tegra'\
'fb console=tty0,115200n8 usbcore.old_scheme_first=1 cpuid=200102 devicetype='\
'1002 tegraboot=nand mtdparts=tegra_nand:16384K@9984K(misc),16384K@26880K(rec'\
'overy),16384K@43776K(boot),204800K@60672K(system),781952K@266112K(cache) roo'\
't=/dev/mmcblk0p1 init=/sbin/init debug' --output boot_new.img
and upload it to the device as shown above
Device Specific Things
Input Devices
- /dev/input/event0 - hardware buttons
- /dev/input/event1 - capacitative buttons
- /dev/input/event2 - touchscreen
- /dev/input/event5 - accelerometer
the pixelqi display mode can be set with
/sys/devices/platform/pixel_qi_screen_ctrl/state
accelerometer is enabled with
/sys/devices/platform/accelerometer/enable
WWAN
the wwan card is a Ericsson F3307 and provides a cdc ethernet interface
chat -V ABORT "ERROR\r\n" "" \
"AT+CFUN=1" "OK\r\n" \
"AT+CGDCONT=1,"IP","$APN" "OK\r\n" \
"AT*ENAP=1,1" "OK\r\n" > /dev/ttyACM0 < /dev/ttyACM0
dhclient -v usb1
(notice that, depending on your provider you might not need to specify the APN - at least here in germany I didnt yet encounter a provider where you had to)
WLAN
wlan works as usual via wpa_supplicant
GPS
gps is /dev/ttyHS3 and outputs NMEA
Battery
/sys/devices/platform/smba10xx_battery/power_supply/battery/capacity
Not working
- alsa (no clue what's going on)
- camera (no v4l2 device in /dev)
- bluetooth (part of bcm wireless)
- fm-transceiver (part of bcm wireless)
- compass (needs memsic daemon running)
- cpu scaling (needs nvidia daemon)
mandelbrot
Wed, 20 Apr 2011 11:29 categories: blogA very nice minimal code size implementation of the Mandelbrot algorithm by Ken Peril I found here
main(k){float i,j,r,x,y=-16;while(puts(""),y++<15)for(x
=0;x++<84;putchar(" .:-;!/>)|&IH%*#"[k&15]))for(i=k=r=0;
j=r*r-i*i-2+x/25,i=2*r*i+y/10,j*j+i*i<11&&k++<111;r=j);}
It is very interesting to see what techniques where applied to minimize the amount of source code bytes. When I tried out the code, not knowing what pattern it would output I was very find to see a Mandelbrot pattern printed to my terminal :)
The code translates to this which outputs the exact same bytes:
#include <stdio.h>
int main(int argc, char **argv)
{
int k,x,y;
float i,j,r;
char *chars;
chars = " .:-;!/>)|&IH%*#";
for(y=-15;y<16;y++) {
puts("");
for(x=1;x<=84;x++) {
i=0;
r=0;
for(k=0;k<112;k++) {
j=r*r-i*i-2+x/25.0f;
i=2*r*i+y/10.0f;
if (j*j+i*i>=11) {
break;
}
r=j;
}
putchar(chars[k&15]);
}
}
puts("");
return 0;
}
y and x iterate over rows and colums on the terminal. They are scaled by 1/25 and 1/10 respectively. 112 is the maximum iteration number and only has the requirement of being divisible by 16 (the number of characters for the ascii art). A difference to the original algorithm is the -2 in calculating j but this is just to shift the x values to the right on output. Alternatively one could also just iterate x eg from -50 to 34 instead from 1 to 84 which would give a similar output. To compensate for the shift and to also draw points close to the border 11 was chosen as a good stopping criterion for beautiful output. Normally one would check for jj+ii being less than or equal to 4 but this would mean that for border points the algorithm would terminate in the 1st iteration, painting those points the same as the ones that do not lie in the Mandelbrot set.