<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3891314539227613589</id><updated>2011-08-02T02:12:35.509+12:00</updated><category term='linux'/><category term='factor'/><category term='video'/><category term='flash'/><category term='java'/><category term='shell'/><category term='C'/><category term='oldblog'/><title type='text'>blog of jedahu</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-6680967999141429865</id><published>2010-11-03T12:29:00.003+13:00</published><updated>2010-11-03T12:40:13.631+13:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>~/bin: apod-set-bg</title><content type='html'>&lt;p&gt;&lt;a href="http://apod.nasa.gov/apod/"&gt;Astronomy Picture Of the Day&lt;/a&gt; shows a new, usually desktop sized, picture every day. &lt;code&gt;apod-set-bg&lt;/code&gt; is a shell script to download the daily image and set it as the desktop background. It also downloads the explanation as a separate &lt;code&gt;html&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Requirements: curl, tidy, &lt;a href="http://xmlstar.sourceforge.net"&gt;xmlstarlet&lt;/a&gt;, &lt;a href="http://linuxbrit.co.uk/software/feh/"&gt;feh&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh

IMG_DIR="$1"

APOD_URL=http://apod.nasa.gov/apod/ 

URL_CONTENT=`curl $APOD_URL | tidy -q -asxml`

IMG_URL=$APOD_URL`echo "$URL_CONTENT" | xml sel -N html='http://www.w3.org/1999/xhtml' -t -v '//html:img/ancestor::html:a/attribute::href' -`

EXPLANATION=`echo "$URL_CONTENT" | xml sel -N html='http://www.w3.org/1999/xhtml' -t -c '/html:html/html:body/html:center[2]' -c '/html:html/html:body/html:p' -`

FILE_NAME=`basename "$IMG_URL"`

FILE_PATH="$IMG_DIR/$FILE_NAME"

curl -o "$FILE_PATH" "$IMG_URL" || exit 1

echo "$EXPLANATION" &amp;gt; "$FILE_PATH.html"

ln -sf "$FILE_PATH" "$IMG_DIR/latest.jpg"
ln -sf "$FILE_PATH.html" "$IMG_DIR/latest.html"

feh --bg-fill "$FILE_PATH"
&lt;/pre&gt;
&lt;p&gt;Put the following in your crontab to run daily.&lt;/p&gt;
&lt;pre&gt;
@daily ID=apod DISPLAY=:0.0 ~/bin/apod-set-bg ~/bg/ &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-6680967999141429865?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/6680967999141429865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2010/11/bin-apod-set-bg.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/6680967999141429865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/6680967999141429865'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2010/11/bin-apod-set-bg.html' title='~/bin: apod-set-bg'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-3708597999569550291</id><published>2010-09-16T14:05:00.003+12:00</published><updated>2010-09-16T16:45:19.303+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video'/><category scheme='http://www.blogger.com/atom/ns#' term='factor'/><title type='text'>tvnz-grab in factor</title><content type='html'>&lt;p&gt;The &lt;a href="/2010/09/saving-tvnz-ondemand-episodes.html"&gt;previous post&lt;/a&gt; in factor. I wrote it so my Windows using friends could have a single-binary solution. Download the &lt;a href="http://download953.mediafire.com/1qg6ftx1okig/lgd7t7o6n9k9h9b/tvnz-grab.zip"&gt;zip archive&lt;/a&gt; and unzip somewhere in the windows path; &lt;code&gt;C:\windows\system32&lt;/code&gt; will do.&lt;/p&gt;
&lt;p&gt;Usage: &lt;code&gt;tvnz-grab &amp;lt;episode-page-url&amp;gt;&lt;/code&gt;. It will download all parts of the episode into the current directory.&lt;/p&gt;
&lt;p&gt;Unfortunately, this only works for NZ content. Foreign content uses Adobe’s encrypted RTMP protocol. To get at episodes using that, check out &lt;a href="http://rtmpdump.mplayerhq.hu"&gt;rtmpsuck&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Imports first.&lt;/p&gt;
&lt;pre&gt;
! Copyright (C) 2010 Jeremy Hughes.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors assocs combinators.short-circuit fry
http.client io.streams.byte-array kernel namespaces make
regexp sequences xml xml.data locals splitting strings
io.encodings.binary io io.files command-line http system
math.parser destructors math math.functions io.pathnames
continuations xml.traversal ;
IN: tvnz-grab
&lt;/pre&gt;
&lt;p&gt;Because I intend to extend this program into a small Qt demo, it is necessary that any words used to display UI information, dispatch on the type of UI.&lt;/p&gt;
&lt;pre&gt;
SYMBOL: ui
SINGLETON: text
&lt;/pre&gt;
&lt;p&gt;And the display methods themselves…&lt;/p&gt;
&lt;pre&gt;
HOOK: show-progress ui ( chunk full -- )
HOOK: show-begin-fetch ui ( url -- )
HOOK: show-end-fetch ui ( -- )
HOOK: show-page-fetch ui ( -- )
HOOK: show-playlist ui ( seq -- )
HOOK: show-fatal-error ui ( error -- )
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;M\ text show-progress&lt;/code&gt; uses the symbols &lt;code&gt;bytes&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; to keep track of the number of bytes downloaded and the proportion of progress-bar fill respectively.&lt;/p&gt;
&lt;pre&gt;
: print-bar ( full chunk -- )
    count [
        [ swap / 50 * round ] dip [
            - CHAR: =
            &lt;repetition&gt; &amp;gt;string write
        ] [ drop ] 2bi
    ] change ;

M: text show-progress
    swap bytes [ + [ print-bar ] keep ] change flush ;

M: text show-begin-fetch
    "Fetching " write print "[" write flush ;

M: text show-end-fetch
    "]" print flush ;

M: text show-page-fetch
    "Fetching TVNZ page..." print flush ;

M: text show-playlist
    length "Found " write number&amp;gt;string write " parts." print
    flush ;

M: text show-fatal-error
    dup string? [ print ]
    [ drop "Oops! Something went wrong." print ] if 1 exit ;
&lt;/pre&gt;
&lt;p&gt;Failed HTTP request errors need to be wrapped in a user friendly explanation.&lt;/p&gt;
&lt;pre&gt;
: wrap-failed-request ( err -- * )
    [
        "HTTP request failed: " % [ message&amp;gt;&amp;gt; % ]
        [ " (" % code&amp;gt;&amp;gt; number&amp;gt;string % ")" % ] bi
    ] "" make throw ;
&lt;/pre&gt;
&lt;p&gt;The playlist parameter in each episode’s web page is in a section of code looking like this.&lt;/p&gt;
&lt;pre&gt;
var videoVars = {
    playlist: '/content/3685181/ta_ent_smil_skin.smil',
    config: '/fmsconfig.xml',
    ord: ord
};
&lt;/pre&gt;
&lt;p&gt;Given this code could change unpredictably, we’ll use nothing more robust than a regular expression to get at the playlist path.&lt;/p&gt;
&lt;pre&gt;
: get-playlist ( url -- data )
    http-get [ check-response drop ]
    [ R/ (?&amp;lt;=playlist: ').*(?=')/ first-match ] bi* [
        "http://tvnz.co.nz" prepend http-get [
            [ check-response drop ]
            [ wrap-failed-request ] recover
        ] dip
    ] [ "Could not find playlist at address." throw ] if* ;
&lt;/pre&gt;
&lt;p&gt;The playlist is an XML file of which only the &lt;code&gt;video&lt;/code&gt; elements concern us.&lt;/p&gt;
&lt;pre&gt;
&amp;lt;video src="path-to-segment.flv" systemBitrate="700000"/&amp;gt;
&lt;/pre&gt;
&lt;p&gt;700000 appears to be the highest bit rate so that is what we’ll go for.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;parse-playlist&lt;/code&gt; takes the output of &lt;code&gt;get-playlist&lt;/code&gt; and returns a list of URLs to episode segments.&lt;/p&gt;
&lt;pre&gt;
: parse-playlist ( data -- urls )
    bytes&amp;gt;xml body&amp;gt;&amp;gt; "video" "700000" "systemBitrate"
    deep-tags-named-with-attr
    [ [ drop "src" ] [ attrs&amp;gt;&amp;gt; ] bi at ] map [ ] filter ;
&lt;/pre&gt;
&lt;p&gt;Each segment is downloaded in chunks.&lt;/p&gt;
&lt;pre&gt;
: call-progress ( data -- )
    length response get check-response
    "content-length" header string&amp;gt;number show-progress ;

: process-chunk ( data stream -- )
    [ stream-write ] [ drop call-progress ] 2bi ;

