Thursday, May 29, 2014

Batch Encoding mp4 Videos to Wav (Audio CD format) in Windows

At times, you want to listen to your favorite tunes while driving in congested roads or for extended period of time between cities. The problem is, your car's audio only support Audio CD. This dictates you to convert your favorite tunes to Audio CD. Moreover, you don't have enough time to convert them one by one. Enter the "batch encoding" realm..
Simply put, batch encoding is the process of encoding multiple files in one go. To do that, we use shell script, or batch file in Windows. Because most of my favorite tunes are mp4 videos, my batch encoding script converts those mp4s into wav files. I used VLC to carry out the encoding and I'm using a powershell script to automate the encoding into batch encoding. This is the powershell script that I use:
$outputExtension = ".wav"
$bitrate = 128
$channels = 2

foreach($inputFile in get-childitem -Filter *.mp4)
{ 
  $outputFileName = [System.IO.Path]::GetFileNameWithoutExtension($inputFile.FullName) + $outputExtension;
  $outputFileName = [System.IO.Path]::Combine($inputFile.DirectoryName, $outputFileName);
  
  echo "Output filename: $outputFileName" 
    
  $programFiles = ${env:ProgramFiles(x86)};
  echo "Program Files: $programFiles"
  
  if($programFiles -eq $null) { $programFiles = $env:ProgramFiles; }
  
  $processName = $programFiles + "\VideoLAN\VLC\vlc.exe"
  echo "processName: $processName"
  
  $processArgs = "-I dummy -vvv `"$($inputFile.FullName)`" --sout=#transcode{acodec=`"s16l`",ab=`"$bitrate`",`"channels=$channels`"}:standard{access=`"file`",mux=`"wav`",dst=`"$outputFileName`"} vlc://quit"

  echo "processArgs: $processArgs"
  
  start-process $processName $processArgs -wait

  }
It's not that complicated. It's a slightly modified script from VLC wiki (https://wiki.videolan.org/How_to_Batch_Encode/). There was one hiccup though because by default poweshell doesn't permit script execution. Therefore, I have to run powershell as administrator and then modify the execution policy to unrestricted like so:
Windows PowerShell
Copyright (C) 2013 Microsoft Corporation. All rights reserved.

PS C:\Users\zzz> Set-ExecutionPolicy Unrestricted
Anyway, the powershell script above assumes that you placed all of the mp4 in the current directory (directory where the powershell script located). The batch encoding result will be located in the current directory as well.
Now, to create audio CD, you'll need the application to burn the wav files into audio CD. I'm using cdrecord in Linux to do this because for some reason, the only machine with CD/DVD writer that I have is running Linux. You can use your favorite CD authoring application to do this.

Happy Encoding!

Tuesday, May 20, 2014

AS400 Programming Tutorial

After searching the web for sometime on AS400 RPG-ILE tutorial, I found the most newbie friendly tutorial over at: http://www.letsas400.com/ile_rpg_iv/index.php. RPG-ILE is also known as RPG IV or RPG400. I'm not yet quite familiar with the AS400 hardware but it seems it's a Power machine. The OS400 on the other hand is a specific OS developed by IBM for the AS400 hardware.

IBM provides a more comprehensive tutorial in the ILE RPG Programmer's Guide. However, to save time, I prefer to read an overview on the language itself and the tutorial in the link above is just what I need to bootstrap learning the ILE RPG. I hope this post is of some use for those starting with ILE RPG on IBM Series i machines, like me. Happy coding :)

Monday, May 12, 2014

Preventing Pointer Aliasing in C (for Scientific Computing Optimization Purposes)

The issue of pointer aliasing in C for those working with Scientific Computing code is probably a familiar issue. Pointer aliasing happens when more than one pointer refers to the same or overlapping memory region. This hurts performance in Scientific Computing code written in C. Pointer aliasing is probably the biggest issue which hurts performance of Scientific Computing code written in C compared to those written in Fortran. However, as of C99 standard, pointer aliasing can be "disabled" via the __restrict__ keyword. Most mainline C/C++ compilers supports this keyword. These are the relevant links for various mainline compilers/toolchains:

Sunday, May 11, 2014

Raspberry Pi 3G-Ethernet Router

In this post, I'm going to explain a DIY 3G-ethernet router based on Raspberry Pi. The configuration of this DIY "router" is simple:

Internet <--> USB 3G modem <-->powered USB hub <--> Raspberry Pi <--> Ethernet <--> user machine (PC/Laptop)

The purpose of this kind of router varied, depending on your needs. However, I have a very specific need in one of my setup where providing Internet connection directly from the 3G modem is not possible and only Ethernet interface can be used by the user (physical/virtual) machine.

These are what you need:
  1. A Raspberry Pi (I'm using the B revision), with Raspbian distro.
  2. A powered USB hub. This is required because most USB 3G modems are power hungry and cannot be operated reliably only via the USB connector on the Pi.
  3. A USB 3G modem. Use whatever you have, hopefully Raspbian kernel already support it. I'm using Huawei E153 USB modem which is rather not so friendly in terms of operation in Raspbian, but it works reliably nonetheless, once you know how to "switch" it into modem "mode".
  4. Ethernet cable.
  5. A user machine to test the interconnection.
  6. Internet/data plan subscription to your mobile operator or whatever works for you.
Let's start with installing the software needed for the USB 3G modem to work on Raspbian. I'm basically using the steps mentioned at The Fan Club, but modify them a bit because I'm not using wvdial. These are my modified steps:
  1. Update your Raspbian with "sudo apt-get update"
  2. Install the needed packages with "sudo apt-get install ppp usb-modeswitch"
  3. Configure the pppd configuration file according to your needs.
Now, the software installation steps to setup the DHCP server and Network Address Translation (NAT) are mostly similar to the one at Adafruit: https://learn.adafruit.com/setting-up-a-raspberry-pi-as-a-wifi-access-point/install-software, except that you should remember that the "outgoing" interface in our case is eth0, instead of wlan0 and the "incoming" interface is ppp0 instead of eth0. Therefore, I believe you can adjust the steps accordingly. Also, I found that Adafruit step to make the NAT setting permanent is not working for me. I have to modify the configuration line in /etc/network/interfaces to:

pre-up iptables-restore < /etc/iptables.ipv4.nat

instead of the one explained by Adafruit to make the NAT work permanently across reboots and shutdowns.

The next step is to connect to the Internet. These are my steps:
  1. Power on the Raspberry Pi.
  2. Unplug the 3G USB modem from the USB hub, and then plug it back again if it's previously plugged in before Raspberry Pi finished booting. This is a compatibility hack because sometimes it is required, and sometimes not.
  3. Wait until the 3G USB modem is recognized (watch syslog, i.e. tail -f /var/log/messages)
  4. Run usb_modeswitch on the modem
  5. Run pppd
  6. Watch syslog to find out whether the data connection succeeded or not, i.e. tail -f /var/log/messages 
  7. Test the connection with your user machine connected through Raspberry Pi Ethernet.
Note that step 1 to 5 must be carried out exactly as mentioned above, otherwise pppd will always fail to initialize data connection with pppd. I'm not so sure what causes it, but it seems that the modem cannot respond to the AT command(s) sent by pppd correctly, at least the command to establish data connection. I saw that through syslog.

I also run a DHCP server in my Raspberry Pi, the isc-dhcp server. The configuration files for isc-dhcp are /etc/init.d/isc-dhcp-server, /etc/default/isc-dhcp-server and /etc/dhcp/dhcpd.conf. You only need to deal with the last two config files. /etc/default/isc-dhcp-server determines which network interface(s) used to listen for DHCP client requests. /etc/dhcp/dhcpd.conf determines the network configuration, such as the IP addresses to assign to the client, DNS servers, gateway, etc. Let's have a look at my configuration files.
This is how my /etc/default/isc-dhcp-server looks like.

# Defaults for isc-dhcp-server initscript
# sourced by /etc/init.d/isc-dhcp-server
# installed at /etc/default/isc-dhcp-server by the maintainer scripts

#
# This is a POSIX shell fragment
#

# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
DHCPD_CONF=/etc/dhcp/dhcpd.conf

# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
#DHCPD_PID=/var/run/dhcpd.pid

# Additional options to start dhcpd with.
#       Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
#OPTIONS=""

# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
#       Separate multiple interfaces with spaces, e.g. "eth0 eth1".
INTERFACES="eth0"
As you can see, isc-dhcp listens to client on the ethernet interface and the dhcpd configuration file to use is set to /etc/dhcp/dhcpd.conf. Now, let's have a look at /etc/dhcp/dhcpd.conf.
#
# Sample configuration file for ISC dhcpd for Debian
#
#

# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;

# option definitions common to all supported networks...
#option domain-name "example.org";
#option domain-name-servers ns1.example.org, ns2.example.org;

default-lease-time 7200;
max-lease-time 86400;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# .. irrelevant commented config omitted for brevity ..

# Raspberry Pi subnet - note: this is the subnet of M$ Internet Connection Sharing
# TODO: Make sure the router configuration is correct
subnet 192.168.137.0 netmask 255.255.255.0 {
  range 192.168.137.3 192.168.137.21;
  option broadcast-address 192.168.137.255;
  option routers 192.168.137.2;
  default-lease-time 7200;
  max-lease-time 86400;
  option domain-name "local";
  option domain-name-servers 8.8.8.8, 8.8.4.4;
}
As you can see, the lease time and maximum lease time configuration are consistent. I found that inconsistencies in these parameters sometimes causes isc-dhcp fails to provide valid IP addresses to the DHCP clients. So, watch-out to those parameters values.

Well, there are some more details regarding pppd, usb_modeswitch and iptables which are missing. This post is still considered beta and I'm going to update it in the not so distant future..