<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9115843</id><updated>2011-04-21T20:31:04.754-04:00</updated><title type='text'>Oscar Papel's Web Log</title><subtitle type='html'>This is a place where I'll discuss computer-related topics that my wife is sick of hearing about.  I really don't expect anyone to read this but it should help me by acting as a sounding board for ideas.  In other words, &lt;b&gt;the "B" in Blog is for Boring&lt;/b&gt;.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9115843.post-111274908575030737</id><published>2005-04-05T16:49:00.000-04:00</published><updated>2005-04-06T01:27:28.236-04:00</updated><title type='text'>Windows.Forms and Mac OS/X</title><content type='html'>I decided to create a step-by-step tutorial on how to get Windows.Forms based PC apps running on Mac OS/X.  As an outsider to the project, I'm going to restrict myself to public releases.  &lt;br /&gt;&lt;br /&gt;Prerequisites:&lt;br /&gt;&lt;br /&gt;Before we begin, we need to check the minimum system requirements:&lt;br /&gt;- Mac OS/X Panther 10.3.x (I used 10.3.8)&lt;br /&gt;- X11 for Mac OS/X ( this is an install option for Panther located on the third CD ). This requirement may go away in the future but for now just make sure you have it installed.&lt;br /&gt;&lt;br /&gt;Step 1: Get Mono&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos6.flickr.com/8569672_eed84ed6be_o.jpg" width="272" height="112" alt="mono" /&gt;&lt;br /&gt;&lt;br /&gt;Download Mono.Framework-1.1.6.dmg from the Mono website (http://www.mono-project.com/Downloads).  &lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos5.flickr.com/8569673_b60d616357_o.jpg" width="129" height="108" alt="drive" /&gt;&lt;br /&gt;&lt;br /&gt;Double click on the .dmg file to mount the disk image.  A drive icon like the one above should now be on your desktop.  Double click on the drive in order to see it's contents.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos7.flickr.com/8569674_926e4be5df_o.jpg" width="393" height="191" alt="dir" /&gt;&lt;br /&gt;&lt;br /&gt;Step 2: Install Mono&lt;br /&gt;&lt;br /&gt;Double click on the package file.  This will start an installation of Mono onto your hard drive.  &lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos6.flickr.com/8569675_931c13ffb1_o.jpg" width="310" height="220" alt="installer" /&gt;&lt;br /&gt;&lt;br /&gt;You need to follow the instructions and complete the installation.  Once you are done, you will be ready to begin writing your first Mac Windows.Forms "Hello World" program.&lt;br /&gt;&lt;br /&gt;Step 3: Creating Hello World&lt;br /&gt;&lt;br /&gt;In this step, we will be creating a simple Message Box based program to test our installation.  Start TextEdit and lets write a simple C# Windows.Forms program.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos7.flickr.com/8571367_c8df4e550d_o.jpg" width="319" height="152" alt="source" /&gt;&lt;br /&gt;&lt;br /&gt;This program won't win any design awards but it will create a Message Box with a text message (the ubiquitous "Hello World"), and an OK button.  Make sure that when you save this file that you don't add a .txt extension to the file!&lt;br /&gt;&lt;br /&gt;We now need to compile this simple program.  We need to start Terminal in order to do this.  Launch Terminal and change your directory to the directory that you saved your Hello.cs file to.  I saved it to a subdirectory of "Documents" so at the command prompt I typed:&lt;br /&gt;&lt;br /&gt;cd ~/Documents/Hello&lt;br /&gt;&lt;br /&gt;You'll need to do something similar.&lt;br /&gt;&lt;br /&gt;we can now launch the compiler.  At the prompt, type:&lt;br /&gt;&lt;br /&gt;mcs Hello.cs /r:System.Windows.Forms.dll /out:Hello.exe&lt;br /&gt;&lt;br /&gt;If you didn't make any typing errors, you should now have Hello.exe in addition to Hello.cs.  &lt;br /&gt;&lt;br /&gt;If this was a PC, we would be done now but since we are on the Mac, we need another step.  We need to MacPack the exe we created so that it can play nice with the Mac's GUI.  Type the following command at the same prompt you used to compile.&lt;br /&gt;&lt;br /&gt;macpack -n:Hello -a:Hello.exe -o:. -m:1&lt;br /&gt;&lt;br /&gt;This will create a Mac bundle that contains our sample and that can be launched by clicking on it in the finder.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos4.flickr.com/8576242_61e2919ede_o.jpg" width="284" height="96" alt="finder" /&gt;&lt;br /&gt;&lt;br /&gt;Step 4: Hello World&lt;br /&gt;&lt;br /&gt;Clicking on the Hello App in the finder should give you the following message box.  &lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos4.flickr.com/8575651_e649cc85ab_o.jpg" width="140" height="117" alt="message" /&gt;&lt;br /&gt;&lt;br /&gt;Clicking the OK button closes the app.&lt;br /&gt;&lt;br /&gt;Addendum: MacPack, an explanation.&lt;br /&gt;&lt;br /&gt;Mac Applications exist as App bundles.  A bundle is just a subdirectory containing an executable as well as all the resources that the executable may need (such as icons, images, sounds, plugins, help, language packs, etc).  In fact, the bundle we created above (called Hello) is really just a subdirectory called Hello.app.  These bundles need to conform to a particular structure so that they interact with the finder and dock properly.  This is where macpack comes in.  It creates the necessary directory tree, a configuration file, and a launch script for your exe.&lt;br /&gt;&lt;br /&gt;The finder reads the directory tree and realizes that it is really an App and treats the bundle like a single file.  If you want to explore the subdirectory, you need to right click (or Ctrl-click for single button mice) and select "Show Package Contents".  This will let you bypass the Mac "magic" and explore the contents of the subdirectory.  This magic doesn't exist when you are in terminal.  Terminal always shows the App as a directory.  The only thing that should be in the root directory of the App is a Contents subdirectory.  Inside this subdirectory are the Resources and MacOS subdirectories as well as the Info.plist file.  &lt;br /&gt;&lt;br /&gt;Info.plist&lt;br /&gt;The Info.plist file configures the bundle.  Double clicking on it should launch the property list editor.  There are two entries created by default when you use macpack.  CFBundleExecutable specifies which executable (located in the MacOS sub) should be run when the app is launched.  CFBundleIdentifier specifies what name should be displayed for this app in the finder.  There are a few others that you might like to use.  &lt;br /&gt;&lt;br /&gt;Custom Icons&lt;br /&gt;First, you may want to use a custom icon.  Create a new Hello.icns file using Icon Composer (part of the XCode Developer tools, another optional install included with Panther) or just borrow an icon from the Resources section of another App.  Copy this file to the Resources section of Hello.app and add a new entry to the Info.plist file where key=CFBundleIconFile and value=Hello.icns (or whatever it is called).  You now need to force the finder to update it's picture for this app.   Dragging the app to the desktop and then back again should do it.  Making a duplicate of the App also works. &lt;br /&gt;&lt;br /&gt;"APPL" status&lt;br /&gt;Your app is ALMOST a fully fledged Mac App.  One thing it can't do, however is get dragged to the dock.  That's because the dock doesn't know that it is an App.  There are many bundle types used by Panther and an App is only one of them.  Frameworks are also bundles.  So are installation packages.  Obviously it doesn't make sense to drag a framework (like Mono.Framework, for instance) to the dock so we need to tell the Dock that this bundle is really an App.  We do this by adding another entry to the Info.plist file where the key=CFBundlePackageType and the value="APPL" (for application).  Once you have done this, your app can now be dragged to the dock like any other Mac App.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Epilogue:&lt;br /&gt;&lt;br /&gt;The astute among you will realize that although I stated that X11 was a requirement, we didn't actually do anything with it.  It does not even need to be running for S.W.F apps to work.  This is because, as it has been explained to me, the only part of X11 that is being used is in the text rendering.  This means that it is theoretically possible to remove the X11 requirement in the future.  As you can see from the screenshot, the X11 rendering is far from exceptional.  Also, I have been told that S.W.F on Mac is still considered to be in the Alpha stage.  Therefore, not all S.W.F apps will run flawlessly.  My advice is to not rely on full S.W.F functionality until at least beta :)&lt;br /&gt;&lt;br /&gt;Oscar&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-111274908575030737?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/111274908575030737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=111274908575030737' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/111274908575030737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/111274908575030737'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2005/04/windowsforms-and-mac-osx.html' title='Windows.Forms and Mac OS/X'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110610461598459095</id><published>2005-01-18T22:15:00.000-05:00</published><updated>2005-01-18T22:34:56.163-05:00</updated><title type='text'>When is a sort not a sort...</title><content type='html'>I've been expanding on the classical image processing in Damocles lately.  Specifically the Rank Operator.  It works like this, take all the pixel values around a central pixel, sort them by value, then replace the central pixel with the minimum / maximum / median / r th pixel from the sorted list. &lt;br /&gt;Now, it seems obvious that you don't need to actually sort data to find the min or max value from a list.  Finding the min/max of a list is an O(n) operation.  Any other position in the list, however, is usually calculated by doing a full sort, then returning the rth ranked item from the list.  A quick glance at this shows that you are performing an O(n log(n)) or O(n^2) sort in order to generate one number, then throwing away most of the data.  Yet, this is how most software performs median filtering.  It's really no problem when your neighbourhood is small (3x3 cross or box) but as your kernel size grows, the sort becomes the biggest concern.  &lt;br /&gt;So how do we avoid it?  By using a slightly different definition of median.  Traditional processing says that for any N items, the median value is the N/2th value after sorting.  We can also use the following definition: the median value is the value that has the same number of values greater than it as smaller than it.  Formally, &lt;br /&gt;&lt;br /&gt;Median when either&lt;br /&gt;1) smaller=larger &lt;br /&gt;2) smaller &amp;lt; larger AND smaller+equal&amp;gt;=larger&lt;br /&gt;&lt;br /&gt;The second test allows for duplicate values in the list and for even values of N.  This is a generalization of the min test or max test.  The min test is smaller==0 while the max test is larger==0.  &lt;br /&gt;You can generalize this to any position in the list as follows:&lt;br /&gt;&lt;br /&gt;(zero based) r'th in list when either&lt;br /&gt;1) smaller=r &lt;br /&gt;2) smaller&amp;lt;r AND smaller+equal&amp;gt;=r&lt;br /&gt;&lt;br /&gt;In this manner, we only need to keep track of how many items are smaller and how many are equal.  &lt;br /&gt;&lt;br /&gt;Also, every time we test a value, we can use the results to fine tune the next iteration.  For example, if a value of, say, 63 is determined to be too small to be the median, we can ignore any values in the list &amp;lt;=63.  Likewise for values that are too big.  By doing this, you progressively narrow the allowable range and avoid testing many values in the list.&lt;br /&gt;&lt;br /&gt;Finally, when largest_possible==smallest_possible, you don't have to do any more testing at all, just return smallest_possible.&lt;br /&gt;&lt;br /&gt;&lt;code&gt; &lt;br /&gt;// ----------------------------------------------&lt;br /&gt;// Function: Rank&lt;br /&gt;// Parameters:&lt;br /&gt;// &amp;nbsp;&amp;nbsp;&amp;nbsp;list: an array of (type)&lt;br /&gt;// &amp;nbsp;&amp;nbsp;&amp;nbsp;length: number of entries in list&lt;br /&gt;// &amp;nbsp;&amp;nbsp;&amp;nbsp;rank: rank within list [0..length-1]&lt;br /&gt;// (floating point data needs code changes)&lt;br /&gt;// ----------------------------------------------&lt;br /&gt;(type) Rank((type) *list,int length,int rank) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(type) temp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(type) smallest=Smallest(type), largest=Largest(type);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;int i,j,lower,same;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (i=0;i&amp;lt;length;i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp=list[i];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ((temp&amp;lt;=largest) &amp;&amp; (temp&amp;gt;=smallest)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (lower=0,same=0,j=0;j&amp;lt;length;j++) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (list[j]&amp;lt;temp) lower++; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else if (list[j]==temp) same++; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (lower==rank) return temp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else if (lower&amp;gt;rank) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (temp&amp;lt;=largest) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;largest=temp-1; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (smallest==largest) return smallest; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} else { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (lower+same&amp;gt;rank) return temp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (temp&amp;gt;=smallest) { &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;smallest=temp+1; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (smallest==largest) return smallest; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;return (smallest+largest)/2;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;A 3x3 rank is usually done with a modified bubble sort (for simplicity, code size, and partial sorting capability) that stops after r iterations in the outer loop.  This routine compare well with this.&lt;br /&gt;This code performs well on random data usually beating O(n log(n)) (quicksort et al).  On identical data, it is O(1).  The pathological worst case is when the numbers are sorted into max, min, max-1, min-1, max-2, min-2, etc.  In this case, the operation performs O(n^2) or O(n*range(type)) whichever is smaller.  This is not a naturally occuring pattern in image data, however.  On large lists, the range(type) clamps the log(n) term to log(range(type)) so performing extremely large ranking operations becomes possible with no additional computation (free!)&lt;br /&gt;&lt;br /&gt;Oscar&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110610461598459095?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110610461598459095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110610461598459095' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110610461598459095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110610461598459095'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2005/01/when-is-sort-not-sort.html' title='When is a sort not a sort...'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110257214383285670</id><published>2004-12-08T23:23:00.000-05:00</published><updated>2004-12-09T01:02:23.833-05:00</updated><title type='text'>Firewire is an onion...</title><content type='html'>I've spent about a week pouring over Firewire documents.  There are a few.  I've summarized the important specs and tech data below.&lt;br /&gt;The first document is commonly known as CSR although it is formally known by ANSI/IEEE 1212-2001 or by ISO/IEC 13213:1994.  CSR stands for Control and Status Register and describes a method for devices to communicate via a shared memory address (64 bits).  The basic operations are read/write a quadlet (a 32 bit value), read/write an octlet (a 64-bit value), read/write a block (arbitrary size) and lock.  The commands are completed asynchronously (i.e. non-blocking) but a software abstraction layer can create the illusion of synchronous calls.  CSR describes how a bus can work but is not tied to any particular implementation.&lt;br /&gt;The next document is known as IEEE 1394-1995 or 1394a-2000 or 1394b-2002 High Speed Serial Bus.  It is an implementation of CSR.  It describes a hot-pluggable bus that can provide power as well as data transmission, typically at 400Mbps (the most common) but can go faster (3200Mbps) or slower (100Mbps) with the newer "b" spec.  The bus creates a tree topology with a "root" having possibly multiple children.  This tree can contain up to 63 nodes but due to bandwidth reasons there is usually far fewer (eg 1 or 2) devices.  Unlike the popular USB2.0 spec, this bus is equally at home connecting computer to device, device to device or computer to computer.  This allows it to be equally at home connecting consumer A/V equipment or connecting two (or more) computers.  It does have a weakness, however.  It's enumeration mechanism does not handle circular connections well.  In other words, there can only be one path along the tree from one device to any other.&lt;br /&gt;Another key capability of this bus is isochronous communications.  This allows you to pre-allocate bandwidth so that time based data (audio/video) will be guaranteed to have the bandwidth available.  Asynchronous communications have to use the remaining unallocated bandwith.  There is a minimum amount of bandwidth reserved for asynchronous so that other devices are not starved out (typically 20%).  This means that the maximum isochronous bandwidth a S400 device can allocate is about 320Mbps.&lt;br /&gt;Due to it's "hot pluggable" nature, every time a device is plugged in or unplugged, the bus is reset and re-enumerated.  The devices that were transmitting isochronously get a chance to reallocate their bandwidth.  This can cause a "blip" in the data stream.  Software can be notified of a bus reset and take appropriate action.  Since the node address can change with a reset, each device has a unique ID available known as an EUI-64.  This ID is formed from a 24 bit Vendor ID (assigned by a central authority) as well as a 40 bit serial number assigned by the vendor.  Two otherwise identical devices will have distinct EUI-64's.&lt;br /&gt;Every Firewire device must implement a minimum amount of CSR registers.  This allows the enumeration mechanism to work as well as determine what protocols the device understands.  It also determines the bus capabilites of the device.  A device can be a cycle master (it can generate the bus start of cycle packets), an isochronous manager (isoch. bandwidth and channel allocation mechanism), or bus manager (supply and manage power, bus optimization and root determination).  The bus can operate without a bus manager but both devices must supply their own power.  A device does not need to be any of the above.&lt;br /&gt;The CSR's form directories with offsets pointing to where to find other directories.  This allows for a generic tree configuration.  The Bus Info Block is first and is always located at offset 0x400.  Immediately following is the Root Directory that describes the device and contains offsets to unit directories.  A device can support multiple protocols and multiple versions of the same protocol.  Each unit dependant directory lists a protocol by Protocol ID and spec version # and the offset where to find the CSR's that control the device using that protocol and version #.  &lt;br /&gt;The next spec to read up on is the IIDC 1394-based Digital Camera specification version 1.30, 1.20 or 1.04 (also known as DCAM).  It is a defined by the 1394 Trade Association Instrumentation and Industrial Control Working Group, Digital Camera Sub Working group  (II-WG DC-SWG).  It's purpose is to define a command set for digital cameras that use the firewire bus.  This is a completely separate group from the DV group which comprise a whole laundry list of specs.  More importantly, it defines uncompressed digital camera operations.  DV cameras use a lossy MPEG2 video compression variant to transmit data.&lt;br /&gt;The spec provides several inquiry registers that allow you to determine what data formats, frame rates, image sizes, etc. are available.  This allows software to choose a configuration that it can deal with and ignore the others if it wants.  There are 5 standard formats each with standard image sizes and frame rates available for compatibility purposes as well as a fixed image format (for still cameras) and a flexible format where you can configure your camera's options known as Format 7.  This is by far the most flexible format and allows you to change every aspect of your image data.  &lt;br /&gt;The spec also defines standard image controls (Brightness, Auto-expose, Sharpness, White Balance, Hue, Saturation, Gamma, Shutter, Gain, Iris, Focus, Temperature, Trigger, Zoom, Pan, Tilt, Optical Filter) as well as the level of support for each of these capabilities (not present, read only, read-write, auto-mode, one-push mode, disable mode, valid range).  Format 7 also allows you to specify the Region of Interest within the image as well as the valid sizes available.  Finally, you can choose your data format (YUV4:2:2, YUV4:1:1, RGB8, Y8, Y16, etc).  Additional, camera specific, controls can be added in an advanced CSR controls directory but additional info is required from the manufacturer in order to identify and translate these CSR's into camera features.  The most important of these is binning options.  Finally, once you have set up your camera, you can tell it to acquire one image (one-shot) a series of images (multi-shot) or a stream of images (stream).  Of course, if your camera is a still camera, isoch stream will not be available.&lt;br /&gt;In general, the specs work together as a protocol stack to cover and define a very wide range of objects.  There is a spec for Hard Disks, printers, keyboard, mice, generic masss storage (media keys), CD/DVD drives known as SBP-2 and more recently SBP-3.  As mentioned before, consumer DV video falls under many specs such as AV/C and HAVi.  RFC 2734 defines how to layer the IP network protocol on the 1394 bus.  Peruse these at your leisure the next time you get insomnia.  Oh, and by the way, the official PDF of the specs are all sold online for about $100 a pop.  Happy reading.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110257214383285670?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110257214383285670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110257214383285670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110257214383285670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110257214383285670'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/12/firewire-is-onion.html' title='Firewire is an onion...'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110152105063806614</id><published>2004-11-26T20:23:00.000-05:00</published><updated>2004-11-26T21:04:10.636-05:00</updated><title type='text'>29.97 fps? what's up with that...</title><content type='html'>I've been recently delving into the IEEE-1394 specs (also known as Firewire or i.Link).  It is a general purpose bus that, unlike USB, is not PC specific.  The various specs work together in stack fashion similar to the ISO network stack with each layer building upon the layer below.  The bus is capable of asynchronous communication but it is it's isochronous capabilities that make it suitable for carrying time-based data such as video and audio.  &lt;br /&gt;The Firewire 400 spec (1394a) uses a native 125 ns clock.  When video transfers over firewire isochronously, the necessary bandwidth is reserved first.  Once this is done, you just start streaming and wait for the video to pour in.  Each frame of video is divided into bus frames.  When the first frame's reserved bandwidth is filled, the remaining data is sent in subsequent bus frames.  Well, it turns out PAL video (25fps) transfers just fine since a new video frame starts every (8000/25) 320th bus frame.  However, NTSC video (30fps) has a problem.  8000/30 is approximately 266.6666 repeating.  This means that a minimum of 267 frames are necessary (the last frame is padded out).  This means that a 1/30th of a second is really 267/8000 of a second which gives you a frame rate of 29.962546816479 fps.  &lt;br /&gt;Audio is different.  Audio has no inherent audio frame the way that video has a video frame.  You can sample audio at whatever frequency you want and with as much precision you want from as many independent sources you want.  You can divide it up into packets of whatever is convenient for transport without any fuss at all.&lt;br /&gt;So what happens when you try and sync separate audio and video sources?  Well, if the video is timed at 29.97 fps but the software assumes it is 30fps then after an hour, the lip movements will be almost 135 video frames out of sync.&lt;br /&gt;It is important to realize that you can avoid this problem completely if you change your camera so that video frame boundaries do NOT coincide with bus boundaries.  Then, your video data is just a stream of bytes that will always fit neatly into bus frames, albeit starting generally somewhere inside a bus frame instead of at the beginning.  You need to add information to your video data to recognize a frame start.  A little bit of overhead and complexity solves this problem.&lt;br /&gt;So there you go.  Crazy frame rates explained.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110152105063806614?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110152105063806614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110152105063806614' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110152105063806614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110152105063806614'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/2997-fps-whats-up-with-that.html' title='29.97 fps? what&apos;s up with that...'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110075668569441319</id><published>2004-11-18T01:24:00.000-05:00</published><updated>2004-11-18T00:44:45.693-05:00</updated><title type='text'>How sharp is sharp?...</title><content type='html'>Ok, I just came across an article over at &lt;a href="http://cross-platform.net"&gt;cross-platform.net&lt;/a&gt; that talks about doing precisely what I am doing with Damocles, namely, writing cross-platform native code that has a managed cross-platform binding in C#.  The article mentions that my design pattern has a very subtle bug that can occur due to the fact that the C# garbage collector might kick in AFTER marshalling the args to an interop call but before the call actually finishes, causing the (admittedly highly unlikely) problem where the finalizer gets called and frees the unmanaged object too soon.  &lt;br /&gt;Now, this can't occur if you always dispose of your objects properly.  It is slightly more likely to occur in a multithreaded scenario since the GC can run simultaneously with unmanaged code.  Regardless, the solution is easy, and so I've decided to add it to the DamoclesSharp project.&lt;br /&gt;It boils down to this: Instead of storing a private IntPtr, you instead store a HandleRef which contains an IntPtr.  It also contains a reference to the managed object forever tying the managed and unmanaged sides together.  This way, the managed object is held until the HandleRef is disposed of, thereby guaranteeing the lifetime of the original object.  &lt;br /&gt;Is it a bug?  Is it just a theoretical possibility that would never happen in real life?  It sure hasn't happened yet, but I haven't run any multithreaded tests either.  Also, even though the possibility is very small, the consequences are huge.  Processing memory that has been freed can result in a segfault or even cause the Blue Screen of Death if processing a buffer owned by the kernel, (say a video buffer that was wrapped).  &lt;br /&gt;&lt;br /&gt;So the code now looks like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class Image : IDisposable {&lt;br /&gt;&lt;br /&gt;private HandleRef native=NULL;&lt;br /&gt;&lt;br /&gt;public Image() { ... }&lt;br /&gt;public Image(IntPtr NativePtr) { native=new HandleRef(this,NativePtr); ... }&lt;br /&gt;~Image() {....}&lt;br /&gt;&lt;br /&gt;#region IDisposable implementation&lt;br /&gt;...&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;#region Interop calls&lt;br /&gt;[DllImport(Damocles.DllName)] private static extern IntPtr AllocateImage(...)&lt;br /&gt;[DllImport(Damocles.DllName)] private static extern void AddImageReference(...)&lt;br /&gt;[DllImport(Damocles.DllName)] private static extern void FreeImage(...)&lt;br /&gt;... other Interop functions here ...&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So this way, we avoid getting cut with DamoclesSharp (I'm sorry, I couldn't resist the pun!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110075668569441319?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110075668569441319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110075668569441319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110075668569441319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110075668569441319'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/how-sharp-is-sharp.html' title='How sharp is sharp?...'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110022352043827548</id><published>2004-11-11T20:18:00.000-05:00</published><updated>2004-11-11T22:38:19.650-05:00</updated><title type='text'>Damocles is Sharp!</title><content type='html'>Damocles can also be used from any managed language.  Known as DamoclesSharp, it is a library that provides managed wrappers or equivalents to the C "objects" of Damocles.  A typical class looks like the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class Image : IDisposable {&lt;br /&gt;&lt;br /&gt;private IntPtr nativePtr=NULL;&lt;br /&gt;&lt;br /&gt;public Image() { ... }&lt;br /&gt;public Image(IntPtr NativePtr) { ... }&lt;br /&gt;~Image() {....}&lt;br /&gt;&lt;br /&gt;#region IDisposable implementation&lt;br /&gt;...&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;#region Interop calls&lt;br /&gt;[DllImport(Damocles.DllName)] private static extern IntPtr AllocateImage(...)&lt;br /&gt;[DllImport(Damocles.DllName)] private static extern void AddImageReference(...)&lt;br /&gt;[DllImport(Damocles.DllName)] private static extern void FreeImage(...)&lt;br /&gt;... other Interop functions here ...&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt; &lt;br /&gt;The class is implemented with the unmanaged resources design pattern.  That is, it creates, modifies, and frees an unmanaged resource (in this case, our C "object").  It implements IDisposable to signal that it contains unmanaged resources and it implements a finalizer that works with the IDisposable implementation to ensure that the C "object" will be freed when the managed object is.  Again, the object can create the underlying C "object" or can be created to wrap an existing one.  &lt;br /&gt;&lt;br /&gt;Just like the ObjC implementation, the C# implementation works with the C memory management to ensure no memory leaks.  &lt;br /&gt;&lt;br /&gt;Also like the ObjC implementation, there are some optimizations in place.  Since the IntPtr is just a managed wrapper around a pinned address to memory, there is no need to cross the interop boundary to read/write the contents of the underlying object.  Care has been taken to compensate for the size of the pointer during this.  As a result, reading and writing the object properties can be done without incurring an interop penalty.  Again, just like the ObjC optimizations, any code using the class is completely unchanged and continues to work as before. &lt;br /&gt;&lt;br /&gt;This code wraps Damocles.dll on the PC and libDamocles.dylib on the Mac.  A simple config file makes this interop layer code portable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110022352043827548?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110022352043827548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110022352043827548' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110022352043827548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110022352043827548'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/damocles-is-sharp.html' title='Damocles is Sharp!'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110021588346786374</id><published>2004-11-11T18:16:00.000-05:00</published><updated>2004-11-11T20:12:01.430-05:00</updated><title type='text'>Damocles from C to ObjC</title><content type='html'>Now that we have some memory managed "objects" in C with some functions that use them, we need to make real OO objects.  Each ObjC object has a corresponding C "object".&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;@interface NSImage : NSObject {&lt;br /&gt;Image *image;&lt;br /&gt;}&lt;br /&gt;- (id)init;&lt;br /&gt;- (id)initWithImage:(Image *)pImage;&lt;br /&gt;- (void)dealloc;&lt;br /&gt;..... other messages ...&lt;br /&gt;@end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When you allocate a NSImage object, with the init message, it allocates an underlying C "object".  When the dealloc message is called, either through a release message or indirectly via a [NSAutoReleasePool release] message, the underlying C "object" is released.  This way, ObjC object memory management works with C "objects" to make memory management seamless.&lt;br /&gt;&lt;br /&gt;When you allocate a NSImage object with the initWithImage message, it performs an AddRef on the C "object".  This way, it gets it's own reference to the C "object" which it can release in the same way that the first NSImage object does.&lt;br /&gt;&lt;br /&gt;All these ObjC objects get compiled into a native Mac Framework and can be directly used by any Cocoa-based Mac project.  This is how EyeImage (one of our commercial products) gets it's functionality.&lt;br /&gt;&lt;br /&gt;There are some minor variations.  For instance, an ObjC NSImage object might temporarily allocate a C Image "object" in order to generate a displayable image then immediately deallocate it.  For performance reasons, no ObjC object wraps this temporary object.  Such cases are rare, however.  Premature optimization is the root of all software evil.  In this case, however, the optimization was deemed worth it.  This optimization does not cause a change in any software that uses NSImage.  Optimization across an interface boundary is almost always an indication of bad design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110021588346786374?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110021588346786374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110021588346786374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021588346786374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021588346786374'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/damocles-from-c-to-objc.html' title='Damocles from C to ObjC'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110021431098560500</id><published>2004-11-11T17:49:00.000-05:00</published><updated>2004-11-11T18:11:18.106-05:00</updated><title type='text'>Memory management in Damocles</title><content type='html'>Memory management is a tricky subject when dealing with native code.  ObjC uses reference counting similar to COM's.  Managed code uses a garbage collector.   In order to be flexible, Damocles has to be able to "wrap" buffers it didn't allocate and support multiple pointer references.  This way, it can support multiple views/subviews of the same data. as well as be "held" by more than one object.&lt;br /&gt;&lt;br /&gt;I came up with a reference counting mechanism that does both and simplifies memory management for non-trivial cases.&lt;br /&gt;&lt;br /&gt;Each "object" is really a c-style structure that has fields, a pointer to it's data payload and a reference count.&lt;br /&gt;&lt;br /&gt;example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;typedef struct {&lt;br /&gt;void *pData;&lt;br /&gt;S32 RefCount;&lt;br /&gt;U32 width;&lt;br /&gt;U32 height;&lt;br /&gt;} Image;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;S32 and U32 have been defined in os.h as a signed and unsigned (respectively) 32bit integer.  os.h shields Damocles from platform differences in C's integer definition making the code more portable.  Also, void * will be a 32bit value on 32bit systems and a 64bit value on 64bit systems.  &lt;br /&gt;&lt;br /&gt;When an Image struct is allocated, you have 2 options.  You can pass a pointer to an existing buffer in which case RefCount will be set to -1.  Calling AddRefCount on Image will cause RefCount to go to -2.  Calling Free on Image causes RefCount to go back to -1.  Calling Free again causes Image to throw away the pointer and deallocate the structure.&lt;br /&gt;&lt;br /&gt;If you DON'T pass a pointer to an existing buffer, one is allocated for you and RefCount=1; Calling AddRefCount on Image will cause RefCount to go to 2.  Calling Free on Image causes RefCount to go back to 1.  Calling Free again causes the pointer to be freed and then the structure to be freed.&lt;br /&gt;&lt;br /&gt;In this way, you can have multiple references to a struct that holds data that may or may not be wrapped.  You can Free the Image in an arbitrary order to the order they were Allocated or AddRef'd and the last one will properly give up or deallocate the buffer properly.&lt;br /&gt;&lt;br /&gt;This was critical to correct operation where you need to return a linked list of objects.  This way, the list holds it's own reference.  you can select an object from the list, AddRef it, destroy the list, use the object then Free it and everything works the way it should.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110021431098560500?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110021431098560500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110021431098560500' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021431098560500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021431098560500'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/memory-management-in-damocles.html' title='Memory management in Damocles'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110021333891729810</id><published>2004-11-11T17:22:00.000-05:00</published><updated>2004-11-11T17:48:58.916-05:00</updated><title type='text'>Obsidian, meet Damocles.</title><content type='html'>As started in the previous post, Damocles was born out of the need to get native performance in my C# classes.  Damocles is implemented in portable ANSI C.  It is a collection of very low level functions to do imaging.  It is not optimized to favour one CPU or another although I did do a lot of work to minimize the working set and instruction count.  It is fast but not hand-tuned assembly fast.  It does NOT use the Altivec instructions on the PPC or the MMX/SSE instructions on the PC.  These will be addressed later.  Damocles was designed to be a well performing PORTABLE base.&lt;br /&gt;&lt;br /&gt;Considering the lack of niceties in plain C, it is amazing that elegant code can be written using it.  Granted, when you are writing 18 versions of Boolean XOR, programming niceties aren't what gets the job done.  It's small, efficient, tight code that does. &lt;br /&gt;&lt;br /&gt;I mentioned 18 because that's how many different pixel formats that Damocles currently supports.  That does NOT count paletteized versions.  Due to the need to support higher than 8 bits per channel images as efficiently as possible, there is direct support for 8,10,12,14 &amp; 16 bits per channel as well as single precision floating point support.  Since there can be Gray, RGB, and RGBA colorspaces, that makes 6 choices for channel depth x 3 colorspaces = 18 pixel formats.  &lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110021333891729810?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110021333891729810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110021333891729810' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021333891729810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021333891729810'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/obsidian-meet-damocles.html' title='Obsidian, meet Damocles.'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110021098706209721</id><published>2004-11-11T16:09:00.000-05:00</published><updated>2004-11-11T17:10:08.596-05:00</updated><title type='text'>How to write Software... (part 4)</title><content type='html'>I should mention that I have a bias towards C# as a language.  It is modern, OO, and has lots of language features that lend themselves to writing elegant programs.  I also follow the progress of the Mono:: and DotGNU Portable.NET open source projects that allow C# to run on several platforms.  The platforms I am most concerned about are (in order) Windows XP, Mac OS/X, and Linux (x86 &amp; PPC).  &lt;br /&gt;&lt;br /&gt;What is NOT available is a cross platform UI for C#.  There are candidates (wxNET, GTKSharp, TK#, SWF, SWT) but they are either incomplete, defunct, or just not ready yet for all my platforms.&lt;br /&gt;&lt;br /&gt;Well, the obvious choice was to separate UI from functionality (always a good decision anyway) and write my imaging library first in C#.  By then, surely, there would be a UI that I could use.  If I put my UI behind a C# interface, then I could even load a different UI for each different platform.  The same with hardware support.  Everything behind an interface.  I just need to do a little reflection discovery at load time to see what I have available.&lt;br /&gt;&lt;br /&gt;I designed the project and called it Obsidian.  Why not.  I wrote the discovery code and the library.  Lots of formal interfaces.&lt;br /&gt;It was implemented in several assemblies.  A real medium-to-large size C# app sans a UI.&lt;br /&gt;&lt;br /&gt;A year passed.  I kept up to date with all kinds of projects, both commercial and free.  And guess what.  I got burned.  No UI materialized that was even a 1.0 release.  I even tried starting interest in creating a project called CocoaSharp.  It was supposed to bring Cocoa (the Mac's native Object framework) into the managed world.  I worked a few weeks on it and released a version 0.1 that wrapped a few key Cocoa UI classes.  Nobody was interested in contributing to the work and I was looking at wrapping by hand hundreds of classes (which were changing underneath me with new OS/X updates).  I gave up and e-mailed the code so someone who asked for it and called it a life lesson.  Note that my CocoaSharp project predated but was otherwise unrelated to the current CocoaSharp project underway, at least to my knowledge.&lt;br /&gt;&lt;br /&gt;As it turns out, processing pixels (even in unsafe code) is not a performance demon under dotNET 1.0 or 1.1 so I got to thinking that C# might not be the full answer.  &lt;br /&gt;&lt;br /&gt;I had some experience with Interop (the method that managed code interfaced with native code) while writing managed camera classes that linked with some native libraries on the PC and the Mac.  It even chose at runtime which native library to use through the same discovery mechanism I had written for the rest of Obsidian.&lt;br /&gt;&lt;br /&gt;I decided it was time to bite the bullet.  Write the lowest level functions in C.  Plain C.  K&amp;R C. no modern conveniences C.  portable C.  Then, I could wrap them into ObjC objects on the Mac, C++ objects on Linux, and C# objects wherever a CLR was available.  Damocles was born.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110021098706209721?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110021098706209721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110021098706209721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021098706209721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110021098706209721'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/how-to-write-software-part-4.html' title='How to write Software... (part 4)'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110020654563785277</id><published>2004-11-11T15:24:00.000-05:00</published><updated>2004-11-11T15:55:45.636-05:00</updated><title type='text'>How to write Software... (part 3)</title><content type='html'>So, let's start.  I need to write imaging software that is cross-platform.  It should perform and feel like a native application on every platform it supports.  It should also be able to take advantage of any platform specific features but degrade gracefully on platforms that lack those features.  It should be capable of taking advantage of multiple processors.  It should be pointer size agnostic (32 or 64 bit)&lt;br /&gt;&lt;br /&gt;Programming language choices available to me:&lt;br /&gt;C&lt;br /&gt;C++&lt;br /&gt;Managed C++&lt;br /&gt;ObjC&lt;br /&gt;C#&lt;br /&gt;Java&lt;br /&gt;Visual Basic&lt;br /&gt;VB.NET&lt;br /&gt;&lt;br /&gt;C : Granddaddy of them all&lt;br /&gt;pro's - ubiquitous. performs well.  portable.&lt;br /&gt;con's - low level, lack of object oriented concepts, verbose.&lt;br /&gt;&lt;br /&gt;C++ : C with objects&lt;br /&gt;pro's - same as C but with OO concepts&lt;br /&gt;con's - interfacing and binding are more difficult than C&lt;br /&gt;&lt;br /&gt;Managed C++ : Managed C with objects&lt;br /&gt;pro's - same as C++ but runs within the confines of the CLR.&lt;br /&gt;con's - performance is not as good as C++, not portable.&lt;br /&gt;&lt;br /&gt;ObjC - Native objects on OS/X&lt;br /&gt;pro's - interfacing done at runtime &lt;br /&gt;con's - not portable, message based calls slower than direct function calls.&lt;br /&gt;&lt;br /&gt;C# - Managed C with objects&lt;br /&gt;pro's - easy language, portable using mono or pnet on non MS platforms.&lt;br /&gt;con's - performance is not as good as C, C++&lt;br /&gt;&lt;br /&gt;Java - portable C-like language&lt;br /&gt;pro's - portable&lt;br /&gt;con's - different platforms have slightly different implementations, performance&lt;br /&gt;&lt;br /&gt;Visual Basic, VB.NET - missing critical pointer manipulation&lt;br /&gt;&lt;br /&gt;In the next part, we'll see what I chose and why I chose it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110020654563785277?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110020654563785277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110020654563785277' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110020654563785277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110020654563785277'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/how-to-write-software-part-3.html' title='How to write Software... (part 3)'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110020445388047411</id><published>2004-11-11T15:01:00.000-05:00</published><updated>2004-11-11T15:22:20.946-05:00</updated><title type='text'>How to write Software... (part 2)</title><content type='html'>I guess I should mention that I'm talking here about writing imaging software.  In other words, the software that I write creates, enhances, processes, analyzes and extracts and captures images.  If I were a database programmer then this thread would be very different.&lt;br /&gt;&lt;br /&gt;The first step in writing any software is gathering your requirements.&lt;br /&gt;&lt;br /&gt;The "What's"  &lt;br /&gt;What should the software do? &lt;br /&gt;What O/S does it need to run on?&lt;br /&gt;What software does it need to interact with?&lt;br /&gt;What hardware does it need to interact with?&lt;br /&gt;What are the time constraints?  &lt;br /&gt;&lt;br /&gt;The "Who's"&lt;br /&gt;Who is the end user/operator?&lt;br /&gt;Who is paying for the software?&lt;br /&gt;Who will maintain the software?&lt;br /&gt;&lt;br /&gt;The "Where's"&lt;br /&gt;Where does the software need to be developed?&lt;br /&gt;Where will training/installation take place?&lt;br /&gt;&lt;br /&gt;The "When's"&lt;br /&gt;When does the software need to be done?&lt;br /&gt;When is the software finished?&lt;br /&gt;When are updates needed?&lt;br /&gt;&lt;br /&gt;The "How's"&lt;br /&gt;How will feedback take place?&lt;br /&gt;How will upgrades occur?&lt;br /&gt;&lt;br /&gt;There are a lot of questions.  And I haven't asked them all.&lt;br /&gt;Since software is never really done, the more questions you ask now, the better off you will be later in the product life cycle.&lt;br /&gt;Note that these questions assume that you are being paid to write software.  When you write software for free, most of these questions can be answered by "whenever I get to it" or "next time I'm doing something with that".  There is a lot of freedom in NOT getting paid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110020445388047411?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110020445388047411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110020445388047411' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110020445388047411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110020445388047411'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/how-to-write-software-part-2.html' title='How to write Software... (part 2)'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9115843.post-110020279752686812</id><published>2004-11-11T14:47:00.000-05:00</published><updated>2004-11-11T14:53:17.553-05:00</updated><title type='text'>How to write Software... (part 1)</title><content type='html'>This seems like such an easy thing to do.  I mean, people write software every day.  I don't pretend to know everything about writing software.  There is so many different kinds of software out there that it would be foolish to think that there is ONE way that is best.  But I have been thinking about this so I thought I'd write down what I've come up with as well as talk about some of my recent attempts at it.  I don't have all the answers.  I don't even have all the questions.  Let's dance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9115843-110020279752686812?l=oepapel.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oepapel.blogspot.com/feeds/110020279752686812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9115843&amp;postID=110020279752686812' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110020279752686812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9115843/posts/default/110020279752686812'/><link rel='alternate' type='text/html' href='http://oepapel.blogspot.com/2004/11/how-to-write-software-part-1.html' title='How to write Software... (part 1)'/><author><name>Oscar Papel</name><uri>http://www.blogger.com/profile/05146065319520650959</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://photos5.flickr.com/8596105_439c4d3d92_o.jpg'/></author><thr:total>0</thr:total></entry></feed>