: get-video-segment ( url -- )
    [ show-begin-fetch ] [ ]
    [ part-name binary &lt;file-writer&gt; ] tri
    [ '[ _ process-chunk ] with-http-get drop flush ]
    with-disposal show-end-fetch ;

: get-video-segments ( urls -- )
    [ get-video-segment ] each ;
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;grab-episode&lt;/code&gt; is where the action starts.&lt;/p&gt;
&lt;pre&gt;
: (grab-episode) ( url -- )
    show-page-fetch get-playlist parse-playlist dup
    show-playlist [
        0 bytes count [ set ] bi-curry@ bi get-video-segments
    ] with-scope ;

: grab-episode ( url -- )
    [ (grab-episode) ] [ nip show-fatal-error ] recover ;
&lt;/pre&gt;
&lt;p&gt;For the complete program see &lt;a href="http://github.com/jedahu/vocabs/tree/master/tvnz-grab/"&gt;my github&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-3708597999569550291?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/3708597999569550291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2010/09/tvnz-grab-in-factor.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/3708597999569550291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/3708597999569550291'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2010/09/tvnz-grab-in-factor.html' title='tvnz-grab in factor'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-1052732968856718</id><published>2010-09-16T13:40:00.006+12:00</published><updated>2010-09-16T16:45:51.727+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>Saving TVNZ “ondemand” episodes</title><content type='html'>&lt;p&gt;The code in my &lt;a href="/2010/09/saving-flash-video-on-linux.html"&gt;previous post&lt;/a&gt; will work for episodes from TVNZ’s &lt;a href="http://tvnz.co.nz/video"&gt;ondemand&lt;/a&gt; service; but there is a more direct approach.&lt;/p&gt;
&lt;p&gt;Each episode page stores a URL to the episode’s playlist in a javascript property &lt;code&gt;"playlist"&lt;/code&gt;. The URL points to an XML file containing the URLs of four or more video parts and no ads. The following script downloads the episode page, grabs the playlist URL, downloads the playlist, and parses it. It returns a newline separated list of video URLs.&lt;/p&gt;
&lt;p&gt;You will need to have curl and &lt;a href="http://xmlstar.sourceforge.net"&gt;xmlstarlet&lt;/a&gt; installed.&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh

if [ "$1" == "" ]; then
    echo "usage: $0 episode-url"
    exit 1
fi

EPISODE="$1"

PLAYLIST=http://tvnz.co.nz`curl "$EPISODE" | grep -Po "(?&lt;=playlist: ').*?(?=')"`

curl "$PLAYLIST" | \
    xml sel -N smil=http://www.w3.org/ns/SMIL \
        -t -m "//smil:video[@systemBitrate='700000']" -v '@src' -n -
&lt;/pre&gt;
&lt;p&gt;I have saved it as &lt;code&gt;tvnz-grab&lt;/code&gt; and call it like so:&lt;/p&gt;
&lt;pre&gt;
tvnz-grab &amp;lt;episode-page-url&amp;gt; | xargs curl -O
&lt;/pre&gt;
&lt;p&gt;The four or five parts can be played as a single file using mplayer’s &lt;code&gt;"-fixed-vo"&lt;/code&gt; option.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-1052732968856718?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/1052732968856718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2010/09/saving-tvnz-ondemand-episodes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/1052732968856718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/1052732968856718'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2010/09/saving-tvnz-ondemand-episodes.html' title='Saving TVNZ “ondemand” episodes'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-8026926982302614347</id><published>2010-09-16T13:12:00.005+12:00</published><updated>2010-09-16T16:46:21.809+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>Saving flash video on linux</title><content type='html'>&lt;p&gt;On linux, the flash-player caches video in files under &lt;code&gt;/tmp&lt;/code&gt;. Each video gets a file called &lt;code&gt;/tmp/Flash[random-string]&lt;/code&gt;. These are easy enough to find and rename to &lt;code&gt;[meaningful-string].flv&lt;/code&gt;. However, some players delete these files on completion, which is a pain given they are the files containing the video we want to save.&lt;/p&gt;
&lt;p&gt;Hard linking these files solves the problem. The &lt;code&gt;Flashxxx&lt;/code&gt; files will be deleted by the player, but their contents will sill be available at whatever location we made the hard link.&lt;/p&gt;
&lt;p&gt;Some players split their content into multiple files, so we want this hard linking process to be automatic.&lt;/p&gt;
&lt;p&gt;I have the following script saved as &lt;code&gt;lnflv&lt;/code&gt; in my &lt;code&gt;~/bin&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh

cd /tmp
for x in Flash*; do
    count=`find . -xdev -samefile "$x" | wc -l`
    if [ $count -gt 1 ]; then
        echo "Not linking $x. Already linked."
    else
        echo "Linking $x."
        ln "$x" "dl-$x.flv"
    fi
done
&lt;/pre&gt;
&lt;p&gt;Run it every thirty seconds like this: &lt;code&gt;watch -n30 lnflv&lt;/code&gt;. Each flash file not already hard linked will be linked to &lt;code&gt;/tmp/dl-Flashxxx.flv&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Order by time and rename video parts with something like this:&lt;/p&gt;
&lt;pre&gt;
alpha=a
for f in `find . -size +10M -name dl-Flash\* | xargs ls -tr`; do
    cp "$f" [name]$alpha.flv
    alpha=`echo -n $alpha | tr 'a-y' 'b-z'`
done
&lt;/pre&gt;
&lt;p&gt;Change &lt;code&gt;[name]&lt;/code&gt; to the name of whatever you are watching. &lt;code&gt;"-size +10M"&lt;/code&gt; filters out files smaller than 10MB; this screens out short ads and is only required for video streams that embed them.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-8026926982302614347?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/8026926982302614347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2010/09/saving-flash-video-on-linux.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/8026926982302614347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/8026926982302614347'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2010/09/saving-flash-video-on-linux.html' title='Saving flash video on linux'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-1917984350379791301</id><published>2010-08-27T12:53:00.002+12:00</published><updated>2010-09-16T16:46:42.771+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='oldblog'/><title type='text'>Old blog: Map in Java</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p&gt;(Found in my years old defunct blog. Less relevant now that Java is getting lambdas.)&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Scheme&lt;/h6&gt;&lt;pre&gt;
(map fn lst ...)

;;  ==&amp;gt; list
      &lt;/pre&gt;&lt;p&gt; &lt;code&gt;map&lt;/code&gt; is a higher order function that applies the function &lt;code&gt;fn&lt;/code&gt; of &lt;code&gt;n&lt;/code&gt; arguments to each element in the lists &lt;code&gt;lst ...&lt;/code&gt; &lt;/p&gt;&lt;p&gt; Java has no map. Enhanced for isn't adequate for the following reasons: &lt;/p&gt;&lt;p style=' -qt-block-indent:1;'&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt; &lt;strong&gt;No return value:&lt;/strong&gt; Since &lt;code&gt;for&lt;/code&gt; is a control structure, not a function, it doesn't return anything useful. This means a data structure has to be created beforehand, and added to at each iteration of the &lt;code&gt;for&lt;/code&gt; loop. &lt;/li&gt;&lt;li&gt; &lt;strong&gt;No function arguments:&lt;/strong&gt; This is not &lt;code&gt;for&lt;/code&gt;'s problem. Functions (methods) are not first class in Java. &lt;/li&gt;&lt;li&gt; &lt;strong&gt;One iterable only:&lt;/strong&gt; The enhanced &lt;code&gt;for&lt;/code&gt; loop can only iterate over one &lt;code&gt;Iterable&lt;/code&gt; data structure. &lt;code&gt;map&lt;/code&gt; can operate on any number of lists. &lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Examples&lt;/h4&gt;&lt;h5&gt;Simple one list mapping&lt;/h5&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Scheme&lt;/h6&gt;&lt;pre&gt;
(define squares (list 1 4 9 16))

(define (sqrts nums)
  (map sqrt nums))

(sqrts squares)

;;  ==&amp;gt; (1 2 3 4)
      &lt;/pre&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
/* No generics for clarity.  Assume also the existance of a static
   method `toList' that takes an Array and returns an ArrayList. */

List squares = toList(new Integer[] {1, 4, 9, 16});

List sqrts(List nums) {
    List out = new ArrayList();
    for (Integer i : nums)
        out.add(Math.sqrt(i));
    return out;
}

sqrts(squares);

//  ==&amp;gt; [1, 2, 3, 4]
      &lt;/pre&gt;&lt;h5&gt;Multiple list mapping&lt;/h5&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Scheme&lt;/h6&gt;&lt;pre&gt;
(define even (list 2 4 6 8))
(define odd (list 1 3 5 7))

(define (sums . lists)
  (apply map + lists))

(sums even odd)

;;  ==&amp;gt; (3 7 11 15)
      &lt;/pre&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
/* Assume the existance of a static method `isSameLength' that tests
   whether all Lists in an array are the same length. */

List even = toList(new Integer[] {2, 4, 6, 8});
List odd = toList(new Integer[] {1, 3, 5, 7});

List sums(List... lists) {
    List out = new ArrayList();
    if (!isSameLength(lists))
        throw new RuntimeException("Lists must have same length.");
    int numargs = lists.length;
    int length = lists[0].size();
    for (int i = 0; i &amp;lt; length; i++) {
        int val = 0;
        for (int k = 0; k &amp;lt; numargs; k++)
            val += lists[k].get(i);
        out.add(val);
    }
    return out;
}

sums(even, odd);

//  ==&amp;gt; [3, 7, 11, 15]
      &lt;/pre&gt;&lt;p&gt; The problem with this is that it isn't generalised. &lt;/p&gt;&lt;h4&gt;Map in Java&lt;/h4&gt;&lt;p&gt; First we'll need a something that acts as a first-class function. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
public interface Proc {

    public Object apply(Object... args);

}
      &lt;/pre&gt;&lt;p&gt; Next, a static map method. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
public static List map(Proc proc, List... lists) {
    List out = new ArrayList();
    if (!isSameLength(lists))
        throw new RuntimeException("`map' requires lists of identical length");
    int numargs = lists.length;
    int length = lists[0].size();
    for (int i = 0; i &amp;lt; length; i++) {
        Obj[] args = new Obj[numargs];
        for (int k = 0; k &amp;lt; numargs; k++)
            args[k] = lists[k].get(i);
        out.add(proc.apply(args));
    }
    return out;
}
      &lt;/pre&gt;&lt;p&gt; Now, the multiple lists example again. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
List even = toList(new Integer[] {2, 4, 6, 8});
List odd = toList(new Integer[] {1, 3, 5, 7});

Proc sum = new Proc() {
    public Object apply(Object... args) {
        return (Integer)args[0] + (Integer)args[1];
    }
};

List sums(List... lists) {
    return map(sum, lists);
}

sums(even, odd);

//  ==&amp;gt; [3, 7, 11, 15]
      &lt;/pre&gt;&lt;p&gt; Much shorter, but with some limitations: &lt;/p&gt;&lt;p style=' -qt-block-indent:1;'&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;It doesn't use generics, and therefore&lt;/li&gt;&lt;li&gt;requires casting in &lt;code&gt;Proc&lt;/code&gt; implementations; and&lt;/li&gt;&lt;li&gt;it is hardcoded to return an &lt;code&gt;ArrayList&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Parametrized map&lt;/h5&gt;&lt;p&gt; First, &lt;code&gt;Proc&lt;/code&gt; is changed. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
public interface Proc1&amp;lt;R, A&amp;gt; {

    public R apply(A arg);

}

public interface Proc2&amp;lt;R, A, B&amp;gt; {

    public R apply(A argA, B argB);

}

public interface ProcN&amp;lt;R, A, B,..., N&amp;gt; {

    public R apply(A argA, B argB,..., N argN);

}
      &lt;/pre&gt;&lt;p&gt; And a parameterized &lt;code&gt;map&lt;/code&gt;. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
public static &amp;lt;R, A, X extends List&amp;lt;R&amp;gt;&amp;gt; X map(Proc1&amp;lt;R, A&amp;gt; proc, X out, List&amp;lt;A&amp;gt; list) {
    for (A a : list)
        out.add(proc.apply(a));
    return out;
}

public static &amp;lt;R, A, B, X extends List&amp;lt;R&amp;gt;&amp;gt; X map(Proc2&amp;lt;R, A, B&amp;gt; proc,
        X out, List&amp;lt;A&amp;gt; listA, List&amp;lt;B&amp;gt; listB) {
    if (!isSameLength(listA, listB))
        throw new RuntimeException("`map' requires lists of identical length.");
    int length = listA.size();
    for (int i = 0; i &amp;lt; length; i ++)
        out.add(proc.apply(listA.get(i), listB.get(i));
    return out;

// And so on up to `map&amp;lt;R, A, B,..., N, X&amp;gt;.
      &lt;/pre&gt;&lt;p&gt; The example would now be: &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
List even = toList(new Integer[] {2, 4, 6, 8});
List odd = toList(new Integer[] {1, 3, 5, 7});

Proc2&amp;lt;Integer, Integer, Integer&amp;gt; sum = 
    new Proc&amp;lt;Integer, Integer, Integer&amp;gt;() {
        public Integer apply(Integer argA, Integer argB) {
            return argA + argB;
        }
    };

List sums(List listA, List listB) {
    return map(sum, new ArrayList(), listA, listB);
}

sums(even, odd);

//  ==&amp;gt; [3, 7, 11, 15]
      &lt;/pre&gt;&lt;h5&gt;The cost of parameterizing&lt;/h5&gt;&lt;p&gt; The obvious limitation of the generic implementation is that arbitrary numbers of arguments are no longer supported in &lt;code&gt;ProcN&lt;/code&gt; or &lt;code&gt;map&lt;/code&gt;. &lt;/p&gt;&lt;h4&gt;Reduce&lt;/h4&gt;&lt;p&gt; &lt;code&gt;reduce&lt;/code&gt; is easily written on top of &lt;code&gt;Proc2&lt;/code&gt;. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;h6&gt;Java&lt;/h6&gt;&lt;pre&gt;
public static &amp;lt;R, A&amp;gt; R reduce(Proc2&amp;lt;R, R, A&amp;gt; proc, List&amp;lt;A&amp;gt; list, R initial) {
    int size = list.size();
    R out = initial;
    for (A a : list)
        out = fun.apply(out, a);
    return out;
}

List nums = toList(new Integer[] {1, 2, 3, 4});

Integer squareSum(List list) {
    return reduce(new Proc2&amp;lt;Integer, Integer, Integer&amp;gt;() {
        public Integer apply(Integer a, Integer b) {
            return a + (b * b);
        }
    }, list, 0);
}

squareSum(nums);

//  ==&amp;gt; 30
      &lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-1917984350379791301?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/1917984350379791301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2010/08/old-blog-map-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/1917984350379791301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/1917984350379791301'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2010/08/old-blog-map-in-java.html' title='Old blog: Map in Java'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-560324009639120677</id><published>2010-08-20T09:41:00.007+12:00</published><updated>2010-08-20T11:27:51.121+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='factor'/><title type='text'>Why I like Factor</title><content type='html'>&lt;p&gt;&lt;a href="http://factorcode.org/"&gt;Factor&lt;/a&gt; is a relatively new language and implementation in the tradition of Forth, Lisp, and Smalltalk. Like Forth, Factor is concatenative and uses a postfix syntax. Also like Forth, Factor emphasises small procedures and constant refactoring. Like many Lisp and Smalltalk implementations, Factor compiles code into a loadable image. Like Lisp, Factor can perform arbitrary computation at compile time using macros while parse time evaluation allows the creation of new syntax forms.&lt;/p&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;Unlike Forth, Lisp, and Smalltalk, Factor is modern and unencumbered. Lisp suffers from an ossified specification, Smalltalk has lived inside its own image for so long it's out of touch with the rest of the world, and Forth provides few of Factor's higher level features like garbage collection and dynamic code updating.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;Factor’s focus on correctness and efficiency is not commonly found in other modern ‘dynamic’ languages. The results speak for themselves.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;1. Factor vocabularies are compiled to machine code.&lt;/em&gt; When using the interactive listener the code is compiled before execution (like SBCL).&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;2. Factor is fast.&lt;/em&gt; Not C fast, but SBCL fast.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;3. Almost all structures are modifiable at runtime.&lt;/em&gt; This includes classes at any position in the hierarchy as well as FFI bindings. When reloading a modified vocabulary, definitions no longer present will be deleted from the running image. These changes are propagated to all dependent code and the changes to the running image are kept consistent.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;4. A simple foreign function interface.&lt;/em&gt; No quirky header files or IDL necessary; everything is done from within Factor. No reloading of Factor necessary either: create bindings incrementally and test them as you go.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;5. Deployment images.&lt;/em&gt; Factor’s deployment tool only loads code the resultant binary will run. Minimal image size for a hello world program is a few hundred kilobytes.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;6. Common Lisp style condition system.&lt;/em&gt; Don’t let stack unwinding lose an exception’s context. Recover anywhere between where the exception is caught and where it was thrown.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Why having a competent designer pays off&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;In contrast to other popular languages like Ruby and Python, Factor does not suffer from limiting creeds like, “There should be one way to do it,” or from BDFLs who don’t see the value in useful language constructs discovered as early as the 70s. Here's the payoff...&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;7. Correct lexical scoping.&lt;/em&gt; Usually in Factor one uses its postfix syntax and data flow combinators, however it also sports a locals vocabulary defined entirely in factor which implements lexical scoping and lambdas. Despite the fact that this is an addition in a language where lexical variables are not the default, Factor's lexical scoping is correct and its lambdas are uncrippled. Python 2.x is unable to rebind a variable in a parent scope (3.x overcomes this by introducing a new keyword, ugh!), and Ruby only recently (1.9) gave blocks their own scope.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;8. Usable higher order functions.&lt;/em&gt; Combinators are used in Factor all the time. For some unfathomable reason Ruby allows only one block argument per function while in Python the use of such esoterica as &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;reduce&lt;/code&gt; is discouraged.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;9. Tail call optimization.&lt;/em&gt; Yep, that’s right, that helpful recursion thingy. Another thing Python doesn't have because, oh I don’t know, &lt;a href="http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html"&gt;ask Guido&lt;/a&gt;. Come to Factor and free your mind from loopiness!&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;10. Low, hi, and FFI.&lt;/em&gt; Factor scales well from highly abstracted garbage collected code, to micro optimization using inline ASM. Along the way, the FFI allows Factor quotations to be used as C callbacks, and provides factor-side memory allocation should you need to store values on the stack or in a memory pool.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;11. Methods are orthogonal to classes.&lt;/em&gt; Generic words and their methods are defined outside classes. Adding a generic word to a preexisting class is as simple as defining it. Extensibility without nasty monkey patching or name clashes, and a nice fit with a hierarchy that can contain anything from tuples, to predicate classes and C structs. No hideously bloated base-class needed (I'm looking at you &lt;a href="http://www.oldenbuettel.de/squeak-doku/Kernel-Objects/Object.html"&gt;Smalltalk&lt;/a&gt;). If Programmer Pooh adds a &lt;code&gt;display-in-opengl&lt;/code&gt; method to &lt;code&gt;object&lt;/code&gt; he need not modify core code, nor will his method clash with any present or future methods on &lt;code&gt;object&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Why having a smart community pays off&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;Smart, or at least willing to learn new things.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;12. No whiners!&lt;/em&gt; Try educating a bunch of Java programmers in the utility of higher order functions or tail-recursion...&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;13. Macros, syntax, and combinators, oh my!&lt;/em&gt; If you don’t whine, you get cool stuff. Macros akin to those in Common Lisp, but hygienic like Scheme, because if you don’t have variables, you can’t capture them. Syntax words like Lisp’s reader macros, but better because no dispatch character craziness is necessary. Observe the usefulness of regular expressions that are syntax checked at parse time, or the &lt;a href="http://docs.factorcode.org/content/article-peg.ebnf.html"&gt;EBNF&lt;/a&gt; vocabulary which compiles an inline EBNF description into parsing code. For higher order goodness check out Factor’s unique &lt;a href="http://docs.factorcode.org/content/article-dataflow-combinators.html"&gt;dataflow combinators&lt;/a&gt;. This is not your ancestor’s stack shuffling!&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;h4&gt;More stuff I like&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;&lt;em&gt;14. Live documentation.&lt;/em&gt; Factor has live documentation ala Emacs, but prettier and better linked. The documentation is contained in separate files to the code it describes. For those of us who hate hunting for scratchings of code amid screeds of API comments, this is a good thing.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;h4&gt;An acceptable Lisp?&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;Someone once &lt;a href="http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-an-acceptable-lisp"&gt;wrote&lt;/a&gt; about Ruby being an acceptable Lisp. They were wrong. Ruby doesn’t have macros, reader macros, native compilation, or a REPL from which everything can be modified. (Oh, but it does have three different kinds of lambda!)&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;Factor isn’t an acceptable Lisp either. Factor is a mighty fine Lisp. Factor is better than Lisp. It has all the things that make Lisp great and more. Factor will make your code beautiful. Factor will cook you breakfast. Factor reads like English, (lisp (like (not))). &lt;a href="http://twitter.com/slava_pestov/statuses/12308204789"&gt;All hail Factor!&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Summation&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;p&gt;I like Factor because it hits the sweet spot of pandering to nothing but being a great language. It lifts much of the good stuff from great languages of yore and gives them an improved spin. It hasn’t yet succumbed to the whining hordes of mediocrity. It is written by a team that really know what they are doing. If that doesn’t describe your language, then &lt;a href="http://factorcode.org"&gt;give Factor a try.&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-560324009639120677?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/560324009639120677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2010/08/why-i-like-factor.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/560324009639120677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/560324009639120677'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2010/08/why-i-like-factor.html' title='Why I like Factor'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-3238594757413075932</id><published>2009-07-17T16:50:00.008+12:00</published><updated>2009-09-21T15:27:24.028+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><title type='text'>Multichannel play record with jack</title><content type='html'>&lt;p&gt;
 Earlier this year I worked for a few weeks for a lecturer at my local
 university. One part of the work involved playing a signal through 24 audio
 ports and simultaneously recording from another 24 ports. These ports came from
 three daisy chained &lt;a
 href="http://www.presonus.com/products/Detail.aspx?ProductId=3"&gt;Presonus
 FP10’s&lt;/a&gt; which were connected by firewire to a linux box. This hardware was
 accessed by the &lt;a href="http://www.ffado.org/"&gt;ffado&lt;/a&gt; &lt;a
 href="http://jackaudio.org/"&gt;jack&lt;/a&gt; drivers. However, none of the following
 is specific to that hardware setup.
&lt;/p&gt;
&lt;p&gt;
 The lecturer gave me permission to write a post covering the code I wrote. What
 follows therefore is a walk through of the code to an executable called
 &lt;code&gt;recapture&lt;/code&gt;.
&lt;/p&gt;

&lt;h4&gt;Simultaneous play and record using jack&lt;/h4&gt;
&lt;p&gt;
 24 inputs an 24 outputs, simultaneous play and record. The jack audio server
 is written in C and can be run as a realtime process under a linux kernel with
 the &lt;a href="http://rt.wiki.kernel.org/index.php/Main_Page"&gt;RT&lt;/a&gt; patch
 applied. There are few bindings to other languages, most likely because of
 these realtime constraints. C was the most sensible language in which to
 implement &lt;code&gt;recapture&lt;/code&gt;.
&lt;/p&gt;
&lt;h5&gt;Includes and macros&lt;/h5&gt;
&lt;pre&gt;
/*
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; version 2 of the License.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 recapture.c 
 2009 Jeremy Hughes

 Play a signal through one port and simultaneously record from another.
*/

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;errno.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
#include &amp;lt;signal.h&amp;gt;
#include &amp;lt;sndfile.h&amp;gt;
#include &amp;lt;math.h&amp;gt;
#include &amp;lt;pthread.h&amp;gt;
#include &amp;lt;getopt.h&amp;gt;
#include &amp;lt;jack/jack.h&amp;gt;
#include &amp;lt;jack/ringbuffer.h&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
 Standard includes plus &lt;code&gt;sndfile.h&lt;/code&gt;, &lt;code&gt;jack/jack.h&lt;/code&gt; and
 &lt;code&gt;jack/ringbuffer.h&lt;/code&gt;. &lt;code&gt;jack.h&lt;/code&gt; contains the general API
 and &lt;code&gt;ringbuffer.h&lt;/code&gt; contains jack's implementation of a &lt;a href="http://en.wikipedia.org/wiki/Circular_buffer"&gt;circular buffer&lt;/a&gt;.  &lt;a href="http://www.mega-nerd.com/libsndfile/"&gt;libsndfile&lt;/a&gt; is used for reading
 and writing audio data.
&lt;/p&gt;
&lt;pre&gt;
const char* usage =
 "usage: recapture [ -b bufsize ] [ -i &amp;lt;inports&amp;gt; ] [ -o &amp;lt;outports&amp;gt; ] infile outfile\n"
 "            &amp;lt;inports&amp;gt; and &amp;lt;outports&amp;gt; are `,' separated\n";

#if 1
#define DEBUG(...) (fprintf(stderr, "recapture: "), fprintf(stderr, __VA_ARGS__))
#else
#define DEBUG
#endif
#define MSG(...) (fprintf(stderr, "recapture: "), fprintf(stderr, __VA_ARGS__))
#define ERR(...) (fprintf(stderr, "recapture: error: "), fprintf(stderr, __VA_ARGS__))
&lt;/pre&gt;
&lt;p&gt;
 Usage notice and some useful macros.
&lt;/p&gt;
&lt;pre&gt;
#define MAX_PORTS 30
&lt;/pre&gt;
&lt;p&gt;
 A sensible number given 24 input and output ports. To be a truly general
 program this would need to be a variable able to be overridden by a
 command line argument.
&lt;/p&gt;
&lt;h5&gt;Structs and typedefs&lt;/h5&gt;
&lt;pre&gt;
typedef jack_default_audio_sample_t recap_sample_t;
&lt;/pre&gt;
&lt;p&gt;
 &lt;code&gt;jack_default_audio_sample_t&lt;/code&gt; is a little long.
&lt;/p&gt;
&lt;pre&gt;
typedef enum _recap_status {
 IDLE, RUNNING, DONE
} recap_status_t;
&lt;/pre&gt;
&lt;p&gt;
 This program starts two extra threads. The main thread sets up a number of
 callbacks which the jack process runs in realtime. The two extra threads are
 a read thread and a write thread. This split is necessary because reading and
 writing cannot occur within a realtime thread without wrecking its realtime
 guarantees. The read and write threads are connected to the jack thread by a
 ringbuffer each.
&lt;/p&gt;
&lt;p&gt;
 Before initial synchronization the read thread is &lt;code&gt;IDLE&lt;/code&gt;, once
 reading has commenced it is &lt;code&gt;RUNNING&lt;/code&gt;, and when reading is finished
 it is &lt;code&gt;DONE&lt;/code&gt;. The jack processing thread also uses &lt;code&gt;IDLE&lt;/code&gt;
 and &lt;code&gt;DONE&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;
typedef struct _recap_state {
 volatile int can_play;
 volatile int can_capture;
 volatile int can_read;
 volatile recap_status_t reading;
 volatile recap_status_t playing;
} recap_state_t;
&lt;/pre&gt;
&lt;p&gt;
 A single instance of this struct is shared among all three threads. Play and
 record start when &lt;code&gt;can_play&lt;/code&gt;, &lt;code&gt;can_capture&lt;/code&gt;, and
 &lt;code&gt;can_read&lt;/code&gt; (which correspond to the three threads) are all true;
 they finish when &lt;code&gt;reading&lt;/code&gt; and &lt;code&gt;playing&lt;/code&gt; are both
 &lt;code&gt;DONE&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;
typedef struct _recap_io_info {
 pthread_t thread_id;
 char* path;
 SNDFILE* file;
 jack_ringbuffer_t* ring;
 long underruns;
 recap_state_t* state;
} recap_io_info_t;
&lt;/pre&gt;
&lt;p&gt;
 Both read and write threads receive an instance of this struct as their only
 argument.
&lt;/p&gt;
&lt;pre&gt;
typedef struct _recap_process_info {
 long overruns;
 long underruns;
 recap_io_info_t* writer_info;
 recap_io_info_t* reader_info;
 recap_state_t* state;
} recap_process_info_t;
&lt;/pre&gt;
&lt;p&gt;
 An instance of this struct is passed to the callback responsible for
 processing the signals.
&lt;/p&gt;
&lt;h5&gt;Global values&lt;/h5&gt;
&lt;pre&gt;
const size_t sample_size = sizeof(recap_sample_t);
&lt;/pre&gt;
&lt;p&gt;
 This works out to be the size of a 32 bit float. Not bad given the sample size
 of CD audio is 16 bits.
&lt;/p&gt;
&lt;pre&gt;
pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ready_to_read = PTHREAD_COND_INITIALIZER;
pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ready_to_write = PTHREAD_COND_INITIALIZER;
&lt;/pre&gt;
&lt;p&gt;
 Locks and condition variables for each IO thread.
&lt;/p&gt;
&lt;pre&gt;
recap_process_info_t* proc_info;
&lt;/pre&gt;
&lt;p&gt;
 Needs to be global for signal handling.
&lt;/p&gt;
&lt;pre&gt;
/* read only after initialization in main() */
int channel_count_r = 0;
int frame_size_r = 0;
int channel_count_w = 0;
int frame_size_w = 0;
jack_nframes_t ring_size = 65536; /* pow(4, 8) */
jack_port_t* recap_in_ports[MAX_PORTS];
jack_port_t* recap_out_ports[MAX_PORTS];
jack_client_t* client;
&lt;/pre&gt;
&lt;p&gt;
 Variables that are not changed subsequent to initialization and therefore
 do not need to be in thread specific structs.
&lt;/p&gt;
&lt;p&gt;
 &lt;code&gt;channel_count_r&lt;/code&gt; and &lt;code&gt;channel_count_w&lt;/code&gt; hold the number
 of read and write signals. The &lt;code&gt;frame_size&lt;/code&gt; of each is calculated
 by multiplying the channel count by the sample size. The default
 &lt;code&gt;ring_size&lt;/code&gt; can be overridden by command line
 argument. &lt;code&gt;recap_in_ports&lt;/code&gt; and &lt;code&gt;recap_out_ports&lt;/code&gt; will
 hold the jack ports this client connects to.
&lt;/p&gt;
&lt;h5&gt;Helper functions&lt;/h5&gt;
&lt;pre&gt;
static size_t array_length(char** array) {
 int i = -1;
 while (array[++i] != NULL);
 return i;
}
&lt;/pre&gt;
&lt;p&gt;
 There is probably a more standard if not more general way to do this, but a)
 I couldn't find it, and b) this function does the job.
&lt;/p&gt;
&lt;pre&gt;
typedef recap_sample_t (*next_value_fn) (void*);

int uninterleave(recap_sample_t** buffers, size_t length, size_t count,
                next_value_fn next_value, void* arg) {
 int status = 0;
 int i;
 int k;
 for (i = 0; i &amp;lt; count; i++) {
   for (k = 0; k &amp;lt; length; k++) {
     recap_sample_t sample = next_value(arg);
     if (sample == -1) {
       status = -1;
       break;
     } else {
       buffers[k][i] = sample;
     }
   }
   if (status) break;
 }
 return status;
}

recap_sample_t next_value(void* arg) {
 recap_sample_t sample;
 jack_ringbuffer_t* rb = (jack_ringbuffer_t*) arg;
 size_t count = jack_ringbuffer_read(rb, (char*) &amp;amp;sample, sample_size);
 if (count &amp;lt; sample_size) sample = -1;
 return sample;
}
&lt;/pre&gt;
&lt;p&gt;
 libsndfile expects multichannel data to be interleaved.
 &lt;code&gt;uninterleave()&lt;/code&gt; uses a supplied function to read interleaved data
 and writes it to an array of output buffers (one per channel).
&lt;/p&gt;
&lt;p&gt;
 &lt;code&gt;next_value()&lt;/code&gt; simply reads the next &lt;code&gt;sample_size&lt;/code&gt; bytes
 from the supplied ringbuffer.
&lt;/p&gt;
&lt;pre&gt;
typedef int (*write_value_fn) (recap_sample_t, void*);

int interleave(recap_sample_t** buffers, size_t length, size_t count,
              write_value_fn write_value, void* arg) {
 int status = 0;
 int i;
 int k;
 for (i = 0; i &amp;lt; count; i++) {
   for (k = 0; k &amp;lt; length; k++) {
     status = write_value(buffers[k][i], arg);
     if (status) break;
   }
   if (status) break;
 }
 return status;
}

int write_value(recap_sample_t sample, void* arg) {
 int status = 0;
 jack_ringbuffer_t* rb = (jack_ringbuffer_t*) arg;
 size_t count = jack_ringbuffer_write(rb, (char*) &amp;amp;sample, sample_size);
 if (count &amp;lt; sample_size) status = -1;
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 &lt;code&gt;interleave()&lt;/code&gt; reads data from an array of input buffers and uses
 the supplied function to write it interleaved.
&lt;/p&gt;
&lt;p&gt;
 &lt;code&gt;write_value()&lt;/code&gt; simple writes &lt;code&gt;sample_size&lt;/code&gt; bytes to the
 supplied ringbuffer.
&lt;/p&gt;
&lt;pre&gt;
static void recap_mute(recap_sample_t** buffers, int count, jack_nframes_t nframes) {
 int i;
 size_t bufsize = nframes * sample_size;
 for (i = 0; i &amp;lt; count; i++)
   memset(buffers[i], 0, bufsize);
}
&lt;/pre&gt;
&lt;p&gt;
 After playing has finished, jack output must be muted (zeroed) otherwise jack
 will continue playing whatever is left in the output buffers, looping through
 the last cycle of whatever signal was being played. Definitely not what you
 want.
&lt;/p&gt;
&lt;h5&gt;Signal handling&lt;/h5&gt;
&lt;pre&gt;
static void cancel_process(recap_process_info_t* info) {
 pthread_cancel(info-&gt;reader_info-&gt;thread_id);
 pthread_cancel(info-&gt;writer_info-&gt;thread_id);
}

static void signal_handler(int sig) {
 MSG("signal received, exiting ...\n");
 cancel_process(proc_info);
}

static void jack_shutdown(void* arg) {
 recap_process_info_t* info = (recap_process_info_t*) arg;
 MSG("JACK shutdown\n");
 cancel_process(info);
}
&lt;/pre&gt;
&lt;p&gt;
 Signal handing. &lt;code&gt;cancel_process()&lt;/code&gt; ensures things are cleaned up
 nicely. &lt;code&gt;jack_shutdown()&lt;/code&gt; is a callback that the jack process calls
 on exit.
&lt;/p&gt;
&lt;h5&gt;Thread abstraction&lt;/h5&gt;
&lt;pre&gt;
typedef int (*io_thread_fn) (recap_io_info_t*);
typedef void (*cleanup_fn) (void*);

#define FINISHED -1

static void* common_thread(pthread_mutex_t* lock, pthread_cond_t* cond, io_thread_fn fn, cleanup_fn cu, void* arg) {
 int* exit = (int*) malloc(sizeof(int*));
 memset(exit, 0, sizeof(*exit));
 int status = 0;
 recap_io_info_t* info = (recap_io_info_t*) arg;
 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 pthread_cleanup_push(cu, arg);
 pthread_mutex_lock(lock);
 while (1) {
   if ((status = fn(info)) != 0) break;
   pthread_cond_wait(cond, lock);
 }
 pthread_mutex_unlock(lock);
 *exit = status;
 if (status == FINISHED) *exit = 0;
 pthread_exit(exit);
 pthread_cleanup_pop(1);
}
&lt;/pre&gt;
&lt;p&gt;
 This abstracts out the common parts of setting up a thread and its loop. The
 supplied &lt;code&gt;io_thread_fn&lt;/code&gt; function is executed every iteration until
 it returns non zero. The supplied &lt;code&gt;cleanup_fn&lt;/code&gt; is called whenever
 the thread is exited. After each iteration the thread waits until it is
 signalled to continue.
&lt;/p&gt;
&lt;pre&gt;
typedef int (*io_test_fn) (recap_io_info_t*);
typedef size_t (*io_size_fn) (recap_io_info_t*);
typedef int (*io_body_fn) (void*, size_t, recap_io_info_t*);

static int io_thread(io_test_fn can_run, io_test_fn is_done, io_size_fn ring_space, io_body_fn body, recap_io_info_t* info) {
 int status = 0;
 if (can_run(info)) {
   size_t space = ring_space(info);
   if (is_done(info)) {
     status = FINISHED;
   } else if (space &gt; 0) {
     void* buf = malloc(space); /* TODO malloc and memset once only */
     status = body(buf, space, info);
     free(buf);
   }
 }
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 Further abstracted out is the code common to the read and write
 threads. &lt;code&gt;io_test_fn&lt;/code&gt; checks when the thread is finished and should
 exit; &lt;code&gt;io_size_fn&lt;/code&gt; returns how much read or write space is
 available; &lt;code&gt;io_body_fn&lt;/code&gt; contains code specific to reading or
 writing.
&lt;/p&gt;
&lt;p&gt;
 It would be good to malloc &lt;code&gt;void* buf&lt;/code&gt; only once at the beginning
 of the thread to ensure no pagefaults. However, since the allocation does not
 occur in a realtime thread and no overruns or underruns (dropouts) were
 observed in testing, it was not a high priority to fix.
&lt;/p&gt;
&lt;h5&gt;Thread implementation&lt;/h5&gt;
&lt;pre&gt;
static int reader_can_run(recap_io_info_t* info) {
 return info-&gt;state-&gt;can_read;
}

static int writer_can_run(recap_io_info_t* info) {
 return info-&gt;state-&gt;can_capture;
}

static int reader_is_done(recap_io_info_t* info) {
 return 0;
}

static int writer_is_done(recap_io_info_t* info) {
 return jack_ringbuffer_read_space(info-&amp;gt;ring) == 0 &amp;amp;&amp;amp; info-&amp;gt;state-&amp;gt;playing == DONE;
}

static size_t reader_space(recap_io_info_t* info) {
 return jack_ringbuffer_write_space(info-&gt;ring);
}

static size_t writer_space(recap_io_info_t* info) {
 return jack_ringbuffer_read_space(info-&gt;ring);
}
&lt;/pre&gt;
&lt;p&gt;
 Read and write implementations of the above typedefs.
&lt;/p&gt;
&lt;pre&gt;
static int reader_body(void* buf, size_t space, recap_io_info_t* info) {
 static int underfill = 0;
 int status = 0;
 sf_count_t nframes = space / frame_size_r;
 sf_count_t frame_count = sf_readf_float(info-&amp;gt;file, buf, nframes);
 if (frame_count == 0) {
   DEBUG("reached end of sndfile: %s\n", info-&amp;gt;path);
   info-&amp;gt;state-&amp;gt;reading = DONE;
   status = FINISHED;
 } else if (underfill &amp;gt; 0) {
   ERR("cannot read sndfile: %s\n", info-&amp;gt;path);
   status = EIO;
 } else {
   sf_count_t size = frame_count * frame_size_r;
   if (jack_ringbuffer_write(info-&amp;gt;ring, buf, size) &amp;lt; size) {
     ++info-&amp;gt;underruns;
     ERR("reader thread: buffer underrun\n");
   }
   DEBUG("read %6ld frames\n", frame_count);
   info-&amp;gt;state-&amp;gt;reading = RUNNING;
   if (frame_count &amp;lt; nframes &amp;amp;&amp;amp; underfill == 0) {
     DEBUG("expected %ld frames but only read %ld,\n", nframes, frame_count);
     DEBUG("wait for one cycle to make sure.\n");
     ++underfill;
   }
 }
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 Reader implementation of &lt;code&gt;io_body_fn&lt;/code&gt;. It is impossible to tell if
 the first underfill is caused by IO problems or by reaching the end of the
 sound file. If the frame count for the following cycle is zero, it is assumed
 that the end of the file has been reached; otherwise if &lt;code&gt;underfill&lt;/code&gt;
 is greater than zero it must be an IO issue so the thread exits.
&lt;/p&gt;
&lt;p&gt;
 The use of &lt;code&gt;static int underfill&lt;/code&gt; means no more than one reader
 thread can be active during the lifetime of the program.
&lt;/p&gt;
&lt;pre&gt;
static int writer_body(void* buf, size_t space, recap_io_info_t* info) {
 int status = 0;
 sf_count_t nframes = space / frame_size_w;
 jack_ringbuffer_read(info-&amp;gt;ring, buf, space);
 if (sf_writef_float(info-&amp;gt;file, buf, nframes) &amp;lt; nframes) {
   ERR("cannot write sndfile (%s)\n", sf_strerror(info-&amp;gt;file));
   status = EIO;
 }
 DEBUG("wrote %5ld frames\n", nframes);
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 Writer implementatino of &lt;code&gt;io_body_fn&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;
static int reader_thread_fn(recap_io_info_t* info) {
 return io_thread(&amp;amp;reader_can_run, &amp;amp;reader_is_done,
                  &amp;amp;reader_space, &amp;amp;reader_body, info);
}

static int writer_thread_fn(recap_io_info_t* info) {
 return io_thread(&amp;amp;writer_can_run, &amp;amp;writer_is_done,
                  &amp;amp;writer_space, &amp;amp;writer_body, info);
}
&lt;/pre&gt;
&lt;p&gt;
 Read and write implementations of &lt;code&gt;io_thread_fn&lt;/code&gt;. Due to the
 earlier abstraction these definitions are simple.
&lt;/p&gt;
&lt;pre&gt;
static void io_cleanup(void* arg) {
 recap_io_info_t* info = (recap_io_info_t*) arg;
 sf_close(info-&amp;gt;file);
}

static void io_free(recap_io_info_t* info) {
 jack_ringbuffer_free(info-&amp;gt;ring);
}
&lt;/pre&gt;
&lt;p&gt;
 &lt;code&gt;io_cleanup()&lt;/code&gt; is passed to &lt;code&gt;common_thread&lt;/code&gt; as the thread
 cleanup callback. &lt;code&gt;io_free()&lt;/code&gt; is used at the end of
 &lt;code&gt;main()&lt;/code&gt; to free resources which the jack thread may still be using
 after the IO threads exit.
&lt;/p&gt;
&lt;pre&gt;
static void* writer_thread(void* arg) {
 return common_thread(&amp;amp;write_lock, &amp;amp;ready_to_write,
                      &amp;amp;writer_thread_fn, &amp;amp;io_cleanup, arg);
}

static void* reader_thread(void* arg) {
 return common_thread(&amp;amp;read_lock, &amp;amp;ready_to_read,
                      &amp;amp;reader_thread_fn, &amp;amp;io_cleanup, arg);
}
&lt;/pre&gt;
&lt;p&gt;
 Functions to start writer and reader threads.
&lt;/p&gt;
&lt;h5&gt;Main jack callback&lt;/h5&gt;
&lt;pre&gt;
static int process(jack_nframes_t nframes, void* arg) {
 recap_process_info_t* info = (recap_process_info_t*) arg;
 recap_state_t* state = info-&amp;gt;state;
&lt;/pre&gt;
&lt;p&gt;
 The main jack callback. This function must read &lt;code&gt;nframes&lt;/code&gt; of signal
 from the connected input ports and write &lt;code&gt;nframes&lt;/code&gt; of signal to the
 connected output ports. The size of &lt;code&gt;nframes&lt;/code&gt; is determined by the
 caller (jack).
&lt;/p&gt;
&lt;pre&gt;
 if (!state-&amp;gt;can_play || !state-&amp;gt;can_capture || !state-&amp;gt;can_read)
   return 0;
&lt;/pre&gt;
&lt;p&gt;
 No point reading or writing anything to jack’s buffers if everything isn’t
 ready to go.
&lt;/p&gt;
&lt;pre&gt;
 recap_sample_t* in[MAX_PORTS];
 recap_sample_t* out[MAX_PORTS];
 int i = 0;
 jack_port_t* prt;
 while ((prt = recap_in_ports[i]) != NULL) {
   in[i++] = (recap_sample_t*) jack_port_get_buffer(prt, nframes);
 }
 in[i] = NULL;

 i = 0;
 while ((prt = recap_out_ports[i]) != NULL) {
   out[i++] = (recap_sample_t*) jack_port_get_buffer(prt, nframes);
 }
 out[i] = NULL;
&lt;/pre&gt;
&lt;p&gt;
 Get the signal buffers of each input and output port. It is recommended in the
 jack documentation that these are not cached.
&lt;/p&gt;
&lt;pre&gt;
 if (state-&amp;gt;playing != DONE &amp;amp;&amp;amp; state-&amp;gt;reading != IDLE) {
&lt;/pre&gt;
&lt;p&gt;
 If &lt;code&gt;state-&amp;gt;reading&lt;/code&gt; is &lt;code&gt;IDLE&lt;/code&gt; there is nothing to
 play yet, and if &lt;code&gt;state-&amp;gt;playing&lt;/code&gt; is &lt;code&gt;DONE&lt;/code&gt; it is
 time to exit the program.
&lt;/p&gt;
&lt;pre&gt;
   jack_ringbuffer_t* rring = info-&amp;gt;reader_info-&amp;gt;ring;
   size_t space = jack_ringbuffer_read_space(rring);
   if (space == 0 &amp;amp;&amp;amp; state-&amp;gt;reading == DONE) {
     state-&amp;gt;playing = DONE;
     recap_mute(out, channel_count_r, nframes);
   } else {
     int err = uninterleave(out, channel_count_r, nframes, &amp;amp;next_value, rring);
     if (err) {
       ++info-&amp;gt;underruns;
       ERR("control thread: buffer underrun\n");
     }
   }
&lt;/pre&gt;
&lt;p&gt;
 This, the guts of the processing is simply uninterleaving the file data and
 writing it to the buffers of the appropriate output ports. Jack handles the
 rest.
&lt;/p&gt;
&lt;pre&gt;
   jack_ringbuffer_t* wring = info-&amp;gt;writer_info-&amp;gt;ring;
   int err = interleave(in, channel_count_w, nframes, &amp;amp;write_value, wring);
   if (err) {
     ++info-&amp;gt;overruns;
     ERR("control thread: buffer overrun\n");
   }
 }
&lt;/pre&gt;
&lt;p&gt;
 Similarly simple. Interleaving the input port data and writing to the writer
 thread’s ringbuffer.
&lt;/p&gt;
&lt;pre&gt;
 if (pthread_mutex_trylock(&amp;amp;read_lock) == 0) {
   pthread_cond_signal(&amp;amp;ready_to_read);
   pthread_mutex_unlock(&amp;amp;read_lock);
 }

 if (pthread_mutex_trylock(&amp;amp;write_lock) == 0) {
   pthread_cond_signal(&amp;amp;ready_to_write);
   pthread_mutex_unlock(&amp;amp;write_lock);
 }
 return 0;
}
&lt;/pre&gt;
&lt;p&gt;
 Data has been written to the writer thread’s ringbuffer and removed from the
 reader thread’s ringbuffer, so signal each thread to begin another iteration.
&lt;/p&gt;
&lt;h5&gt;Thread setup and running&lt;/h5&gt;
&lt;pre&gt;
static int setup_writer_thread(recap_io_info_t* info) {
 int status = 0;
 SF_INFO sf_info;
 sf_info.samplerate = jack_get_sample_rate(client);
 sf_info.channels = channel_count_w;
 sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_32;
 if ((info-&amp;gt;file = sf_open(info-&amp;gt;path, SFM_WRITE, &amp;amp;sf_info)) == NULL) {
   ERR("cannot open sndfile \"%s\" for output (%s)\n",
       info-&amp;gt;path, sf_strerror(info-&amp;gt;file));
   jack_client_close(client);
   status = EIO;
 }
 DEBUG("opened to write: %s\n", info-&amp;gt;path);
 DEBUG("writing %i channels\n", channel_count_w);
 info-&amp;gt;ring = jack_ringbuffer_create(sample_size * ring_size);
 memset(info-&amp;gt;ring-&amp;gt;buf, 0, info-&amp;gt;ring-&amp;gt;size);
 info-&amp;gt;state-&amp;gt;can_capture = 0;
 pthread_create(&amp;amp;info-&amp;gt;thread_id, NULL, writer_thread, info);
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 Set up resources for the writer thread then create the thread. This means
 opening a (multichannel) WAV file to write to, creating a ringbuffer, and
 touching all its allocated memory to prevent pagefaults later on.
&lt;/p&gt;
&lt;pre&gt;
static int setup_reader_thread(recap_io_info_t* info) {
 int status = 0;
 SF_INFO sf_info;
 sf_info.format = 0;
 DEBUG("opened to read: %s\n", info-&amp;gt;path);
 if ((info-&amp;gt;file = sf_open(info-&amp;gt;path, SFM_READ, &amp;amp;sf_info)) == NULL) {
   ERR("cannot read sndfile: %s\n", info-&amp;gt;path);
   status = EIO;
 }
 channel_count_r = sf_info.channels;
 frame_size_r = channel_count_r * sample_size;
 DEBUG("reading %i channels\n", channel_count_r);
 if (sf_info.samplerate != 44100) {
   ERR("jack sample rate must be 44100 (is %i)\n", sf_info.samplerate);
   cancel_process(proc_info);
 }
 info-&amp;gt;ring = jack_ringbuffer_create(sample_size * ring_size);
 memset(info-&amp;gt;ring-&amp;gt;buf, 0, info-&amp;gt;ring-&amp;gt;size);
 info-&amp;gt;state-&amp;gt;can_read = 0;
 pthread_create(&amp;amp;info-&amp;gt;thread_id, NULL, reader_thread, info);
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 Same purpose as the previous function but for the reader thread. Opens a
 (multichannel) WAV file to read from, creates a ringbuffer, and touches all
 its memory.
&lt;/p&gt;
&lt;p&gt;
 Similarites between these two functions could probably be extracted into a
 general &lt;code&gt;setup_io_thread()&lt;/code&gt; function.
&lt;/p&gt;
&lt;pre&gt;
static int run_io_thread(recap_io_info_t* info) {
 int* status;
 int ret;
 pthread_join(info-&amp;gt;thread_id, (void**) &amp;amp;status);
 if (status == PTHREAD_CANCELED) {
   ret = EPIPE;
 } else {
   ret = *status;
   free(status);
 }
 return ret;
}
&lt;/pre&gt;
&lt;p&gt;
 Joins to a thread and returns its exit status.
&lt;/p&gt;
&lt;h5&gt;Port registration and connection&lt;/h5&gt;
&lt;pre&gt;
static jack_port_t* register_port(char* name, int flags) {
  jack_port_t* port;
  if ((port = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, flags, 0)) == 0) {
    DEBUG("cannot register port \"%s\"\n", name);
    jack_client_close(client);
    exit(1);
  }
  return port;
}
&lt;/pre&gt;
&lt;p&gt;
  Register the named port with the jack process.
&lt;/p&gt;
&lt;pre&gt;
static void connect(const char* out, const char* in) {
 if (jack_connect(client, out, in)) {
   DEBUG("cannot connect port \"%s\" to \"%s\"\n", out, in);
   jack_client_close(client);
   exit(1);
 }
}

static void connect_ports(char** in_names, char** out_names) {
 int i;
 char* s;
 for (i = 0; i &amp;lt; channel_count_w; i++) {
   char prt[32];
   sprintf(prt, "recapture:input_%i", i);
   char* shrt = prt + strlen("recapture:");
   register_port(shrt, JackPortIsInput);
   recap_in_ports[i] = jack_port_by_name(client, prt);
   if ((s = in_names[i]) != NULL) connect(s, prt);
 }
 recap_in_ports[i] = NULL;
 for (i = 0; i &amp;lt; channel_count_r; i++) {
   char prt[32];
   sprintf(prt, "recapture:output_%i", i);
   char* shrt = prt + strlen("recapture:");
   register_port(shrt, JackPortIsOutput);
   recap_out_ports[i] = jack_port_by_name(client, prt);
   if ((s = out_names[i]) != NULL) connect(prt, s);
 }
 recap_out_ports[i] = NULL;
}
&lt;/pre&gt;
&lt;p&gt;
 Initialize &lt;code&gt;recap_in_ports&lt;/code&gt; and &lt;code&gt;recap_out_ports&lt;/code&gt; with
 this client’s in and out ports, and connect them to the supplied jack ports.
&lt;/p&gt;
&lt;h5&gt;Set callbacks and handlers&lt;/h5&gt;
&lt;pre&gt;
static void set_handlers(jack_client_t* client, recap_process_info_t* info) {
 jack_set_process_callback(client, process, info);
 jack_on_shutdown(client, jack_shutdown, info);
 signal(SIGQUIT, signal_handler);
 signal(SIGTERM, signal_handler);
 signal(SIGHUP, signal_handler);
 signal(SIGINT, signal_handler);
}
&lt;/pre&gt;
&lt;p&gt;
 Set jack callbacks and signal handlers.
&lt;/p&gt;
&lt;h5&gt;Run jack client&lt;/h5&gt;
&lt;pre&gt;
static int run_client(jack_client_t* client, recap_process_info_t* info) {
 recap_state_t* state = info-&amp;gt;state;

 state-&amp;gt;can_play    = 1;
 state-&amp;gt;can_capture = 1;
 state-&amp;gt;can_read    = 1;

 int reader_status = run_io_thread(info-&amp;gt;reader_info);
 int writer_status = run_io_thread(info-&amp;gt;writer_info);
 int other_status = 0;

 if (info-&amp;gt;overruns &amp;gt; 0) {
   ERR("recapture failed with %ld overruns.\n", info-&amp;gt;overruns);
   ERR("try a bigger buffer than -b %" PRIu32 ".\n", ring_size);
   other_status = EPIPE;
 }
 long underruns = info-&amp;gt;underruns + info-&amp;gt;reader_info-&amp;gt;underruns;
 if (underruns &amp;gt; 0) {
   ERR("recapture failed with %ld underruns.\n", underruns);
   ERR("try a bigger buffer than -b %" PRIu32 ".\n", ring_size);
   other_status = EPIPE;
 }
 return reader_status || writer_status || other_status;
}
&lt;/pre&gt;
&lt;p&gt;
 Run reader and writer threads, and return their status.
&lt;/p&gt;
&lt;p&gt;
 Looks like &lt;code&gt;can_play&lt;/code&gt;, &lt;code&gt;can_capture&lt;/code&gt;, and
 &lt;code&gt;can_read&lt;/code&gt; could be collapsed in to one field.
&lt;/p&gt;
&lt;h5&gt;Argument parsing&lt;/h5&gt;
&lt;pre&gt;
static void split_names(char* str, char** list) {
 int i = 0;
 char* s = strtok(str, ",");
 while (s != NULL) {
   list[i++] = s;
   s = strtok(NULL, ",");
 }
 list[i] = NULL;
}
&lt;/pre&gt;
&lt;p&gt;
 Port names given on the commandline are comma separated.
&lt;/p&gt;
&lt;pre&gt;
static void parse_arguments(int argc, char** argv, char** in_names, char** out_names) {
 char* optstring = "b:i:o:h";
 struct option long_options[] = {
   { "help", 0, 0, 'h' },
   { "bufsize", 1, 0, 'b' },
   { "inports", 1, 0, 'i' },
   { "outports", 1, 0, 'o' },
   { 0, 0, 0, 0 }
 };

 int c;
 int longopt_index = 0;
 int show_usage = 0;
 extern int optind;
 extern int opterr;
 opterr = 0;
 while ((c = getopt_long(argc, argv, optstring, long_options, &amp;amp;longopt_index)) != -1) {
   switch (c) {
   case 1:
     break;
   case 'h':
     show_usage = 1;
     break;
   case 'b':
     ring_size = atoi(optarg);
     break;
   case 'i':
     split_names(optarg, in_names);
     break;
   case 'o':
     split_names(optarg, out_names);
     break;
   default:
     show_usage = 1;
     break;
   }
 }

 if (show_usage == 1 || argc - optind &amp;lt; 2) {
   MSG("%s", usage);
   exit(1);
 }
}
&lt;/pre&gt;
&lt;p&gt;
 Straightforward argument handling.
&lt;/p&gt;
&lt;h5&gt;main&lt;/h5&gt;
&lt;pre&gt;
int main(int argc, char** argv) {
 recap_process_info_t info;
 recap_io_info_t reader_info;
 recap_io_info_t writer_info;
 recap_state_t state;
 memset(&amp;amp;info, 0, sizeof(info));
 memset(&amp;amp;reader_info, 0, sizeof(reader_info));
 memset(&amp;amp;writer_info, 0, sizeof(writer_info));
 memset(&amp;amp;state, 0, sizeof(state));
 info.reader_info = &amp;amp;reader_info;
 info.writer_info = &amp;amp;writer_info;
 info.state = &amp;amp;state;
 reader_info.state = &amp;amp;state;
 writer_info.state = &amp;amp;state;
 state.can_play = 0;
 state.reading = IDLE;
 state.playing = IDLE;
 proc_info = &amp;amp;info;
&lt;/pre&gt;
&lt;p&gt;
 Initialize info instances and touch their memory to prevent pagefaults.
&lt;/p&gt;
&lt;pre&gt;
 char* in_port_names[MAX_PORTS];
 char* out_port_names[MAX_PORTS];
 parse_arguments(argc, argv, in_port_names, out_port_names);

 proc_info-&amp;gt;reader_info-&amp;gt;path = argv[optind];
 proc_info-&amp;gt;writer_info-&amp;gt;path = argv[++optind];
&lt;/pre&gt;
&lt;p&gt;
 Port names and file paths.
&lt;/p&gt;
&lt;pre&gt;
 channel_count_w = array_length(in_port_names);
 frame_size_w = channel_count_w * sample_size;
&lt;/pre&gt;
&lt;p&gt;
 Writer thread channel count and frame size. Those for the reader thread are
 taken from the input file in &lt;code&gt;setup_reader_thread()&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;
 DEBUG("%s\n", proc_info-&amp;gt;reader_info-&amp;gt;path);
 if ((client = jack_client_open("recapture", JackNullOption, NULL)) == 0) {
   ERR("jack server not running?\n");
   exit(1);
 }

 set_handlers(client, proc_info);
&lt;/pre&gt;
&lt;p&gt;
 Connect to jack and set up jack and signal callbacks.
&lt;/p&gt;
&lt;pre&gt;
 int status = 0;
 if (!(status = setup_writer_thread(proc_info-&amp;gt;writer_info)) &amp;amp;&amp;amp;
     !(status = setup_reader_thread(proc_info-&amp;gt;reader_info))) {
   if (jack_activate(client)) {
     ERR("cannot activate client\n");
     status = 1;
   } else {
     connect_ports(in_port_names, out_port_names);
     DEBUG("connected ports\n");
     status = run_client(client, proc_info);
     jack_client_close(client);
   }
 }
&lt;/pre&gt;
&lt;p&gt;
 Provided the IO threads execute ok, run this client and then close it once
 &lt;code&gt;run_client()&lt;/code&gt; returns.
&lt;/p&gt;
&lt;pre&gt;
 io_free(proc_info-&amp;gt;reader_info);
 io_free(proc_info-&amp;gt;writer_info);
 return status;
}
&lt;/pre&gt;
&lt;p&gt;
 Free remaining resources and return.
&lt;/p&gt;
&lt;h4&gt;Running&lt;/h4&gt;
First start jackd, then run recapture like this:
&lt;pre&gt;
recapture -i system:in_1,system:in_2 -o system:out_1,system:out_2 at_least_two_channels_input.wav two_channels_out.wav
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-3238594757413075932?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/3238594757413075932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2009/07/multichannel-play-record-with-jack.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/3238594757413075932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/3238594757413075932'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2009/07/multichannel-play-record-with-jack.html' title='Multichannel play record with jack'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-6363204678720740053</id><published>2009-07-17T07:29:00.003+12:00</published><updated>2009-07-17T09:14:43.295+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='factor'/><title type='text'>alien.marshall: marshalling between factor and C</title><content type='html'>&lt;p&gt;
 &lt;a href="/2009/07/introducing-alieninline-vocabulary-for.html"&gt;&lt;code&gt;alien.inline&lt;/code&gt;&lt;/a&gt;
 is nice, but it would be even nicer to have factor values automatically
 marshalled to and from their C equivalents. &lt;code&gt;alien.marshall&lt;/code&gt;
 enables this.
&lt;/p&gt;
&lt;p&gt;
 A short example:
&lt;/p&gt;
&lt;pre&gt;
USING: alien.inline.syntax alien.marshall.syntax ;
IN: marshall-test

C-LIBRARY: short-example

CM-STRUCTURE: rectangle
   { "int" "width" }
   { "int" "height" } ;

CM-FUNCTION: int area ( rectangle c )
   return c.width * c.height;
;

CM-FUNCTION: void incr ( int* a, int delta )
   *a += delta;
;

;C-LIBRARY
&lt;/pre&gt;
&lt;p&gt;
 and output:
&lt;/p&gt;
&lt;pre&gt;
( scratchpad ) &amp;lt;rectangle&amp;gt; 3 &amp;gt;&amp;gt;width 5 &amp;gt;&amp;gt;height

--- Data stack:
T{ rectangle f ALIEN: 36777744 f }
( scratchpad ) area

--- Data stack:
15
( scratchpad ) 3 incr

--- Data stack:
18
&lt;/pre&gt;
&lt;p&gt;
 As you can see, struct fields are marshalled, as are struct arguments. Output
 parameters are unmarshalled and pushed on the stack after the return value (if
 not void).
&lt;/p&gt;
&lt;p&gt;
  Non–false &lt;code&gt;c-ptrs&lt;/code&gt; are not marshalled, they are passed to the C
  function unchanged. It is assumed that if you pass a &lt;code&gt;c-ptr&lt;/code&gt; you
  know what you are doing and can clean up after yourself.
&lt;/p&gt;
&lt;p&gt;
  Return values and output parameters which are pointers, are assumed to be
  pointers to a single value. Factor words which call C functions returning
  pointers to arrays (single or multi–dimensional) will need to include
  hand–coded unmarshalling.
&lt;/p&gt;
&lt;p&gt;
  Return pointers and output pointers are freed after unmarshalling. Struct
  fields are an exception to this: fields containing pointers will need to be
  explicitly freed once the struct is no longer needed (overriding the struct’s
  &lt;code&gt;dispose*&lt;/code&gt; method is a good way to do this).
&lt;/p&gt;
&lt;p&gt;
 &lt;code&gt;alien.marshall&lt;/code&gt;words follow the same pattern as
 &lt;code&gt;alien.inline&lt;/code&gt;, but with a &lt;code&gt;CM-&lt;/code&gt; prefix instead of
 &lt;code&gt;C-&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
 There are also &lt;code&gt;M-&lt;/code&gt; prefixed words. These do not generate C code.
 They behave like their counterparts in &lt;code&gt;alien.syntax&lt;/code&gt; with the
 addition of marshalling and unmarshalling of values.
&lt;/p&gt;
&lt;p&gt;
 Next up: &lt;code&gt;alien.c++-templates&lt;/code&gt;…
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-6363204678720740053?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/6363204678720740053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2009/07/alienmarshall-marshalling-between.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/6363204678720740053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/6363204678720740053'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2009/07/alienmarshall-marshalling-between.html' title='alien.marshall: marshalling between factor and C'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-7390204254356810092</id><published>2009-07-11T15:55:00.000+12:00</published><updated>2009-07-17T09:14:36.389+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>~/bin: scroff</title><content type='html'>&lt;p&gt;
  I play movies using mplayer, and it's somewhat annoying when my screen goes to
  sleep after half an hour. &lt;code&gt;scroff&lt;/code&gt; runs a command with
  gnome-screensaver or DPMS disabled (depending on which is available).
&lt;/p&gt;
&lt;pre&gt;
$ scroff mplayer big_buck_bunny_720p_stereo.ogg
&lt;/pre&gt;
&lt;p&gt;
  And the script:
&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh

if [[ -x `which gnome-screensaver-command 2&gt;/dev/null` ]]
then
    gnome-screensaver-command --inhibit &amp;amp;
    pid=$!
    "$@"
    kill $pid
elif [[ -x `which xset` ]] \
    &amp;amp;&amp;amp; [[ `xset q | grep "DPMS is Enabled"` ]]
then
    xset -dpms
    "$@"
    xset +dpms
else
    "$@"
fi
&lt;/pre&gt;
&lt;p&gt;
  Since I use mplayer all the time I've saved the following as ~/bin/mplayer:
&lt;/p&gt;
&lt;pre&gt;
  #!/bin/sh

  scroff /usr/bin/mplayer "$@"
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-7390204254356810092?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/7390204254356810092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2009/07/bin-scroff.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/7390204254356810092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/7390204254356810092'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2009/07/bin-scroff.html' title='~/bin: scroff'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-2639160881695377483</id><published>2009-07-11T14:26:00.000+12:00</published><updated>2009-07-11T15:52:16.121+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><title type='text'>~/bin: until-same</title><content type='html'>&lt;p&gt;
  Imagine you've started downloading a large file from a server which doesn't
  support resuming. It's taking ages and you want to go to bed, but you also
  don't want the computer to stay on unnecessarily after completion of the
  download. What do you do?
&lt;/p&gt;
&lt;p&gt;
  You use &lt;code&gt;until-same&lt;/code&gt;: a simple shell command that repeats a command
  until it's output is the same twice in a row.
&lt;/p&gt;
&lt;pre&gt;
$ until-same -h
usage: until-same [ -v ] &amp;lt;interval&amp;gt; &amp;lt;command&amp;gt;

$ until-same 1m ls -l large.iso ; hibernate
&lt;/pre&gt;
&lt;p&gt;
  &lt;code&gt;&amp;lt;interval&amp;gt;&lt;/code&gt; uses the same syntax as the sleep command (not the
  shell builtin). &lt;code&gt;-v&lt;/code&gt; simply prints the output of each command execution
  to stdout.
&lt;/p&gt;
&lt;p&gt;
  And here's the script:
&lt;/p&gt;
&lt;pre&gt;
#!/bin/sh

verbose=0
if [[ "$1" == "-v" ]]; then
    verbose=1
    shift
fi

if [[ "$1" == "-h" ]] || [[ -z "$1" ]] || [[ -z "$2" ]]; then
    echo "usage: until-same [ -v ] &amp;lt;interval&amp;gt; &amp;lt;command&amp;gt;"
    exit 1
fi

interval="$1"
shift
curr=`$@`
prev="$curr NOTTHESAME"

while [[ "$curr" != "$prev" ]]; do
    env sleep "$interval"
    prev="$curr"
    curr=`$@`
    [[ $verbose == 1 ]] &amp;amp;&amp;amp; echo "$curr"
done
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-2639160881695377483?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/2639160881695377483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2009/07/bin-until-same.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/2639160881695377483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/2639160881695377483'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2009/07/bin-until-same.html' title='~/bin: until-same'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3891314539227613589.post-121862050648130348</id><published>2009-07-09T16:48:00.002+12:00</published><updated>2009-07-16T12:34:00.686+12:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='factor'/><title type='text'>alien.inline: inline C for factor</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;
  &lt;p&gt;&lt;b&gt;15/7/2009&lt;/b&gt; updated example to match source changes&lt;/p&gt;
      &lt;p&gt;
        Factor's FFI is rather nice in that it doesn't use C headers, however
        there are still times when writing a little glue code in C is necessary
        (e.g. to make macro values or C++ methods available to the factor
        FFi). This task is made more tractable by &lt;code&gt;alien.inline&lt;/code&gt; which enables
        writing C code in factor vocabularies. Said code is automatically
        compiled and linked to when the vocabulary is loaded.
      &lt;/p&gt;
      &lt;p&gt;
        Here is a short example:
      &lt;/p&gt;
      &lt;pre class='factor'&gt;
USING: alien.inline.syntax ;
IN: inline-test

C-LIBRARY: short-example

COMPILE-AS-C++

C-INCLUDE: &amp;lt;string&amp;gt;

C-TYPEDEF: std::string stdstr

C-FUNCTION: stdstr* new_std_str ( const-char* s )
    stdstr* x = new stdstr(s);
    return x;
;

ALIAS: &amp;lt;stdstr&amp;gt; new_std_str

C-FUNCTION: const-char* std_to_c_str ( stdstr* s )
    return s-&amp;gt;c_str();
;

ALIAS: std&amp;gt;c-str std_to_c_str

C-STRUCTURE: rectangle
    { "int" "width" }
    { "int" "height" } ;

C-FUNCTION: int area ( rectangle c )
    return c.width * c.height;
;

;C-LIBRARY
      &lt;/pre&gt;
      &lt;p&gt;
        and output, which is no different to normal FFI usage:
      &lt;/p&gt;
      &lt;pre class='factor'&gt;
( scratchpad ) "abc" &amp;lt;stdstr&amp;gt;

--- Data stack:
ALIEN: 16240640
( scratchpad ) std&amp;gt;c-str

--- Data stack:
"abc"
( scratchpad ) "rectangle" &amp;lt;c-object&amp;gt; 3 over set-rectangle-width 5 over set-rectangle-height

--- Data stack:
B{ 3 0 0 0 5 0 0 0 }
( scratchpad ) area

--- Data stack:
15
      &lt;/pre&gt;
      &lt;p&gt;
        All the parsing words. Some of them perform the same function as their
        analogues in alien.syntax, but also generate the equivalent C code. Each
        parsing word has a runtime equivalent.
      &lt;/p&gt;
      &lt;dl&gt;
        &lt;dt&gt;&lt;code&gt;C-LIBRARY: name&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;sets up variables&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;COMPILE-AS-C++&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;treat generated code as C++&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-INCLUDE: name&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;generates &lt;code&gt;#include name&lt;/code&gt;&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-LINK: name&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;adds &lt;code&gt;-lname&lt;/code&gt; to linker command&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-FRAMEWORK: name&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;adds &lt;code&gt;-framework name&lt;/code&gt; to linker command (OS X only)&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-LINK/FRAMEWORK: name&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;equivalent to &lt;code&gt;C-FRAMEWORK:&lt;/code&gt; on OS X and &lt;code&gt;C-LINK:&lt;/code&gt; everywhere else&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-TYPEDEF: old new&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;like &lt;code&gt;TYPEDEF:&lt;/code&gt; but generates a C typedef statement too&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-STRUCTURE: name pairs... ;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;like &lt;code&gt;C-STRUCT:&lt;/code&gt; but also generates equivalent C code&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;C-FUNCTION: return name args body... ;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;like &lt;code&gt;FUNCTION:&lt;/code&gt; but with a function body written in C or C++&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;RAW-C: multiline-string ;&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;insert a string into the generated C/C++ file; useful for macros and other details not implemented in &lt;code&gt;alien.inline&lt;/code&gt;; works the same as &lt;code&gt;STRING:&lt;/code&gt;&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;;C-LIBRARY&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;writes, compiles, and links generated code, then calls &lt;code&gt;add-library&lt;/code&gt;; does nothing if the shared library is younger than the factor source file&lt;/dd&gt;
        &lt;dt&gt;&lt;code&gt;DELETE-C-LIBRARY: name&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;delete the shared library file corresponding to &lt;code&gt;name&lt;/code&gt; (must be executed in the vocabulary where &lt;code&gt;name&lt;/code&gt; is defined); mainly useful in unit tests&lt;/dd&gt;
      &lt;/dl&gt;
      &lt;p&gt;
        The library file produced by the above example would be named
        &lt;code&gt;libinline-test_short-example&lt;/code&gt;; factor would see it as
        &lt;code&gt;inline-test_short-example&lt;/code&gt;.  Source and unlinked object files are
        written to &lt;code&gt;resource:temp/&lt;/code&gt; and linked libraries are written to
        &lt;code&gt;resource:alien-inline-libs/&lt;/code&gt;.
      &lt;/p&gt;
      &lt;p&gt;
        As of 9/7/2009 alien.inline is brand new, so there likely will be corner
        cases it does not handle so well. If you run into trouble, pipe up on
        the factor mailing list or look for jedahu on #concatenative.
      &lt;/p&gt;
      &lt;p&gt;
        Next up: &lt;a href="/2009/07/alienmarshall-marshalling-between.html"&gt;&lt;code&gt;alien.marshall&lt;/code&gt;&lt;/a&gt;&amp;hellip;
      &lt;/p&gt;
    &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3891314539227613589-121862050648130348?l=jedahu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jedahu.blogspot.com/feeds/121862050648130348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://jedahu.blogspot.com/2009/07/introducing-alieninline-vocabulary-for.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/121862050648130348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3891314539227613589/posts/default/121862050648130348'/><link rel='alternate' type='text/html' href='http://jedahu.blogspot.com/2009/07/introducing-alieninline-vocabulary-for.html' title='alien.inline: inline C for factor'/><author><name>jedahu</name><uri>http://www.blogger.com/profile/00404458748680160640</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
