<?xml version="1.0" encoding="ISO-8859-1" ?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>The Icon Bar (RSS 2.0 feed)</title>
    <link>http://www.iconbar.com/</link>
    <description>Technology news and views</description>
    <managingEditor>richard@--iconbar--.com</managingEditor>
    <language>en-gb</language>
    <copyright>(c) The Icon Bar 2009.  All rights reserved.</copyright>
    <lastBuildDate>Mon, 17 Mar 2008 12:00:00 GMT</lastBuildDate>
    <category>The Icon Bar: News</category>
    <ttl>15</ttl>
    <image>
      <title>The Icon Bar</title>
      <url>http://iconbar.com/images/logos/rss-TIB.gif</url>
      <link>http://www.iconbar.com/</link>
    </image>
  <item>
   <title>Merry Christmas and Happy New Year from The Icon Bar</title>
   <link>http://iconbar.com/comments/rss/news1218.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1218.html</guid>
   <description>Once again the time has come to wish you all a Merry Christmas. By the time you read this, chances are that Christmas has already been and gone, although I'm sure some of you will have a peek at the site today whilst chomping on your mince pies :)</description>
   <content:encoded>
    <![CDATA[
    <img src="http://www.iconbar.com/tibtheme/default/logos/xmas_hills.gif" align="right" alt="[TIB Christmas Logo]" style="background:#aaaaff;" />Once again the time has come to wish you all a Merry Christmas. By the time you read this, chances are that Christmas has already been and gone, although I'm sure some of you will have a peek at the site today whilst chomping on your mince pies :)</p><p>From everyone at The Icon Bar, we would like to wish you a Merry Christmas and a happy and prosperous New Year. Thanks for reading TIB in 2008 (what there was of it to read!) and we'll see you in 2009. Oh, and don't forget to vote in <a href="http://www.drobe.co.uk/article.php?id=2381">Drobe Awards 2008</a> poll while there's still time!</p><p><b>Links:</b><br /><a href="http://en.wikipedia.org/wiki/Christmas">Christmas</a> (Wikipedia)</p><p><a href="http://iconbar.com/comments/rss/news1218.html">3 comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Thu, 25 Dec 2008 00:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Video conversion on RISC OS</title>
   <link>http://iconbar.com/comments/rss/news1217.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1217.html</guid>
   <description>A while ago you may remember that I wrote an article about video conversion for RISC OS, and near the end raised the topic of video conversion on RISC OS using a port of ffmpeg.</description>
   <content:encoded>
    <![CDATA[
    <img src="/news/images/ffmpeg.png" align="right" width="68" height="68" hspace="2" vspace="2">A while ago you may remember that I wrote an article about <a href="/articles/Video_conversion_for_RISC_OS/index1096.html">video conversion for RISC OS</a>, and near the end raised the topic of video conversion <i>on</i> RISC OS using a port of <a href="http://ffmpeg.mplayerhq.hu/">ffmpeg</a>. Although the version of ffmpeg I originally tried on RISC OS was old and broken, Christopher Martin obviously thinks there's some merit to this approach, as he has recently produced <a href="http://www.users.on.net/~belles/software/ffmpeg/">!FFmpeg</a>, a working port of ffmpeg for RISC OS.</p><p>Once more in the interests of SCIENCE, I threw a few test videos at !FFmpeg and measured its performance against that of a similar version of ffmpeg running on my Windows PC.</p><br /> <h3>Test one: DVB-T</h3><p>Since my first article was largely concerned with converting recorded DVB-T (aka Freeview) TV programmes for watching on RISC OS, I figured the logical place to start would be with testing that. I copied a short clip over to my Iyonix and attempted to convert it to a suitable resolution for playback (416x312x25fps MPEG 1 @ 850kbps). The conversion rate was about as bad as I was expecting - 3fps. But at least it did work, and the resulting file was played back through <a href="http://users.skynet.be/Andre.Timmermans/image/kinoamp/kinoamp.htm">!KinoAMP</a> without any problems.</p><p>Of course since there's currently no software/hardware available to record DVB-T on RISC OS, there's little point in transferring multi-gigabyte files over to a RISC OS machine in order to encode them - you might as well use the PC that recorded the programme in the first place. In my case, my 2.6GHz PC was able to re-encode the test clip at a much more acceptable 235fps.</p><h3>Test two: YouTube</h3><p>For this test I saved a .flv file from YouTube and converted it for playback. Since the video resolution was only 320x240, I decided to keep things simple and just used the !FFmpeg WIMP frontend to handle the conversion for me (more on that later).</p><p>End result: My Iyonix achieved a conversion rate of 11fps. Since the !FFmpeg frontend used the -sameq option, the quality of the video did not degrade due to the transcoding, but the output file was 3 times the size of the input. Nevertheless, KinoAMP was able to play it back without any problems.</p><p>Performing the same conversion on my PC resulted in a conversion rate of 1080fps - so still about 100 times faster than what RISC OS can offer.</p><h3>Test three: YouTube on a RiscPC</h3><p>Since the conversion rate on the Iyonix was nearly acceptable (or at least in the double-digit range) I decided I might as well try converting the same .flv video to MPEG on my StrongARM RiscPC, with the right settings for RiscPC playback (288x216x25fps video @ 250kbps, same 64kbps mp3 audio as source). The conversion ran at a less than stellar 2-3 fps, but once more the output was watchable when played back through KinoAMP, and the video quality hadn't degraded too much.</p><h3>The !FFmpeg frontend</h3><p>As mentioned earlier, !FFmpeg comes with a RISC OS frontend, which can simplify the task of converting many videos. However it doesn't allow you to specify the output resolution, so if you're converting a high resolution video, or one for playback on a RiscPC, you'll have to run ffmpeg from the command line for the best results. Unfortunately that isn't as easy as it sounds, as ffmpeg seems to have trouble finding files unless you give it the full pathname or remove the filename extensions (which could make life even more difficult since you'll have to specify the output container format manually).</p><h3>Conclusion</h3><p>Video conversion on RISC OS - it's now possible, but the poor performance of converting even low-resolution videos like those on YouTube means that it still isn't something you'd really want to do unless you have no better alternative available. However it is worth noting that the current version seems to have been compiled against GCC 3.4.6, which means it's missing out on the soft-float support available in the GCC 4.1.1 pre-release. Soft-float support could result in a significant performance boost, even if it still doesn't result in better-than-realtime conversion.</p><p>If you really do want to watch YouTube on RISC OS, you might want to have a look at <a href="http://www.users.on.net/~belles/software/murnong/">Murnong</a>, an ffmpeg-based solution again created by Christopher Martin. The transcoding performance isn't likely to be any better, but at least it will simplify the number of steps you need to go through to get a video downloaded and converted.</p><p><a href="http://iconbar.com/comments/rss/news1217.html">1 comment in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Sat, 20 Dec 2008 20:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Midlands User Group Christmas Show Report</title>
   <link>http://iconbar.com/comments/rss/news1216.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1216.html</guid>
   <description>Saturday 6 December saw the Midlands User Group's RISC OS Christmas Show in Birmingham. The show was held at Birmingham University's Guild of Students, and was attended by a steady stream of people throughout the day. What follows is a brief report and some photos from the event.</description>
   <content:encoded>
    <![CDATA[
    Saturday 6 December saw the Midlands User Group's RISC OS Christmas Show in Birmingham. The show was held at Birmingham University's Guild of Students, and was attended by a steady stream of people throughout the day. What follows is a brief report and some photos from the event.</p><p>The main announcements for this show were from RISCOS Ltd. who had their new RISC OS Upgrade CD available, along with a "RISC OS Virtually Free" CD, which for a few quid gives you a licensed copy of RISC OS 4 to be used with emulators, and comes with instructions for some emulators on how to get started.</p><p>RISC OS Open Ltd. had an Iyonix which was running a ROM image built from the publicly available sources, and were selling calendars, t-shirts, mouse mat and coaster packs and source CDs.</p><p>Orpheus and RISC OS Now were also present, notably with free mince pies for the punters (which were yummy!). A new issue of RISC OS Now was available, albeit in A5 size instead of the usual A4 size booklet. Paul Vigay took along an Acorn System One to show off, along with an Enigma Machine kit, which were on display on the Orpheus stand.</p><p>NetSurf were in attendance showing off the latest builds of the open source browser, including a Linux build with support for tabbed browsing. CJE had their mini-tardis at the show for all the spares you could need, and R-Comp had their usual selection of RISC OS products for punters, ranging from Games to laptops.</p><p>The Acorn through the Ages display contained working examples of Acorn kit from days gone by, from the Atom through to the Omega (although the Omega had an amusing sign on the top stating "Microdigital Omega - Non working". The BBC Model B on display sadly went up in smoke during the afternoon, leaving the unmistakable smell of burning electronics hanging around that half of the room for the afternoon.</p><p>Shortly before the show ended, the raffle was held. Each punter who entered had a number on their ticket (I was visitor number four!), and the number was picked randomly by a programme on Graham Shaw's computer, with source code available for anyone who wanted to check it was all above board. The winning number, as I recall, was 20.</p><p>Shortly after the raffle, the show drew to a close as crowds thinned out. Overall, it seemed a productive day. There were plenty of people at most of the stands throughout the day, and it looked from my viewpoint at the NetSurf stand that a fair amount of money changed hands around the room. Next year's show will be on the 5th of December. I'll leave you now to peruse the photos below from today's event. For those who missed them, the live feed and its photos are still available for the time being, <a href="http://twitter.com/riscos">here</a>.<br /> <h2>Show photos</h2><p><small>Click a photo for a larger view</small><br /><table border="0" cellpadding="0" width="100%" cellspacing="2"><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/1.jpg" target="_blank"><img src="/news/midlands2008/t_1.jpg" alt="Show photo" /></a><br />The show venue</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/2.jpg" target="_blank"><img src="/news/midlands2008/t_2.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/3.jpg" target="_blank"><img src="/news/midlands2008/t_3.jpg" alt="Show photo" /></a><br />The show is this-a-way</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/4.jpg" target="_blank"><img src="/news/midlands2008/t_4.jpg" alt="Show photo" /></a></td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/5.jpg" target="_blank"><img src="/news/midlands2008/t_5.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/6.jpg" target="_blank"><img src="/news/midlands2008/t_6.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/7.jpg" target="_blank"><img src="/news/midlands2008/t_7.jpg" alt="Show photo" /></a><br />Exhibitors getting ready</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/8.jpg" target="_blank"><img src="/news/midlands2008/t_8.jpg" alt="Show photo" /></a><br />Punters start to trickle in</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/9.jpg" target="_blank"><img src="/news/midlands2008/t_9.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/10.jpg" target="_blank"><img src="/news/midlands2008/t_10.jpg" alt="Show photo" /></a><br />Paul Vigay looks like he's up to something...</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/11.jpg" target="_blank"><img src="/news/midlands2008/t_11.jpg" alt="Show photo" /></a><br />He's got an Acorn System One, and a built Enigma kit</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/12.jpg" target="_blank"><img src="/news/midlands2008/t_12.jpg" alt="Show photo" /></a><br />ROL look ready for Christmas</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/13.jpg" target="_blank"><img src="/news/midlands2008/t_13.jpg" alt="Show photo" /></a><br />Paul Vigay shows off his kit to Drobe's Photographer and ROOL</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/14.jpg" target="_blank"><img src="/news/midlands2008/t_14.jpg" alt="Show photo" /></a><br />CJE get busy</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/15.jpg" target="_blank"><img src="/news/midlands2008/t_15.jpg" alt="Show photo" /></a><br />RISC OS Now was popular with the punters (and exhibitors!)</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/16.jpg" target="_blank"><img src="/news/midlands2008/t_16.jpg" alt="Show photo" /></a><br />Advantage6 had some A9 all-in-ones</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/17.jpg" target="_blank"><img src="/news/midlands2008/t_17.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/18.jpg" target="_blank"><img src="/news/midlands2008/t_18.jpg" alt="Show photo" /></a><br />ROL check out the opposition</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/19.jpg" target="_blank"><img src="/news/midlands2008/t_19.jpg" alt="Show photo" /></a><br />John Cartmell looking amused</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/20.jpg" target="_blank"><img src="/news/midlands2008/t_20.jpg" alt="Show photo" /></a><br />Despite this photo, the Atom <i>was</i> working</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/21.jpg" target="_blank"><img src="/news/midlands2008/t_21.jpg" alt="Show photo" /></a><br />This BBC B later went up in smoke, leaving the smell of toasty electronics hanging around for a while</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/22.jpg" target="_blank"><img src="/news/midlands2008/t_22.jpg" alt="Show photo" /></a><br />Archimedes and A3010 on display</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/23.jpg" target="_blank"><img src="/news/midlands2008/t_23.jpg" alt="Show photo" /></a><br />A5000, A7000 and RiscPC</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/24.jpg" target="_blank"><img src="/news/midlands2008/t_24.jpg" alt="Show photo" /></a><br />A portable BBC Master</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/25.jpg" target="_blank"><img src="/news/midlands2008/t_25.jpg" alt="Show photo" /></a><br />R-Comp had lots to sell</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/26.jpg" target="_blank"><img src="/news/midlands2008/t_26.jpg" alt="Show photo" /></a><br />Orpheus special offers</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/27.jpg" target="_blank"><img src="/news/midlands2008/t_27.jpg" alt="Show photo" /></a><br />NetSurf</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/28.jpg" target="_blank"><img src="/news/midlands2008/t_28.jpg" alt="Show photo" /></a><br />A rather dark MW Software (sorry Martin!)</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/29.jpg" target="_blank"><img src="/news/midlands2008/t_29.jpg" alt="Show photo" /></a><br />Microdigital Omega. Non working</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/30.jpg" target="_blank"><img src="/news/midlands2008/t_30.jpg" alt="Show photo" /></a><br />Home-Made portable</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/31.jpg" target="_blank"><img src="/news/midlands2008/t_31.jpg" alt="Show photo" /></a><br />Another look at that non working Omega</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/32.jpg" target="_blank"><img src="/news/midlands2008/t_32.jpg" alt="Show photo" /></a><br />A9 Home in a briefcase, and a VA-running laptop</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/33.jpg" target="_blank"><img src="/news/midlands2008/t_33.jpg" alt="Show photo" /></a><br />Kinetic RiscPC in a tower case</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/34.jpg" target="_blank"><img src="/news/midlands2008/t_34.jpg" alt="Show photo" /></a><br />ROOL goodies</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/35.jpg" target="_blank"><img src="/news/midlands2008/t_35.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/36.jpg" target="_blank"><img src="/news/midlands2008/t_36.jpg" alt="Show photo" /></a><br />Meteors, anybody?</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/37.jpg" target="_blank"><img src="/news/midlands2008/t_37.jpg" alt="Show photo" /></a><br />Linux port of NetSurf with tabbed browsing</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/38.jpg" target="_blank"><img src="/news/midlands2008/t_38.jpg" alt="Show photo" /></a><br />Iyonix running a ROM image built from publicly available sources</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/39.jpg" target="_blank"><img src="/news/midlands2008/t_39.jpg" alt="Show photo" /></a><br />General show atmosphere</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/40.jpg" target="_blank"><img src="/news/midlands2008/t_40.jpg" alt="Show photo" /></a><br />Another look at PV's Acorn System One and Enigma kit</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/41.jpg" target="_blank"><img src="/news/midlands2008/t_41.jpg" alt="Show photo" /></a><br />Electron</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/42.jpg" target="_blank"><img src="/news/midlands2008/t_42.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/43.jpg" target="_blank"><img src="/news/midlands2008/t_43.jpg" alt="Show photo" /></a><br />Another look at the Omega</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/44.jpg" target="_blank"><img src="/news/midlands2008/t_44.jpg" alt="Show photo" /></a></td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/45.jpg" target="_blank"><img src="/news/midlands2008/t_45.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/46.jpg" target="_blank"><img src="/news/midlands2008/t_46.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/47.jpg" target="_blank"><img src="/news/midlands2008/t_47.jpg" alt="Show photo" /></a><br />Paul Vigay had free mince pies!</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/48.jpg" target="_blank"><img src="/news/midlands2008/t_48.jpg" alt="Show photo" /></a><br />I decided to not ask.</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/49.jpg" target="_blank"><img src="/news/midlands2008/t_49.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/50.jpg" target="_blank"><img src="/news/midlands2008/t_50.jpg" alt="Show photo" /></a><br />The show starts to wind down</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/51.jpg" target="_blank"><img src="/news/midlands2008/t_51.jpg" alt="Show photo" /></a></td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/52.jpg" target="_blank"><img src="/news/midlands2008/t_52.jpg" alt="Show photo" /></a><br />Artworks and Easi/TechWriter highlights</td></tr><tr><td valign="top" colspan="4"> </td></tr><tr><td valign="top" width="25%" align="center"><a href="/news/midlands2008/53.jpg" target="_blank"><img src="/news/midlands2008/t_53.jpg" alt="Show photo" /></a><br />R-Comp find a quiet moment</td><td valign="top" width="25%" align="center"><a href="/news/midlands2008/54.jpg" target="_blank"><img src="/news/midlands2008/t_54.jpg" alt="Show photo" /></a><br />Just after the raffle. The chap behind the chap in a suit won.</td><td valign="top" width="25%" align="center"> </td><td valign="top" width="25%" align="center"> </td></tr></table></p><p><a href="http://iconbar.com/comments/rss/news1216.html">10 comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Sat, 06 Dec 2008 20:43:00 GMT</pubDate>
  </item>
  <item>
   <title>Midlands User Group Christmas Show 2008 Live Feed</title>
   <link>http://iconbar.com/comments/rss/news1215.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1215.html</guid>
   <description>The Midlands Christmas Show kicks off tomorrow. During the day, The Icon Bar will (mobile phone signal permitting) have a live update feed from the show for those of you who can't make it to the show, which you can see at the following URL...</description>
   <content:encoded>
    <![CDATA[
    The Midlands Christmas Show kicks off tomorrow. During the day, The Icon Bar will (mobile phone signal permitting) have a live update feed from the show for those of you who can't make it to the show, which you can see at the following URL:<br /><center><font size="+1"><b><a href="http://twitter.com/riscos">http://twitter.com/riscos/</a></b></font></center><br />A more detailed report on the show will be available soon after the show, which is scheduled to take place at the Birmingham University Guild of Students on Saturday from 10:30am until 4:30pm.</p><p><b>Further information:</b><br /><a href="http://twitter.com/riscos/">Live update twitter feed</a><br /><a href="http://twitpic.com/photos/riscos">Live photos</a><br /><a href="http://www.mug.riscos.org/show08/">Midlands User Group Christmas Show website</a></p><p><a href="http://iconbar.com/comments/rss/news1215.html">No comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Fri, 05 Dec 2008 14:46:00 GMT</pubDate>
  </item>
  <item>
   <title>Building the Dream 4 - Random city basics</title>
   <link>http://iconbar.com/comments/rss/news1214.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1214.html</guid>
   <description>As stated in the last article, this time I'll be looking at what went into the MK I map generator for my eternally work-in-progress game, DeathDawn.</description>
   <content:encoded>
    <![CDATA[
    <img src="/news/images/dream/logo.png" align="right" hspace="2" vspace="2">As stated in <a href="/articles/Building_the_Dream_3_-_Random_map_generators_redux/index1211.html">the last article</a>, this time I'll be looking at what went into the MK I map generator for my eternally work-in-progress game, <a href="http://www.phlamethrower.co.uk/riscos/deathdawn.php">DeathDawn</a>.</p><p>Specifically, I'll be looking at the implementation and evolution of the following components of the generator:<ul><li><b>City block placement</b>. This is arguably the most important stage as it defines the overall layout of the city.</li><li><b>Edge and node linking</b>. A housekeeping stage that prepares the data structures for the road weighting stage.</li><li><b>Road weighting</b>. A city with roads which all have the same number of lanes isn't very realistic, so this stage uses an algorithm to determine the number of lanes each road should have.</li><li><b>Road and building painting</b>. With the city structure generated, all that's left is to translate it into the format used by the engine during actual gameplay.</li></ul> <h3>City block placement</h3><p><h4>Choice of algorithm</h4><p>If I wanted the city to look like a city, the choice of algorithm for laying out the city blocks is undoubtedly one of the most important choices to be made. At the time, I had several options available:<ol><li>The <a href="/articles/Random_map_generators/index1114.html">previously-described algorithm used in maze game GAIO</a>, where one large room is recursively split into smaller rooms along either the horizontal or vertical axis. Except in the case of DeathDawn the rooms would be buildings and the walls would be roads.</li><li>A solution borrowed from elsewhere, for example that used by <a href="https://www.cs.auckland.ac.nz/~roboteam/">Team Black Sheep</a>'s <a href="https://www.cs.auckland.ac.nz/~roboteam/documents/RandomMapGenerator.pdf">Robocup Rescue city generator</a>. In the above-named example roads are placed onto the lines of an irregularly-spaced grid, then some roads are removed at random to enlarge the size of some city blocks, and then random offsets are applied to the node coordinates in order to add more bends and hide the fact that the roads are based around a rigid grid structure. All except the last step would be applicable for DeathDawn, due to the near impossibility of representing roads that don't run along the 4 cardinal directions.</li><li>An entirely new algorithm developed with DeathDawn in mind</li></ol>In the end, the decision was made to develop a new algorithm. The GAIO algorithm was deemed inappropriate due to its tendency to generate one long road running from one edge of the city to another, making the output feel too artificial. The Black Sheep Robocup Rescue generator was also deemed inappropriate, since it relied too much on the random displacement of nodes (and thus support for diagonal roads) in order to generate the desired effect.</p><p>Other useful food for thought during this development process included Nikos A. Salingaros's keynote speech <a href="http://zeta.math.utsa.edu/~yxk833/connecting.html">"Connecting the Fractal City"</a>, presented at the 5th Biennial of towns and town planners in Europe.<h4>Implementation</h4><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:220px;float:right;"><a href="/news/images/dream/4_fig1.png" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/4_fig1sm.png"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 1</strong><br>Output of the first city block generator (Click for larger)</p><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0 0;"><a href="/news/images/dream/4_fig2.png" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/4_fig2sm.png"></a></p><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 2</strong><br>Output of the tweaked city block generator (Click for larger)</p></div>I was essentially back at square one - how do I create a realistic looking city block structure? Some roads need to be long and straight, others need to be narrow and twisty. Some buildings need to be big, others need to be small. Some need to be regular, some need to be irregular.</p><p>Although I could try building a complex fractal-based generator, I decided to go with the simplest approach possible and build from there. Starting in the top-left corner of the map, the confusingly-named <tt>magic_road_algorithm()</tt> function would fill the map with city blocks (<tt>cblocks</tt>), laying them down one at a time next to each other. Each block would be rectangular in shape (for now, at least), and would be a random size (within certain limits). With a little tweaking, this algorithm worked surprisingly well.<h5>Initial problems</h5><p>Although the first version worked, it did suffer from problems. Mainly that everything had a habit of shrinking and shifting to the left as it went further down the map, and there were many instances of city blocks which are either too small or non-existent (i.e. two roads placed directly next to each other). When you take into account the fact that roads shown in figures 1 and 2 are single-lane roads, you can see how this could cause problems when the roads are widened by later stages of the generator.<h5>Tweak #1 - cblock size selection</h5><p>The first tweak was to the <tt>cblock</tt> size selection. In the initial code, the algorithm would scan the map to work out the largest <tt>cblock</tt> that could be placed, and then select a block that fits within that area (and also obeys the min/max block size). However this fails to take into account the requirements of the next block to be placed, and frequently results in situations where the next block is forced to be smaller than the minimum size. Due to the top-to-bottom, left-to-right scanning and filling of the map this results in the large number of thin yet tall blocks seen in figure 1, particularly along the right hand edge of the map.</p><p>By altering the algorithm to take into account the minimum size constraint of the next block (both in the X and Y axes), avoiding a split if the next block would be too small, the number of too-small blocks was reduced significantly.</p><p><h5 style="clear: both;">Tweak #2 - Generate longer straight roads</h5><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:256px;float:right;"><img style="display:block;" border=0 src="/news/images/dream/4_fig3.png"><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 3</strong><br>A diagram showing city block creation. The numbers indicate the order in which the blocks are created.</p></div>The output of the first generator suffered from a problem where the average length of the vertical roads was higher than the average length of the horizontal roads. This is another artifact that's the result of the top-to-bottom, left-to-right scanning order. As you can see from figure 3, the uneven heights of blocks 2, 3 and 4 places width constraints on blocks 6 and 7. Unless those constraints are broken, the vertical road running between 2 and 3 (and 3 and 4) will stretch to the bottom of the map, and there will never be a horizontal road below block 3 that's wider than block 3. The only way to break the constraints is to make two adjacent blocks have their bottom edges in line with each other, like with blocks 7 and 4.</p><p>The problem with the original generator was that because the widths and heights of the blocks are both random, the chances of a situation like 7 and 4 occuring are relatively slim - only 1 in N, where N is the maximum block height.</p><p>A simple solution to this problem was discovered; a <tt>uniformity</tt> parameter was added to the function. This parameter gives the random chance of the new <tt>cblock</tt> having its bottom edge in line with the bottom edge of the block to the left. If the <tt>uniformity</tt> says not to place the two in line, then a random height will be chosen as usual. By tweaking this value (current generators use the value of 30%) a satisfactory result was produced, where the city appears to have an equal number/length of long horizontal and vertical roads.<h3>Edge and node linking</h3><p>Although the <tt>magic_road_algorithm()</tt> function creates a list of <tt>cblocks</tt>, and those <tt>cblocks</tt> are linked into the <tt>cbmap</tt>, the blocks don't have any direct way of enumerating their neighbours. And more importantly for the road weighting code, there are no <tt>edge</tt> or <tt>corner</tt> structures for the road code to manipulate.</p><p>The <tt>build_edges_and_nodes()</tt> function fixes this by using the <tt>cbmap</tt> to scan the area surrounding each <tt>cblock</tt>, creating <tt>edge</tt> structures between each pair of neighbouring blocks. The <tt>edge</tt> list is then used along with the <tt>cbmap</tt> again to work out what <tt>cblocks</tt> are at the end of each edge, to create and link the <tt>corner</tt> structures.</p><p>The end result is a fully interlinked network of <tt>cblocks</tt>, <tt>edges</tt> and <tt>corners</tt>, as seen in figures 5 and 6 from the preceding article. <a href="/articles/Building_the_Dream_3_-_Random_map_generators_redux/index1211.html">Remember to have a quick look back at that article if none of this is making any sense!</a><h3>Road weighting</h3><p>The <tt>edge</tt> structures are treated by the map generator as being individual segments of road. But a city that contains roads that are all the same width isn't very realistic, so a 'weighting' algorithm is used to decide how popular (and therefore how wide) each road should be. This algorithm (in the <tt>weight_road_algorithm()</tt> function) uses an idea borrowed from The Black Sheep's Robocup entry, whereby a number of simulated journeys through the city are made and statistics gathered for what the most popular roads are. These journeys are simulated using an <a href="http://en.wikipedia.org/wiki/A*_search_algorithm">A* algorithm</a> to find the 'best' route between two random points in the city (i.e. two <tt>corner</tt> structs). By performing several thousand journeys and counting how many times each road is used, the most popular roads can be identified, and they can be upgraded to the widest width possible (for DeathDawn, this is 6 lanes). Other, lesser popular roads are given 4 lanes, while the majority are left with 2 lanes. Finally the least popular roads are downgraded to footpaths, to add some more variety to the city.<h4>Implementation details</h4><p>Like all A* implementations, the one used by the road weighting algorithm relies on a <a href="http://en.wikipedia.org/wiki/Priority_queue">priority queue</a> data structure to store all the partial paths and decide which to process next. In the case of the road weighting algorithm, the priority queue contains pointers to <tt>road_path</tt> structures:</p><p><code>typedef struct _road_path {<br />  int l;<br />  struct _road_path *next;<br />  corner *c;<br />  struct _road_path *lnext;<br />} road_path;</code><ul><li>The <tt>l</tt> member contains the current total length of the path. This is used as part of the priority queue sorting function to decide which <tt>road_path</tt> to expand next.</li><li>The <tt>next</tt> member points to the <tt>road_path</tt>'s predecessor along the travel route. A more logical name would probably be <tt>prev</tt>, but <tt>next</tt> is the name that's stuck.</li><li>The <tt>c</tt> member points to the <tt>corner</tt> which this path stops at.</li><li>The <tt>lnext</tt> member is used to manage a linked list of all the <tt>road_paths</tt>, to allow them all to be deleted at the end of each journey simulation. It has no bearing upon the A* algorithm itself.</li></ul>At the start of each journey simulation, a single <tt>road_path</tt> is inserted into the priority queue. This has a route length of 0, a null <tt>next</tt> pointer, and points to the 'start' <tt>corner</tt> in the journey. Then, for each iteration of the A* algorithm, the head element is removed from the priority queue, and the <tt>weight_road_add()</tt> function is called to expand the partial path in every possible direction (i.e. along the four <tt>edges</tt> pointed to by the <tt>edges</tt> member of the <tt>corner</tt> that the path links to). Once a <tt>road_path</tt> is generated which lies ontop of the 'end' <tt>corner</tt>, the process stops.</p><p>But how does this help us find the quickest route?</p><p>Simple: The <tt>next</tt> pointer of each new <tt>road_path</tt> is made to point towards the parent <tt>road_path</tt>. This means that, for the <tt>road_path</tt> which lies ontop of the 'end' <tt>corner</tt>, if you followed the <tt>next</tt> pointers you would travel along the quickest route back to the 'start' <tt>corner</tt>. With a little bit of extra logic to translate <tt>corner</tt> pairs into <tt>edges</tt>, you can therefore work out which <tt>edges</tt> are used in the journey and increase their use counts.</p><p>One important optimisation applied to the basic algorithm is that each <tt>corner</tt> is only processed once. This is implemented by the use of the <tt>visited</tt> flag of the <tt>corner</tt> structure. The flag is set the first time a <tt>road_path</tt> is generated for that corner, and any subsequent attempts to generate a path for that corner will fail. This optimisation is permissible because although there may be multiple paths towards each <tt>corner</tt>, we are only interested in the best (i.e. shortest) path to each corner - and due to the nature of A* the best path will always<sup>1</sup> be the first one generated. Without this optimisation the number of generated partial paths has the potential to increase exponentially, increasing both memory costs and execution time of the algorithm (and when you've got to perform several thousand route simulations to generate the road widths, execution time becomes very important). With the optimisation in place, you can be guaranteed to generate no more <tt>road_paths</tt> than there are <tt>corners</tt>. Care is taken to make sure the <tt>visited</tt> flag is cleared after each journey simulation - this is done in the loop that runs through the <tt>lnext</tt> pointer chain and deletes each path element.</p><p>One important thing to remember if you're implementing your own A* algorithm is that unless you implement a similar system to avoid generating redundant or looping paths, the algorithm may not terminate if there is no possible path between the two points. Well, it'll terminate when it runs out of memory, but that could easily take an unacceptably long time, or result in other bits of code failing.</p><p>Once the ten thousand or so simulated journeys have been made and the road use counts tallied, an array is produced containing pointers to each road <tt>edge</tt>. This array is then sorted in order of road popularity, from most popular to least. The first 10% of the array entries are upgraded to 6-lane roads; the next 20% to 4-lane, the next 60% to 2-lane, and the remaining 10% are downgraded to 1-lane footpaths.</p><p><small><sup>1</sup> Actually this is probably false - particularly once the following algorithm tweaks are taken into account - but at the very least the first path generated for each <tt>corner</tt> is good enough as far as the road weighting algorithm is concerned.</small><h4>Tweaking and improvements</h4><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:256px;float:right;"><a href="/news/images/dream/4_fig4.png" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/4_fig4sm.png"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 4</strong><br>Sample output of the current road weighting algorithm (Click for larger)</p></div>Initially the evaluation function used by the A* algorithm to find the 'best' route was concerned with only finding the shortest route. However during testing this was seen to have two problems: Firstly the most popular roads were all in the city centre, which resulted in the widest roads being placed there in a big cluster. This is somewhat unrealistic since the city centre, due to its popularity, is likely to be the part of the city with the least space available for wide roads to be placed. The second problem observed was that the wider roads tended to zig-zag quite a bit, which is again rather unrealistic since wide roads are meant to simulate motorways, which are generally wide and straight to allow high speeds and reduced travel time.</p><p>Fixing these problems required some quite simple tweaks to the code: When adding a new section to the route path, the path length is increased by 1 if it runs through the center of the map. The path length is also increased by 1 if it involves turning a corner. Since the A* algorithm aims to find the route with the lowest distance travelled, these changes successfully discouraged the code from generating wide roads in the city center, and significantly reduced the number of twists and turns in wide roads (although there are still various problems left to fix with wide roads).</p><p>Later on, beyond the MK 1 city generator, a problem was also identified where wide roads were being placed next to small city blocks - in fact, the roads were so wide that they were taking over the entire surface of the block (or more). Despite choosing a minimum <tt>cblock</tt> size that should avoid this, this situation is still possible due to the city block placement code being unable to guarantee that overly-small blocks won't be generated. To counter this, the <tt>edge</tt> creation function identifies when the edge is next to a too-small <tt>cblock</tt> and sets a flag in the edge (actually just changing its <tt>type</tt> it to <tt>SURFTYPE_PATH</tt>). Then the road weighting algorithm detects when a <tt>SURFTYPE_PATH</tt> edge is being inserted as part of the route, and adds a penalty of 2 to the route length, to discourage use of such paths and thus reduce the chances of wide roads being placed there.</p><p>Another post-MK 1 addition was a post-processing stage. Once the road widths have been calculated, any roads which overlap the map edge are forcibly reduced to paths, and any roads which are too wide for the <tt>cblock</tt> they are next to will be reduced in width until they no longer overlap the center of the <tt>cblock</tt> (This is in addition to the much gentler tweak where 2 is added to path lengths). Also it was observed that maps frequently contained unrealistically short sections of wide road (often only one <tt>edge</tt> long), so to combat this another processing step was added where any wide roads that are one <tt>edge</tt> long will be reduced in width.<h3>Road and building painting</h3><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:240px;float:right;"><a href="/news/images/dream/4_fig5.jpg" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/4_fig5sm.jpg"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 5</strong><br>Ugly road/building painting from the MK 1 generator (Click for larger)</p></div>Road and building painting in the MK 1 generator was very simple. Buildings were just large rectangular structures placed inside <tt>cblocks</tt> (preferably avodiing placing them ontop of roads, although that was often not the case), and roads were painted using a semi-intelligent algorithm designed to correctly place road markings (although it also failed rather poorly).</p><p>The only noteworthy feature of the MK 1 road and building painting was the use of the <tt>canvas</tt> system - although I've deliberately glossed over the structure of the final map representation, it's based around a simple compression system that doesn't lend itself well to modification. As a work around the <tt>canvas</tt> system was introduced, which allows sections of the map to be extracted in an uncompressed form, manipulated by the road/building painting code (including functions for rotating the <tt>canvas</tt> in 90 degree increments), and then inserted back into the map in its original position. Although the current implementation results in some redundant data being left behind in the compressed map, the canvas system has greatly simplified the task of generating the world.<h3>Next time...</h3><p>Next time I'll be taking a look at the stages added in the MK 2 generator, and any improvements made to existing stages which haven't been discussed above. In particular I'll go into detail about the method used to paint the road navigation flags, and into more detail about how the road and building painting works using its system of surface and building definitions.</p><p><a href="http://iconbar.com/comments/rss/news1214.html">No comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Fri, 28 Nov 2008 12:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Maybe you should read drobe.co.uk, instead?</title>
   <link>http://iconbar.com/comments/rss/news1213.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1213.html</guid>
   <description>Anyone reading this will have seen it by now, but just in case you gave up hope (but, erm, kept coming back to us for updates), Drobe has - after a few sparks of life recently - now relaunched.</description>
   <content:encoded>
    <![CDATA[
    <img src="http://www.iconbar.com/news/uploaded/droberelaunch.png" width="300" height="182" alt="Drobe.co.uk screenshot" align="right" style="border: solid black 1px; margin-left: 1em;" />Anyone reading this will have seen it by now, but just in case you gave up hope (but, erm, kept coming back to us for updates), <a href="http://www.drobe.co.uk/">Drobe</a> has - after a few sparks of life recently - <a href="http://www.drobe.co.uk/article.php?id=2329&nc=16">now relaunched</a>.</p><p>There has been some criticism of the new design; visually, I think it looks great, but then I've always enjoyed websites that are clean and simple and uncluttered. My <a href="http://www.iconbar.com/Take_her_off_the_monitor_I_dont_want_to_see_her_face/news1129.html#drobe">biggest complaints with the old design</a> were that the masthead looked too busy, and there wasn't enough white space; both of these issues have now been addressed. (Although can we have the logo back in colour? Pretty please?) </p><p>The biggest advantage to the new site is with the outside links to other articles. Previously stuck in a sidebar to the right, they are now fully integrated into the main article listing - making them easier to see immediately, and also allowing comments. This clearly makes the site easier to run, and <a href="http://www.diodesign.co.uk/">Chris Williams</a> has made no bones about the fact that if the site was to return, it needed to take up less of his time. (Co-running <a href="http://www.ganymede.tv/">a couple</a> <a href="http://noisetosignal.org/">of websites</a> myself, I fully sympathise.) This redesign solves that issue - now an interesting link can spark off a decent discussion rather than a full article, and the fact that a lively commenting community can fill in the gaps and make people come back to the site is vital when a site-runner is short on time. Moreover, there's also still room for full Drobe articles when time allows. A win all-round for everyone - or, at the very least, the best everyone was going to get in the current climate, as a return to <em>numerous</em> full-length updates from Drobe seems unlikely at this point.</p><p>I also personally like the disappearance of the comment and user ratings - I never found them especially helpful, and at times they almost felt like they were inviting trouble, rather than alleviating it. Maybe they'll come back in a future update - the launch article says some missing features are due back soon - but I really hope they don't.</p><p>Any bad things? Well, I can't say I like the linking of the headline of the launch article to an email address - I don't want my email client appearing unless I specifically want it to, and I don't really feel like having to check the browser status bar before clicking on every link. (I generally solve that issue on my websites by only linking email addresses to actual visible email addresses - but then I am a bit of a boring bastard.) Still, I don't expect this to be a major issue - most headlines will link to external articles or actual Drobe content, rather than email addresses.</p><p>A bigger disadvantage is the addition of threaded discussion. I've never liked it on websites, as I find it easier to follow all new comments on a discussion at the bottom of the page, rather than having to glance right through the list of comments. This is a personal dislike, though - many people love threaded discussion, and it does have its benefits too. It's certainly not something that would be easy to allow users to switch on and off - threaded discussion discourages the quoting of the previous comment, and so allowing users to switch it off would quickly render some comments unintelligable.</p><p>Still, overall, it's a great redesign. It would have been easy to give up on the site completely, or have unrealistic expectations of how much time you would actually be able to spend on the site to keep it running properly. The new look allows the site to be quickly updated, for commenters to keep the site interesting with new discussion - and also allows full articles to be posted as and when time allows. It's just great to have Drobe back again - hell, I haven't used RISC OS in ages, but I still drop in, because there's usually stuff worth reading there, external link or not.</p><p>And that bloody awful creased paper background has gone as well. Result.</p><p><em>On a TIB note, the irony is not lost on me that this is only the sixth article we've actually published on here this year. The idea of us being qualified to comment on how another site does is slightly laughable, admittedly. So feel free to laugh away - although we should have a fourth installment of <a href="http://www.iconbar.com/articles/tutorial/">our</em> Building the Dream <em>articles</a> up soon.</em></p><p><a href="http://iconbar.com/comments/rss/news1213.html">9 comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Tue, 11 Nov 2008 04:21:00 GMT</pubDate>
  </item>
  <item>
   <title>Phaethon Soundtrack</title>
   <link>http://iconbar.com/comments/rss/news1212.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1212.html</guid>
   <description>You may have spotted in the forums that Dan Wilson has released the soundtrack from hit game Phaethon in MP3 format. Well, we now have the whole lot archived in downloads section!</description>
   <content:encoded>
    <![CDATA[
    <img src="http://www.acornarcade.com/downloads/_images/Phaethon_Sound_Track.jpg" align="right" width="160" height="128" alt="Phaeton" hspace="5" />You may have spotted in the <a href="http://www.iconbar.com/forums/viewthread.php?threadid=10933#108403">forums</a> that <a href="http://www.last.fm/music/D.A.Wilson">Dan Wilson</a> has released the soundtrack from hit game <a href="http://www.last.fm/music/D.A.Wilson/!Phaethon+Game+Sound+Track">Phaethon in MP3 format</a>. Well, we now have the whole lot archived in <a href="/downloads/">downloads</a> section!</p><p><a href="http://www.acornarcade.com/downloads/Phaethon_Sound_Track.zip">Download file Phaethon_Sound_Track.zip (59803K)</a></p><p><a href="http://iconbar.com/comments/rss/news1212.html">No comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Sun, 28 Sep 2008 07:35:00 GMT</pubDate>
  </item>
  <item>
   <title>Building the Dream 3 - Random map generators, redux</title>
   <link>http://iconbar.com/comments/rss/news1211.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1211.html</guid>
   <description>After writing my first article about random map generators, I said I was going to write a city generator. Well now I have, and I'm here to tell you about it over the course of the next few Building the Dream articles.Blow your own trumpet much?</description>
   <content:encoded>
    <![CDATA[
    <img src="/news/images/dream/logo.png" align="right" hspace="2" vspace="2">After writing my <a href="/articles/Random_map_generators/index1114.html" target="_blank">first article about random map generators</a>, I said I was going to write a city generator. Well now I have, and I'm here to tell you about it over the course of the next few <i>Building the Dream</i> articles.<h3>Blow your own trumpet much?</h3><p>Although this article could just be dismissed as me blowing my own trumpet, I'm hoping that it will serve a somewhat more useful purpose. Before, during, and after working on the map generator I've searched the Internet for examples of similar generators and failed to find any. Sure, there are odd bits and pieces - descriptions of simpler generators that have given me ideas on some techniques to use, or <a href="http://kotaku.com/352086/new-introversion-game-will-spawn-cities-like-a-god" target="_blank">screenshots of sexy work-in-progress realtime generators</a>, but no actual algorithms or code samples from generators that come close to the required complexity of my generator.</p><p>So hopefully this article will become a useful reference point for anyone else wanting to undertake the task of writing a city generator, whether they're targeting a grid-based world representation like mine or a vector-based one.</p><p>Apart from discussing the algorithms used in the generator (and why they're used) I'll also talk about the data structures that are used - so even if you're not interested in random map generators you should be able to find plenty of examples of uses for the data structures <a href="/articles/Building_the_Dream_1_-_Container_data_structures/index1162.html" target="_blank">covered in the first Building the Dream article</a>, as requested quite some time ago.</p><p> <h3>Why random?</h3><p>This is the first question I asked myself - and the first question you should ask yourself if you're planning a random map generator (or any other kind of procedural content, really).<div style="border:2px solid #aaf;margin:2px;padding:0;width:171px;float:right;"><a href="/news/images/dream/3_fig1.png" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/3_fig1sm.jpg"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 1</strong><br>The Vice City map from GTA 1 - would you want to create a map as large and detailed as that? (Click for larger)</p></div>For me, the answer was fairly simple. <a href="http://www.phlamethrower.co.uk/riscos/deathdawn.php" target="_blank">DeathDawn</a> development had reached the limits of what the diminutive test map could offer. If I wanted to continue working, I had to create a new, full-size map for use in the game. I could either create the map by hand (after first writing a map editor), or get a random map generator to create it for me.</p><p>Although writing a map editor would probably take less time and effort than writing a map generator, I decided to go down the generator route. This is because I've tried creating a city by hand before, for GTA 1, and know that it's a lot of hard work. I'd be constantly scrutinising the map, wondering if two adjacent buildings are too similar to each other, or whether the road layout of the map feels right, or whether there's too much or too little detail in a certain area. And every time I need a new unique building for a mission I'd have to go back and rip an existing generic building out - potentially changing the layout of large areas of the map in order to make it fit correctly. So although writing an editor would be quick and easy, creating the maps would likely be not.</p><p>However a map generator, although it would take a certain amount of time and effort to get working right, could potentially spawn millions of detailed maps just at the click of a button, with minimal effort on my part to feed the generator with input parameters. This would be particularly useful since at the time I started I also had no idea exactly how many maps I wanted the game to have.</p><p>As an added bonus, writing a random map generator would also be a hell of a lot more interesting than a boring old level editor.<h3>The goal</h3><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:250px;float:right;"><a href="/news/images/dream/3_fig2.jpg" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/3_fig2sm.jpg"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 2</strong><br>Liberty City from GTA 1, rendered in full 3D with the Junction 25 editor. (Click for larger)</p></div>The goal of the map generator is to create city maps for DeathDawn. But how big do they need to be, and what format should they be in?</p><p>In the interests of keeping things simple and not reinventing the wheel, the DeathDawn map structure is based around that of GTA 1. GTA 1 was capable of providing large cities (about 1km square) to the player, using under 500K of storage for the map itself. Each city consisted of a set of cubes arranged in a 256x256x6 grid. In real-world terms the length of the side of each cube is around 4m (or at least that's the length I've based DeathDawn around). The cubes were fairly limited in what they could do - you could specify the textures of the 5 visible sides, and the slope of the top surface - but that's about it as far as architectural details go. In addition to the visible features of the map there were also certain invisible features - such as the content type of the block (solid, air, or water), and how the AI should behave (whether it's pavement and should have pedestrians walking on it, or whether it's road and should have cars drive along it - and in which direction). Uncompressed this data could easily be 6 or more megabytes in size, but by relying on the fact that most blocks are identical, and many vertical stacks of blocks are identical, the size can easily be reduced to under 500K, leaving much more space for textures and sound effects.</p><p>Although DeathDawn's map format is slightly more advanced than that of GTA 1, the goals are pretty much the same - for the map generator to produce a map typically 256x256 block-stacks in size, with as much building detail as possible, and with the right AI flags to allow for pedestrians and cars to spawn and find their way around the map. The generator should also be capable of producing any secondary data needed - such as the locations of traffic lights, train tracks, and the territories of the different facitons. It should also be able to add specific buildings to the map at the demand of the mission script, so that missions can use unique buildings if they want.<h3>Evolutionary development</h3><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:240px;float:right;"><a href="/news/images/dream/3_fig3.jpg" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/3_fig3sm.jpg"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 3</strong><br>Sample output of the MK 1 generator (Click for larger)</p></div>The map generator has gone through roughly three distinct stages of development. The first stage (the MK 1 generator) was capable of placing roads and buildings, as well as splitting the map into different zones (The zone information is used to dictate which faction owns the territory, as well as provide place names for the player as he drives around). But the buildings were just simple textured boxes, and the roads were buggy - apart from visual problems (bad road markings at intersections) there were also situations where the navigation flags the AI uses had been placed wrong, resulting in cars driving off the road and onto the pavement or into walls. The generator was also severely limited, with no support for extra city features like hills, bridges, train tracks, or traffic lights. There was also no system in place to allow for mission-specific buildings to be added.</p><p>The MK 2 generator was designed as a partial restructuring, partial rewrite of the MK 1 generator, in order to solve all of the major bugs as well as provide scope for the addition of new features - such as hills, bridges, train tracks, and the mission buildings. Although the MK 2 generator managed to fulfil most of these goals, several design flaws became apparent during its implementation, the most important of which was that there was no way of guaranteeing that the mission buildings that were requested actually made it into the map.</p><p>And so the MK 3 generator was devised - a reordering of the stages the MK 2 generator goes through, in order to ensure as best as possible that the mission buildings will actually be placed. Plans are also being made to improve the MK 3 generator further, in particular to improve the level of detail and placement of regular buildings.</p><p>Note that the DeathDawn source code currently available on my site contains the source for the MK 2 version of the generator; however by the time this set of map generator articles is complete I'm planning on having the latest version available for your viewing (dis)pleasure.<h3>Overview</h3><p><div style="border:2px solid #aaf;margin:2px;padding:0;width:228px;float:right;"><a href="/news/images/dream/3_fig4.png" target="_blank"><img style="display:block;" border=0 src="/news/images/dream/3_fig4sm.jpg"></a><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 4</strong><br>Sample output of the current MK 3 generator (Click for larger)</p></div>The generator, as it currently stands, performs the following operations, in the order detailed below. Each article will be covering one or more of the stages.<ol><li><b>Zoning #1</b>. This stage splits the empty map into zones, and assigns each zone a style, dependent upon which factions have been chosen to inhabit the map. The size of each zone is determined based upon how many mission buildings must be spawned there (and how large they are), in an attempt to ensure that enough space is available when it comes to placing them.</li><li><b>City block placement</b>. This fills the map with a series of rectangles, in a grid-like pattern. Each rectangle will later contain a building, and the edges of the rectangles will become roads. The zone location data that was generated in the first stage is used to apply different road and building styles to each city block.</li><li><b>Edge and node linking</b>. This doesn't add any new features to the map; it's just a housekeeping stage to correctly link together all the structures created by the city block stage.</li><li><b>Road weighting</b>. This stage decides how wide each road should be, by simulating a large number of trips through the city using an algorithm similar to the one a real-world computer route planner would use. After the trips have been simulated, the most-used roads will be chosen to be the widest roads (i.e. motorways), and the least-used will be downgraded to footpaths.</li><li><b>Zoning #2</b>. This stage examines the map to find the true size and shape of each zone (the earlier zoning stage just gives estimated bounds). It also assigns names to each zone, which will be seen by the player as he drives around the city.</li><li><b>Mission building placement</b>. Using the city block and zone information generated in the previous stages, this stage searches for suitable locations to place the mission script buildings that have been demanded by the mission script.</li><li><b>Layer splitting</b>. Added in the MK 2 generator, layers allow the generator to support hills, by storing the data for different altitudes in different structures. The current layer splitting code merely splits the map from one layer into two, by randomly placing hills throughout the map and moving all the buildings that lie inside a hill up onto the second layer. Eventually the layering code may be expanded to allow for more complex structures (notably bridges), or it may be discarded altogether in favour of a more streamlined approach.</li><li><b>Road prepainting</b>. The final map structure, as used by the game, is wholly incompatible with the data structures used by the generator. The map painting (and pre-painting) stages are therefore concerned with translating the map generator data into the final map data structure. In the case of road pre-painting, this involves marking into a temporary 2D array the location of each road.</li><li><b>Road and building painting</b>. This is a fairly complex stage. Not only does it paint each building into the main 3D map structure, but it also paints the surrounding road and ground blocks. In particular it contains code for placing the correct road textures on the surface of each block, as well as the navigation flags used by the AI.</li><li><b>Hill side painting</b>. A more correct name for this stage may be 'cliff face painting'; it involves a brute-force examination of the map to look for gaps in the joins between the upper and lower layers of the map, and places wall textures at the appropriate places to ensure that the player can't see through to the void underneath the map.</li><li><b>Traffic light placement</b>. Now that all the roads and buildings have been painted, each road intersection is examined to see if it is suitable for hosting a set of traffic lights. Although this stage could probably be performed before the road and building painting, it's easier to do it after, as it provides a much more robust method of verifying that the traffic lights won't be placed incorrectly.</li><li><b>Train track placement</b>. The map generator is capable of generating elevated train tracks for inner-city and inter-city rail travel. Similar to the hill side and traffic light placement code, a brute-force approach is used to examine the finished map, to ensure that the train track weaves around buildings instead of ploughing straight through them.</li></ol><h3>In detail</h3><p>For this first article about the map generator, I'm going to be talking solely about the data structures that are used. Understanding the data structures is vital to understanding the flow of the generator as a whole. Later articles will go into more detail about each stage of the map generation.</p><p>If you're put off by all these wordy descriptions, don't worry, because there's a few diagrams at the end showing how everything fits together.<h4>The layer structure</h4><p>First off there is the layer structure. This was introduced in the MK 2 generator as a way of tieing together various variables and structures that the generator uses.<div style="float: right;width:300px;border:2px solid #aaf;margin:2px;padding:0;"><small><b>Aside: Why use a linked list and an array at the same time?</b></p><p>Throughout the code there are two basic ways in which the collection of <tt>cblock</tt>s are accessed:<ol><li>Group access - an identical operation needs to be performed on all <tt>cblock</tt>s.</li><li>Spatial queries - given a certain point in the map, the <tt>cblock</tt> that contains that point needs to be discovered.</li></ol>As with most computational problems there are two solutions - one that's optimised for speed and one that's optimised for memory usage. At the moment I'm currently more interested in speed (and ease of implementation) than memory usage, so I went with the simple approach of a linked list for group access to <tt>cblock</tt>s and a big array of pointers for spatial access. In the future I may switch to a different approach, such as an <a href="http://en.wikipedia.org/wiki/R-tree" target="_blank">R-tree</a>, which is able to provide fast group and spatial access to most types of N-dimensional data, without incurring large memory costs.</small></div><br /><code>typedef struct _layer {<br />  rect r;<br />  int z;<br />  gdll *cblocks;<br />  cblock **cbmap;<br />  fbll *corners;<br />  int *surfmap;<br />} layer;</code><ul><li>The <tt>r</tt> member of the structure, a '<tt>rect</tt>', contains the minimum and maximum X and Y bounds of the layer, measured in blocks. Currently this is just set to the bounds of the map, but in the future it may be used to limit development to certain areas (e.g. if there is water at the edge of the map the layer would be restricted to just the island of land in the middle).</li><li>The <tt>z</tt> member gives the layer its height above ground, measured in blocks.</li><li>The <tt>cblocks</tt> member is a pointer to a <tt>gdll</tt> - a linked list structure that I often use in my code to make handling linked lists slightly easier. The linked list will contain a list of all the city blocks that are contained in the layer.</li><li>The <tt>cbmap</tt> member points to a 2D array of pointers to <tt>cblock</tt>s, allowing rapid lookup of which city block falls on which map block. The <tt>cblock</tt>s pointed to by the <tt>cbmap</tt> are the same <tt>cblock</tt>s that are contained in the <tt>gdll</tt> list.</li><li>The <tt>corners</tt> member is another of my linked list structures, but a different type - a frame-based linked list, which is basically just a linked list of arrays. A frame-based linked list allows you to quickly and easily look up the Nth element of the list, at the cost of much slower insertion/removal of items in the middle of the list. In the case of the map generator, this speed trade off was deemed worthwhile to ensure the speedy operation of the road weighting algorithm. As the name suggests, the data contained in the <tt>corners</tt> linked list is a list of all the corners of the city blocks; or more correctly, a list of all the end points of the edges which join city blocks. More about this later.</li><li>The <tt>surfmap</tt> member is similar to the <tt>cbmap</tt>, in that it points to a 2D array. But instead of indicating which city block each location belongs to, it instead indicates which surface type (road, pavement, grass, water, etc.) each location is. This is mainly used by the road painting code to ensure that roads aren't painted where they shouldn't be. Although the final map structure contains similar data, it works out easier for the map generator to store it in a temporary array as well.</li></ul><h4>The cblock structure</h4><p>Each <tt>cblock</tt> represents a city block; i.e. a plot of land with one or more buildings inside it, and surrounded by pavements and roads. Currently only one building is placed in each cblock, but this will likely change with the MK 3+ generator - take a look at figure 4 and you'll see how much empty space there currently is inside each city block.</p><p><code>typedef struct _cblock {<br />  rect r;<br />  rect br;<br />  gdll *neighbours;<br />  gdll_item *i;<br />  zonedef *z;<br />  struct _layer *l;<br />  builddef *b;<br />  int msi;<br />} cblock;</code><ul><li>The <tt>r</tt> member provides the bounding box of the block. This box stretches from the middle lane of the road one one side to the middle lane of the road on the other side. This represents the maximal area that the painting stages will paint grass or pavement into, to fill in the gaps between the building and the road.</li><li>The <tt>br</tt> is another bounding box, but this time provides the bounding box of the building that sits inside the block. This is computed by looking at the widths of the roads that surround the block.</li><li><tt>neighbours</tt> is a linked list of <tt>edge</tt>s that surround the block. <tt>edge</tt> structures are created whenever two <tt>cblock</tt>s touch, and are used to generate the roads and paths that run through the city.</li><li><tt>z</tt> points to a <tt>zonedef</tt> - a structure that dictates which building, pavement and road styles to use when painting the <tt>cblock</tt>. The <tt>z</tt> field is also used by the 'Zoning #2' stage to calculate the true bounds of each of the named map zones and faction territories.</li><li><tt>l</tt> points to the <tt>layer</tt> that the city block belongs to. During map generation certain information (most notably the Z coordinate) of the city block is needed, so a reference back to the parent layer is the easiest way of providing that information.</li><li><tt>b</tt> points to a <tt>builddef</tt>, i.e. a building definition. It indicates the type of building that's been selected to spawn at the location. Currently this field is only used for the mission buildings; for all other city blocks a random building is selected at painting time, using the list given in the <tt>zonedef</tt>.</li><li>If a mission building is being used, the <tt>msi</tt> field will be set to the index in the master mission building list. If no mission building is being placed in this block then the index will be -1. The <tt>msi</tt> field is crucial to allow the building location to be fed back to the mission script.</li></ul><h4>Edges</h4><p>The <tt>edge</tt> structure is used to link neighbouring <tt>cblock</tt>s together, and dictates the locations of the roads and paths that run through the city.</p><p><code>typedef struct _edge {<br />  gdll_item *a,*b;<br />  corner *c,*d;<br />  int type;<br />  int weight;<br />  short clip,dlip;<br />} edge;</code><ul><li><tt>a</tt> and <tt>b</tt> are two <tt>gdll_item</tt> pointers; <tt>gdll_items</tt> are used to reference individual entries in <tt>gdll</tt> lists. There are two of them because the edge is shared between two <tt>cblock</tt>s, each of which has a different list of neighbouring <tt>edge</tt>s.</li><li><tt>c</tt> and <tt>d</tt> are two <tt>corner</tt> pointers, dictating the two end points of the edge.</li><li><tt>type</tt> is the type of edge - road, pavement, cliff, etc.</li><li><tt>weight</tt> has a dual meaning. During the road weighting stage it's a counter of how many times the edge has been used, and after the stage it's the number of lanes in the road (assuming it is a road).</li><li><tt>clip</tt> and <tt>dlip</tt> are the distances from <tt>c</tt> and <tt>d</tt> at which the straight part of the road exists; i.e. it's how large any crossroads or T-junctions are. This information is mostly redundant with information stored in the <tt>corner</tt>s themselves, but for the moment it stays where it is. <tt>short</tt>s are used to try and keep memory usage down, although in reality there are still many other memory optimisations I could apply if I wanted.</li></ul>Note that an <tt>edge</tt> can cross from one layer into another, e.g. to create the slope of a hillside or bridge. This is why there's no <tt>layer</tt> pointer in the edge, and each <tt>layer</tt> doesn't have a list of edges.<h4>Corners</h4><p>As their names suggest, corners are the places where edges meet.</p><p><code>typedef struct {<br />  struct _edge *edges[4];<br />  short x,y;<br />  int visited;<br />  short w,h;<br />  struct _layer *l;<br />  int type;<br />} corner;</code><ul><li><tt>edges</tt> is a small array listing the <tt>edge</tt>s that the corner is connected to. Since edges only run horizontally or vertically, there's no chance of there being more than 4 edges connected to a specific corner.</li><li><tt>x</tt> and <tt>y</tt> are the coordinates of the corner within the layer.</li><li><tt>visited</tt> is a flag used by the road weighting algorithm.</li><li><tt>w</tt> and <tt>h</tt> are the dimensions of the corner, in terms of the total number of lanes (map blocks).</li><li><tt>l</tt> is a reference to the layer that this <tt>corner</tt> belongs to.</li><li><tt>surftype</tt> is the surface type of the corner (road, pavement, etc.) This could be calculated just by looking at the surface types of the connected edges, but storing it locally helps keep things simple.</li></ul><h3>What?</h3><p>If all those data structures are confusing you, then perhaps these diagrams will help. Figure 5 shows how the different data structures fit together to represent different parts of the city. Figure 6 shows the actual relationships between the different structures, from the datas point of view (i.e. what pointers point to what).<div style="border:2px solid #aaf;margin:1em auto;padding:0;width:531px;"><img style="display:block;" border=0 src="/news/images/dream/3_fig5.png"><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 5</strong><br>How the data structures represent the city</p></div><div style="border:2px solid #aaf;margin:1em auto;padding:0;width:433px;"><img style="display:block;" border=0 src="/news/images/dream/3_fig6.png"><p style="background-color:#ccf;margin:0;border-top:2px solid #aaf; padding:0.5em 0.3em;"><strong>Figure 6</strong><br>How the data structures are related in code</p></div><h3>Next time...</h3><p>The next article, due shortly after judgement day, will take a look at what constituted the MK 1 map generator - i.e. the city block placement, edge and node linking, and road weighting stages of the generator. If there's space I may also describe the algorithm used to paint the road navigation flags for the intersections.</p><p><a href="http://iconbar.com/comments/rss/news1211.html">1 comment in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Sat, 23 Aug 2008 11:00:00 GMT</pubDate>
  </item>
  <item>
   <title>Right On Commander!</title>
   <link>http://iconbar.com/comments/rss/news1210.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1210.html</guid>
   <description>Gareth Moore wrote in to let us know that, as foretold in the forums, the "Brits Who Made the Modern World" series is a big rip-off of the book "The Backroom Boys". No, wait, that wasn't it.</description>
   <content:encoded>
    <![CDATA[
    Gareth Moore wrote in to let us know that, as foretold in the forums, the "Brits Who Made the Modern World" series is a big rip-off of the book "<a href="/articles/Book_Backroom_Boys/index516.html">The Backroom Boys</a>". No, wait, that wasn't it.</p><p>The <a href="http://library.digiguide.com/lib/uk-tv-highlight/Brits+Who+Made+The+Modern+World-4496/Documentary/">final episode airs on August 22nd at 7:30pm on Five</a>. Go on, guess what it's about.</p><p> <div align="center"><img src="/news/uploaded/elite.png" alt="Elite" width="315" height="284" /></center></p><p><a href="http://iconbar.com/comments/rss/news1210.html">12 comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Thu, 14 Aug 2008 21:30:00 GMT</pubDate>
  </item>
  <item>
   <title>Building the Dream 2 - The RISC OS Sound System</title>
   <link>http://iconbar.com/comments/rss/news1209.html</link>
   <guid isPermaLink="true">http://iconbar.com/comments/rss/news1209.html</guid>
   <description>A bit later than I was hoping, but nevertheless it's now time for Building the Dream 2. This time I'll be looking at the RISC OS sound system - everything from the terminology used, to what makes a sound, how the RISC OS sound system works, and how you can write your own sample player.</description>
   <content:encoded>
    <![CDATA[
    <img src="/news/images/dream/logo.png" align="right" hspace="2" vspace="2"/>A bit later than I was hoping, but nevertheless it's now time for Building the Dream 2. This time I'll be looking at the RISC OS sound system - everything from the terminology used, to what makes a sound, how the RISC OS sound system works, and how you can write your own sample player.</p><p> <h3>Terminology (and how sound works)</h3><p>First, let's start with the basics. A <b>sample</b> can, confusingly, have two meanings. It can either be used to describe a sound clip (e.g. a .WAV file), or one of the individual units of sound that make up a part of the clip. For the latter, a sound sample is typically stored as a 16 bit signed integer. After some processing by the sound software/hardware to provide volume scaling or mixing with other sounds, the sample is sent to an analogue-to-digital converter that translates it into a voltage. This controls the position of the diaphragm in the speaker. In order to generate an audible sound, the position of the diaphragm must be changed many hundreds or thousands of times a second, resulting in it oscillating back and forth. These oscillations set up the required pressure waves in the air, which travel outwards from the speaker and eventually stimulate the receptors inside your ear.</p><p>Most sound hardware operates by processing a certain number of samples per second - this is known as the <b>frequency</b> of the sound system, and is measured in Hertz (Hz). Most hardware supports several different frequency settings, e.g. 11kHz, 22kHz and 44kHz. Although at first glance it may appear that the computer is only able to generate sounds at 11kHz, 22kHz, or 44kHz frequencies, in reality many different frequencies of sound can be generated by sending the correct sequence of samples. For example, if the sound system is set to 22kHz, and the sequence of samples 32767, -32768, 32767, -32768, 32767, ... etc. is sent to the hardware, then a constant 11kHz tone will be emitted by the speaker. The tone will be at 11kHz instead of the expected 22kHz because the <b>period</b> (duration) of the wave is 2 samples. I.e. every 2 samples the in-out motion of the speaker diaphragm will repeat (and it is in the in-out motion that results in a sound being produced). If the sequnce of samples had instead been 32767, 0, -32768, 0, 32767, 0 -32768, 0, 32767, ... then the tone would be at 5.5kHz, because the period of the wave is 4 samples. Many other patterns are possible, each providing approximations to different frequencies of sound. The higher the sample rate of the hardware, and the higher the resolution of the samples (e.g. 24 bit instead of 16 bit), the closer these patterns come to representing the real shape of a specific frequency sound wave. One thing to remember though is that the maximum frequency sound you can output will be half the frequency of the sound system, because a period of at least two samples is required in order to represent the essential in-out motion.</p><p>Although I've mentioned the <b>period</b> as being the duration of one cycle of a sound wave, it is also used to describe the duration of one sample. For example, at 22kHz, the period of each sample is 1/22050s = 0.000045351 seconds (Note that 22kHz rarely equals 22000Hz. A 22kHz sound system would typically run at 22050Hz, and it is only written as 22kHz as a matter of convenience. Similarly 11kHz is 11025Hz and 44kHz is 44100Hz). This means that, every 0.00045351 seconds, the sound hardware reads a sample from the sound buffer, converts it to a voltage, and sends it to the speaker.</p><p>The <b>buffer</b> is another important aspect of the sound system. Rather than constantly pester the CPU with requests for individual samples, the sound hardware typically requests several hundred samples at a time, which the CPU will put into a memory buffer ready for reading by the sound hardware. This provides more efficient operation, as it reduces the number of context switches that the CPU must perform (A context switch - e.g. switching from running an application to running the sound buffer fill routine - will take a finite amount of time. So the more context switches there are, the more CPU time will be lost to performing the switching) Bigger buffers will require less context switches, and so will incurr a lower CPU overhead. However care has to be taken, as the buffer introduces a delay in the sound system - if the buffer is too large the user will notice that a sound is only heard a considerable amount of time after it was meant to start playing. This is more of importance to games than regular desktop use, as games rely upon many sounds starting and stopping at specific times. It is also important for movie playback, to ensure the sound is in sync with the pictures - although if the buffer size remains constant, the delay can be taken into account by the movie player code.<h3>The RISC OS sound system</h3><p><div align="center"><img src="/news/images/dream/2_fig1.png"/></div><p>There are actually two RISC OS sound systems - the older, practically obsolete 8bit sound system, and the newer 16bit sound system. Although I'll be discussing both in this section, the code samples in the next section will focus on the use of the 16bit sound system, as it is the easiest to write for, produces higher-quality sound output, and has better support for mutliple users (via the SharedSound module).</p><p>In the beginning though, there was just the 8bit sound system. This is the system that was shipped with the first ARM-powered machines running Arthur. It could be configured to support between 1 and 8 channels of 8bit audio, which would then be mixed together in hardware to produce the two stereo channels output to the speakers. To do this, each channel could be assigned a stereo 'position', which controlled how much of it was mixed into the left and right output channels. Although the sample rate and buffer size of the sound system could be changed, these settings could not be changed on a channel-by-channel basis - they had to be a global change.</p><p>The 8bit sound system was based largely around the notion of <b>voice generators</b> - pieces of code (normally contained in a module) which either played back samples from a stored audio clip or generated the data on-the-fly. Each channel would be assigned a specific voice generator, meaning that each channel can only play one sound at once. Sound playback is controlled via the channel interface - so rather than request for a specific sound to be played, you instead issue a standard call to the channel controller to play whatever sound (voice) is currently attached to the given channel. The pitch, volume, and duration of the sound can be specified with the command, although it is up to the voice generator whether it pays attention to those values or not. Although each channel can only have one generator attached at once, there is nothing to stop the same generator from being attached to multiple channels.</p><p>Although adequate when first introduced, it's obvious that the old sound system contained several flaws. Only 8 channels existed, and so only 8 sounds could be played at once (unless software mixing was used). It was also a single-user system, as no framework existed for allocating specific channels to specific programs. Furthermore, the reliance upon voice generators made it difficult to implement continuous sound sources (such as music players). Although it is possible to implement a music player as a voice generator, the solution several music players took was to bypass the channel allocation system entirely and instead claim the entire sound system for itself, preventing any other sounds from being played at all (even if the music player only uses a few of the available hardware channels).</p><p>The other point to note about the 8bit sound system is that it used logarithmic samples, not linear; although this makes the data more difficult to process, it results in a marked increase in sound quality, as it essentially gives the computer a 12bit sound system.<h3>16bit sound and SharedSound</h3><p>With the introduction of the RiscPC came a standardised 16bit sound specification, and the hardware to go with it. The main aspect of the specification was the new SWI, Sound_LinearHandler, which allows programs to register their own 16bit sound handler function. This function has the role of filling both the left and right channels of the 16bit sound buffer with data; thus it is limited to stereo sound hardware only. The main drawback of the 16bit sound system is that only one handler can be registered at once - however this was soon resolved with the release of the SharedSound module, which is now the standard interface to the 16bit sound system under RISC OS.</p><p>The SharedSound module operates by registering its own handler (via Sound_LinearHandler); it then allows clients to register as many sound handlers as they want, via the SharedSound_InstallHandler SWI. Each time a buffer fill request is received from the Sound module, SharedSound will iterate through the list of client handlers and call each handler, allowing them to write whatever data they want to the sound buffer. Because the same buffer is shared between all clients, each client must correctly obey the mixing flags that SharedSound passes to it, to ensure data from other clients doesn't get overwritten. However the use of linear 16bit sound samples makes the mixing process trivial to perform.</p><p>Apart from providing shared access to the 16bit sound buffer, SharedSound also provides useful information about the sample rate of the buffer, in particular fractional step values to convert from the client's sample rate to the buffer rate. It also allows the volume of each handler to be changed individually (although it is up to the fill code to perform the required volume scaling). It also allows several different types of handler to be used - standard handlers that can be run from an interrupt handler, callback handlers that perform processing in a callback (which means they can take longer, as interrupts will be enabled), and process handlers (which are called in a callback after all other handlers, to allow for any effects to be applied to the final sound buffer data). In my experience, even with relatively simple buffer fill code like the one in the example below, if you're playing more than a handful of sounds at once you will get better performance by switching from an interrupt-based fill routine to a callback-based fill routine.</p><p>The only downside to the SharedSound module is that the latest version is only available if you own RISC OS 6. If you don't have RISC OS 6 (Or any earlier version of the module shipped with RISC OS Select/Adjust), then it looks like the most recent version available on the Internet is version 1.04, available from <a href="http://www.castle.org.uk/support/files/SSound104.zip">here</a> on Castle's website. For documentation, the best source would appear to be the 'OS' StrongHelp manual, available <a href="http://sudden.recoil.org/stronghelp/">here</a> on the StrongHelp site.<h3>A sample simple SharedSound sample player</h3><p>I'll now go into detail about how to write your own sample player, using SharedSound. The player will load one or more WAV files from disc and play them back all at the same time - demonstrating how to read (simple) WAV files, how to interface with SharedSound, and how to perform relatively simple activities such as playing multiple sounds at the same time, at their correct sample rates. The code could be easily expanded to support other features, e.g. looping, staggered playback, individual pitch/volume controls for each sound, etc. - basically everything you need for a simple music player or computer game.</p><p><a href="/downloads/dream2_code.zip">Download the code</a></p><p>To run the sample you will need RISC OS 3.5 or above, a copy of the SharedSound module, and some WAV files. The included makefile is suitable for compiling the code with GCC.</p><p>The code is split into four sections, which will be explained below. It is a mixture of C and assembler; C for file reading and general control, assembler for buffer filling and some error handling. The code could have been written as a mix of BASIC and assembler (or in pure assembler), but processing the WAV files in C is much easier than in BASIC or assembler. If you really wanted you could use C for the buffer filling code instead of assembler - but that would require extra wrapper code to get the CPU/stack in the correct state for the running APCS code, as well as extra care when writing the code to ensure certain instructions (e.g. floating point) aren't used. For a simple player like this, it's a lot easier and safer just to write the buffer fill code in assembler.<h4>1. WAV reading</h4><p>Each WAV file is read into a <b>sound</b> struct by the <b>load_wav()</b> function. This function will take the filename and <b>sound</b> pointer as input, and attempt to convert the WAV file into a sequence of stereo 16bit samples (stored in the correct format for placing in one of SharedSound's buffers). Although the code is by no means perfect, it should be able to understand almost any uncompressed 1 or 2 channel WAV file you throw at it. If you're interested in writing your own WAV reader, then you're out of luck, because I've lost the link to the original page I used when writing the code. All I can do is point you to <a href="http://en.wikipedia.org/wiki/WAV">Wikipedia</a> and let you struggle by yourself if one of the sites they link to gets it wrong!<h4>2. SharedSound initialisation</h4><p>This is performed by the <b>init_sharedsound()</b> function. After the buffer fill code has been registered with SharedSound, <b>init_sharedsound()</b> performs two other important tasks - it registers a couple of error handlers (more on that later) and reads the current sample rate. It uses the sample rate returned by SharedSound to calculate the playback rate of each WAV file. This is necessary because the WAV loader doesn't do any sample rate conversion. Instead, each <b>sound</b> is given its own playback rate.<h4>3. Playback</h4><p>On the C side, not much occurs during playback. The code merely waits in a while() loop until it detects that all samples have reached their end. This means that playback is entirely under the control of SharedSound - and our <b>buffer_fill()</b> code.</p><p>Each time the <b>buffer_fill()</b> code gets called, it processes the <b>sound</b> list, adding each sound to the buffer one at a time. I've deliberately left the buffer fill code quite simple, so that you can see how it works. For one, it ignores most of the information SharedSound supplies it with, such as sample rates and volume levels - because it should already know the sample rate to use, and no volume scaling is performed. Secondly, no math overflow checks are performed on the samples as they are added into the sound buffer - this will result in clicks and other noise if you play too many loud sounds at once. Extending the code to support volume scaling and/or overflow protection is fairly trivial.</p><p>Note that because of the way sound works, in order to play two sounds at the same time we merely have to add the two samples to each other. This will only work with linear sound samples however - if this code were for the 8-bit sound system then it would be much more complicated (which is one of the many advantages of using the 16bit sound system instead).</p><p>It's also worth pointing out the use of R7, R12, and R8 in tracking the playback position. R7 and R12 contain the playback position of the <b>sound</b>; R7 is the whole part (i.e. number of samples played) and R12 the fractional part. R8 is the sample rate. This is calculated (in <b>init_sharedsound()</b>) as the ratio of the WAV sample rate to the SharedSound playback rate. So if you were playing an 11kHz WAV file into a 22kHz SharedSound buffer, the ratio would be 1:2, or 0.5. This ratio is stored in R8 as an 8.24 format fixed-point number (8 bit whole number, 24 bit fraction). So the 0.5 of the example would become 8388608 (Or 0x100000 in hex). R12 is also stored in 8.24 format; this means that, each time the playback position is updated, the upper 8 bits of R12 are added to the lower 8 bits of R7, and then cleared from R12. R12's sole purpose is to track the fractional part of the sample position.</p><p>Note that R7 is saved in the <b>sound</b> state, but R12 is not. This does mean that if any value is left in R12 after each buffer fill, it will have the effect of stretching the sample slightly. For example if there are 100 buffer fills per second, then at most the sample will be stretched by 100 samples per second, making it 1% longer and 1% lower in pitch. If I were writing a music player then I might store the value of R12 between buffer fills; but for a simple sample player there is little point, as the effect is minor and not guaranteed to occur anyway.<h4>4. Shutdown</h4><p>Shutdown is handled by the aptly-named <b>shutdown_sharedsound()</b> function. This function unregisters the SharedSound handler (if it is still installed, as an error may have forced it to be removed), and disables the ErrorV handler that was installed by <b>init_sharedsound()</b>. The ErrorV handler is used for error handling, which is discussed below.<h3>Error handling</h3><p>Error handling is a very important part of audio playback under RISC OS, especially if your buffer fill code runs from application space or relies on data stored in application space. If your program exits in an unexpected way then there's a chance that the buffer fill code will be left active - at which point anything could happen from random data beginning to play or the machine locking up entirely. After struggling with error handling for some time, I've come across a solution that appears to work under all circumstances.</p><p>Firstly, a C <b>atexit()</b> handler is used to catch all cases of the C program terminating under the control of the C library. This handler will get called if the program exits via <b>exit()</b>, <b>abort()</b>, or by returning from <b>main()</b>. In our case, <b>shutdown_sharedsound()</b> is registed as an atexit funciton.</p><p>Secondly, an assembler function is attached to ErrorV, the vector that will be executed whenever the OS is made aware of an error. This is necessary to trap the cases which <b>atexit()</b> does not - for example more serious errors such as data aborts or undefined instructions. The assembler function that gets registered (<b>error_handler()</b>) disables the SharedSound handler, but, importantly, does not disable the ErrorV handler. This is because after testing it on my Iyonix I found that the machine would lock up completely on error, most likely because it does not support an error handler removing itself. Manually removing the error handler isn't deathly important anyway, as the OS is capable of removing it itself when the application exits.<h3>Multitasking</h3><p>A couple of extra considerations are needed for multitasking programs. Firstly - don't expect to be able to play sounds in the WIMP using a player in application space. This is because of how RISC OS mainpulates the memory map to allow each program to run from the same &8000 base address. Secondly - don't expect to be able to do it from a TaskWindow either (hence the check near the start of <b>main()</b> in the example), again for the same reason as above. If you want to play sounds from within the WIMP then you'll have to rely on buffer fill code stored in the module area (ideally inside a module rather than as a random piece of floating code), and store your sample data in a dynamic area or in the module area.<h3>Interrupts</h3><p>One important thing to remember if you're doing more complex work with sounds is that all buffer fills occur in interrupts. This means that your program doesn't know when they will occur; if you have some C code that adds and removes sound effects from a list of effects to play, then there's a chance the buffer fill code will get called in the middle of your code updating the list. You should design your code with this in mind. For example, if you are swapping a long sample with a short sample, and you update the data pointer before updating the playback position or sample length, then there's a chance random data will be played instead of sound data. The best course of action in this case is likely to be to temporarily set a 'paused' flag for that sound, or set the data pointer to 0 (and have the buffer fill code interpret that case as there being no data to play). If your sample playback list is constantly changing then you might want to keep two lists - one which is in a safe state and is read by the buffer fill code, the other which is in a volatile state as it is constructed or updated. After a list has been constructed the 'active list' pointer will be swapped to point at the other list. If you take this approach, remember that you will have to store the playback position for each sound somewhere sensible (i.e. not in either of the two lists)</p><p>For example, the game I'm currently working on, <a href="http://www.phlamethrower.co.uk/riscos/deathdawn.php">DeathDawn</a>, uses three structures to manage sounds: Each sample is stored in a <b>sample</b> structure. This contains the raw sample data, length, and sample rate of that data. Each object in the game has a fixed number of <b>sound</b> slots; each slot can reference a <b>sample</b>, and contains the playback position, volume and pitch modifiers, as well as pause and repeat flags. Although there may be 30 objects in the game world with 4 sound slots each, there may only be 4 slots which are both in use and in earshot of the player. For this reason, two lists of <b>active</b> sounds are kept. These lists only contain pointers to the <b>sound</b>s that should be played. As well as the <b>sound</b> pointer itself, each entry also contains the final volumes of the left and right stereo channels, and the fully-adjusted 8.24 fractional step to use for playback. At the end of each frame, the <b>active</b> list that is used by the buffer fill code is swapped with the list that has just been assembled by the C code. Although this solution solves many problems with handling sounds it is still not perfect, for special code must be used to delete <b>sound</b> structures (to ensure they are not referenced in either the of the <b>active</b> lists), and if a <b>sample</b> is swapped for one of a different sample rate then there's a chance it will be played at the wrong rate for the duration of one buffer fill (although this can be fixed by moving the sample rate calculation into the buffer fill code). The reliance on <b>active</b> sound lists also introduces a delay of a few centiseconds between a sound being scheduled for playing and playback to begin.<h3>Next time...</h3><p>The next article, due sometime before judgement day, will deal once again with the topic of <a href="/articles/Random_map_generators/index1114.html">random map generators</a>, as well as provide numerous examples of uses for the different container data structures <a href="/articles/Building_the_Dream_1_-_Container_data_structures/index1162.html">that were discussed last time</a>.</p><p><a href="http://iconbar.com/comments/rss/news1209.html">3 comments in forum</a>

    ]]>
   </content:encoded>
   <pubDate>Mon, 17 Mar 2008 12:00:00 GMT</pubDate>
  </item>

  </channel>
</rss>