<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>QuickTime for Java: A Developer's Notebook/Audio Media - Revision history</title>
		<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;action=history</link>
		<description>Revision history for this page on the wiki</description>
		<language>en</language>
		<generator>MediaWiki 1.11.0</generator>
		<lastBuildDate>Thu, 20 Jun 2013 04:07:58 GMT</lastBuildDate>
		<item>
			<title>Newacct at 08:22, 12 May 2010</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=26177&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 08:22, 12 May 2010&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 99:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 99:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   protected static void dumpTagsFromUserData (UserData userData) {&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   protected static void dumpTagsFromUserData (UserData userData) {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;       // try for each &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;key &lt;/del&gt;in TAG_MAP&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;       // try for each &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;entry &lt;/ins&gt;in TAG_MAP&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;       Iterator it = TAG_MAP.&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;keySet&lt;/del&gt;( ).iterator( );&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;       &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;for (&lt;/ins&gt;Iterator it = TAG_MAP.&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;entrySet&lt;/ins&gt;( ).iterator( ); it.hasNext( )&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;; &lt;/ins&gt;) {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;       while (&lt;/del&gt;it.hasNext( )) {&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;           Map.Entry entry = (Map.Entry) it.next( );&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           Integer key = (Integer) &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;it&lt;/del&gt;.&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;next&lt;/del&gt;( );&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           Integer key = (Integer) &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;entry&lt;/ins&gt;.&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;getKey&lt;/ins&gt;( );&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           int tag = key.intValue( );&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           int tag = key.intValue( );&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           String tagName = (String) &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;TAG_MAP&lt;/del&gt;.&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;get&lt;/del&gt;(&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;key&lt;/del&gt;);&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           String tagName = (String) &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;entry&lt;/ins&gt;.&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;getValue&lt;/ins&gt;();&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           try {&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;           try {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;               String value =&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;               String value =&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Wed, 12 May 2010 08:22:32 GMT</pubDate>			<dc:creator>Newacct</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Newacct at 01:11, 29 January 2010</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=26121&amp;oldid=prev</link>
			<description>&lt;p&gt;&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 01:11, 29 January 2010&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 52:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 52:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; public class ID3TagReader &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;extends Object &lt;/del&gt;{&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; public class ID3TagReader {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   /* these values are straight out of Movies.h&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   /* these values are straight out of Movies.h&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 581:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 581:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; public class AACTagReader &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;extends Object &lt;/del&gt;{&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; public class AACTagReader {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   /* these values are straight out of Movies.h&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;   /* these values are straight out of Movies.h&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,173:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,173:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; public class AudioSampleBuilder &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;extends Object &lt;/del&gt;{&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; public class AudioSampleBuilder {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;  &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; static final int SAMPLING = 44100;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; static final int SAMPLING = 44100;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wikicontent:diff:version:1.11a:oldid:7242:newid:26121 --&gt;
&lt;/table&gt;</description>
			<pubDate>Fri, 29 Jan 2010 01:11:38 GMT</pubDate>			<dc:creator>Newacct</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=7242&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:22, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 13:22:47 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=7163&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:17, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 143:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 143:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;    [java] Full Name: SPACE LION&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;    [java] Full Name: SPACE LION&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Because the artist (, or &amp;quot;Yoko Kanno&amp;quot; in ''romaji'') is written in non-Western characters, QuickTime doesn't attempt to import it, and thus there's no artist item to retrieve from the user data.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Because the artist (&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;[[Image:QuickTime for Java: A Developers Notebook_I_7_tt101.png]]&lt;/ins&gt;, or &amp;quot;Yoko Kanno&amp;quot; in ''romaji'') is written in non-Western characters, QuickTime doesn't attempt to import it, and thus there's no artist item to retrieve from the user data.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=== What about... ===&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;=== What about... ===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 13:17:34 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=4467&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:26, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:26:00 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=4466&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:17, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 899:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 899:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-1. Balance, treble, and bass controls'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-1. Balance, treble, and bass controls'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_7_tt200.png|Balance, treble, and bass controls]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_7_tt200.png|Balance, treble, and bass controls]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 921:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 921:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-2. Audio level meter in QuickTime Player'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-2. Audio level meter in QuickTime Player'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_7_tt203.png|Audio level meter in QuickTime Player]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_7_tt203.png|Audio level meter in QuickTime Player]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,109:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,109:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-3. Frequency bands displayed as a level meter'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-3. Frequency bands displayed as a level meter'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_7_tt204.png|Frequency bands displayed as a level meter]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_7_tt204.png|Frequency bands displayed as a level meter]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,156:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,156:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-4. Square wave'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-4. Square wave'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_7_tt206.png|Square wave]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_7_tt206.png|Square wave]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,373:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,373:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-5. Sine wave'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 7-5. Sine wave'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developer's &lt;/del&gt;Notebook_I_7_tt208.png|Sine wave]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:QuickTime for Java: A &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Developers &lt;/ins&gt;Notebook_I_7_tt208.png|Sine wave]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:17:35 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=4315&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:16, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:16:22 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=4314&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 00:15, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 00:15:32 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=4163&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 23:57, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 23:57:58 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media&amp;diff=4162&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{QuickTime for Java: A Developer's Notebook/TOC}}&lt;br /&gt;
This is the first of three chapters dealing with specific media types. Video will be covered in [[QuickTime for Java: A Developer's Notebook/Video Media|Chapter 8]], and several other kinds of media—including things you might not have thought of as media, such as text and time codes—will be covered in [[QuickTime for Java: A Developer's Notebook/Miscellaneous Media|Chapter 9]].&lt;br /&gt;
&lt;br /&gt;
It's possible that you've never thought of QuickTime as being the engine for audio-only applications—the ubiquity of QuickTime's ''.mov'' file format probably makes it more readily recognized as a video standard. But QuickTime's support for audio has been critical to many applications. For example, the fact that QuickTime was already ported to Windows made bringing iTunes and its music store over to Windows a lot easier.&lt;br /&gt;
&lt;br /&gt;
In fact, iTunes is probably responsible for getting QuickTime onto a lot more Windows machines than it would have reached otherwise. So, I'll begin with a few labs that are particularly applicable to the MP3s and AACs collected by iTunes users.&lt;br /&gt;
&lt;br /&gt;
== Reading Information from MP3 Files ==&lt;br /&gt;
&lt;br /&gt;
If you've ever listened to an MP3 music file—and at this point, who hasn't—you've surely appreciated the fact that useful information like artist, song title, album title, etc., is stored ''inside'' the file. Not only does this make it convenient to organize your music, but also, when you move a song from one device to another, this ''metadata'' travels with it.&lt;br /&gt;
&lt;br /&gt;
The most widely accepted standard for doing this is the ID3 standard, which puts this metadata into parts of the file that are not interpreted as containing audio data—MP3s arrange data in ''frames'' , and ID3 puts metadata between these frames. ID3 tags typically are found at the beginning of a file, which makes them stream-friendly, although some files tagged with earlier versions of the standard have the metadata at the end of the file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Visit ''http://www.id3.org/'' to learn more about ID3''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When QuickTime imports an MP3 file, it reads ID3 tags and makes them available to your program through the movie's ''user data'', allowing you to display the tags to the user, or use them in any other way you see fit.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
Once you open an MP3 as a movie, you need to get at the user data, which contains the imported ID3 tags. Fortunately, it's wrapped as an object called &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
 UserData userData = movie.getUserData( );&lt;br /&gt;
&lt;br /&gt;
The user data is something of a grab bag of data that you can read from and write to freely. Items are keyed by &amp;lt;tt&amp;gt;FOUR_CHAR_CODE&amp;lt;/tt&amp;gt; s, and the contents aren't required to adhere to any particular standard or format (after all, you're free to write whatever you like in user data). For example, QuickTime Player writes a &amp;quot;&amp;lt;tt&amp;gt;WLOC&amp;lt;/tt&amp;gt;&amp;quot; entry that stores the window location last used for the movie.&lt;br /&gt;
&lt;br /&gt;
Apple has a standard set of keys that you can use to retrieve the data parsed from an MP3's ID3 tags. Because these are text values, you use &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt; 's &amp;lt;tt&amp;gt;getTextAsString( )&amp;lt;/tt&amp;gt; method to pull them out. &amp;lt;tt&amp;gt;getTextAsString( )&amp;lt;/tt&amp;gt; takes three arguments: the type you're requesting; an index to indicate whether you want the first, second, etc., instance of that type; and a region tag that's irrelevant in the ID3 case.&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-EX-1|Example 7-1]] shows a basic exercise of this technique, getting the &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt; object and asking for album, artist, creation date, and song title information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Run this example from the downloadable book code with ant run-ch07-id3tagreader''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-EX-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 7-1. Retrieving ID3 metadata'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch07;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.std.movies.media.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
 import java.util.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 public class ID3TagReader extends Object {&lt;br /&gt;
  &lt;br /&gt;
   /* these values are straight out of Movies.h&lt;br /&gt;
   */&lt;br /&gt;
   final static int  kUserDataTextAlbum            = 0xA9616C62; /*'©alb' */&lt;br /&gt;
   final static int  kUserDataTextArtist           = 0xA9415254; &lt;br /&gt;
   final static int  kUserDataTextCreationDate     = 0xA9646179; /*'©day' */&lt;br /&gt;
   final static int  kUserDataTextFullName         = 0xA96E616D; /*'©nam' */&lt;br /&gt;
  &lt;br /&gt;
   /* This array maps all the tag constants to human-readable strings&lt;br /&gt;
    */&lt;br /&gt;
   private static final Object[  ][  ] TAG_NAMES = {&lt;br /&gt;
       {new Integer (kUserDataTextAlbum), &amp;quot;Album&amp;quot;},&lt;br /&gt;
       {new Integer (kUserDataTextArtist),&amp;quot;Artist&amp;quot; },&lt;br /&gt;
       {new Integer (kUserDataTextCreationDate), &amp;quot;Created&amp;quot;},&lt;br /&gt;
       {new Integer (kUserDataTextFullName), &amp;quot;Full Name&amp;quot;}&lt;br /&gt;
   };&lt;br /&gt;
  &lt;br /&gt;
   private static final HashMap TAG_MAP =&lt;br /&gt;
       new HashMap(TAG_NAMES.length);&lt;br /&gt;
   static {&lt;br /&gt;
       for (int i=0; i&amp;lt;TAG_NAMES.length; i++) {&lt;br /&gt;
           TAG_MAP.put (TAG_NAMES[i][0],&lt;br /&gt;
                        TAG_NAMES[i][1]);&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       new ID3TagReader( );&lt;br /&gt;
       System.exit(0);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public ID3TagReader( ) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile f = QTFile.standardGetFilePreview (null);&lt;br /&gt;
           OpenMovieFile omf = OpenMovieFile.asRead(f);&lt;br /&gt;
           Movie movie = Movie.fromFile (omf);&lt;br /&gt;
           // get user data&lt;br /&gt;
           UserData userData = movie.getUserData( );&lt;br /&gt;
           dumpTagsFromUserData(userData);&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   protected static void dumpTagsFromUserData (UserData userData) {&lt;br /&gt;
       // try for each key in TAG_MAP&lt;br /&gt;
       Iterator it = TAG_MAP.keySet( ).iterator( );&lt;br /&gt;
       while (it.hasNext( )) {&lt;br /&gt;
           Integer key = (Integer) it.next( );&lt;br /&gt;
           int tag = key.intValue( );&lt;br /&gt;
           String tagName = (String) TAG_MAP.get(key);&lt;br /&gt;
           try {&lt;br /&gt;
               String value =&lt;br /&gt;
                   userData.getTextAsString (tag,&lt;br /&gt;
                                             1,&lt;br /&gt;
                                             IOConstants.langUnspecified);&lt;br /&gt;
               System.out.println (tagName + &amp;quot;: &amp;quot; + value);&lt;br /&gt;
           } catch (QTException qte) {  } // no such tag&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run, this dumps the found tags to standard out, as seen in the following console output:&lt;br /&gt;
&lt;br /&gt;
 cadamson% ant run-ch07-id3tagreader&lt;br /&gt;
 Buildfile: build.xml&lt;br /&gt;
  &lt;br /&gt;
 run-ch07-id3tagreader:&lt;br /&gt;
    [java] Album: Arthur Or The Decline And Fall Of The British Empire&lt;br /&gt;
    [java] Full Name: Victoria&lt;br /&gt;
    [java] Artist: The Kinks&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The application sets up some static values for keys it is interested in and maps them to human-readable names. For example, the &amp;lt;tt&amp;gt;FOUR_CHAR_CODE&amp;lt;/tt&amp;gt; &amp;quot;&amp;lt;tt&amp;gt;@alb&amp;lt;/tt&amp;gt;&amp;quot; is mapped to &amp;quot;Album.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The program prompts the user to select an MP3 file and imports it as a movie, from which it gets a &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt; object. In &amp;lt;tt&amp;gt;dumpTagsFromUserData( )&amp;lt;/tt&amp;gt;, it calls &amp;lt;tt&amp;gt;getTextAsString()&amp;lt;/tt&amp;gt; to attempt to get a value for each known tag. If successful, it writes the key and value to the console. If a given tag is absent from the user data, QuickTime throws an exception, which this program quietly ignores.&lt;br /&gt;
&lt;br /&gt;
QuickTime has an important and disappointing limitation: it does not import tags written in non-Western scripts. For example, here's the output when I run the application against an MP3 whose &amp;quot;artist&amp;quot; tag is in Japanese ''kana'' (characters):&lt;br /&gt;
&lt;br /&gt;
 cadamson% ant run-ch07-id3tagreader&lt;br /&gt;
 Buildfile: build.xml&lt;br /&gt;
  &lt;br /&gt;
 run-ch07-id3tagreader:&lt;br /&gt;
    [java] Album: COWBOY BEBOP O.S.T.1&lt;br /&gt;
    [java] Created: 1998&lt;br /&gt;
    [java] Full Name: SPACE LION&lt;br /&gt;
&lt;br /&gt;
Because the artist (, or &amp;quot;Yoko Kanno&amp;quot; in ''romaji'') is written in non-Western characters, QuickTime doesn't attempt to import it, and thus there's no artist item to retrieve from the user data.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...other tags? A big list of metadata tags are defined in the native API's ''Movies.h'' file. Unfortunately, these aren't in the &amp;lt;tt&amp;gt;StdQTConstants&amp;lt;/tt&amp;gt; classes, or anywhere else in QTJ, so you have to define your own constants for them. [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-TABLE-1|Table 7-1]] is the list of supported values.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-TABLE-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Table 7-1. Audio metadata tag constants'''&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Constant name !! Hex value !! 4CC&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextAlbum&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9616C62&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©alb&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextArtist&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9415254&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©ART&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextAuthor&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9617574&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©aut&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextChapter&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9636870&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©chp&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextComment&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9636D74&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©cmt&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextComposer&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9636F6D&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©com&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextCopyright&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9637079&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©cpy&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextCreationDate&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9646179&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©day&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextDescription&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9646573&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©des&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextDirector&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9646972&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©dir&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextDisclaimer&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9646973&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©dis&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextEncodedBy&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9656E63&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©enc&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextFullName&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA96E616D&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©nam&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextGenre&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA967656E&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©gen&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextHostComputer&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9687374&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©hst&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextInformation&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9696E66&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©inf&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextKeywords&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA96B6579&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©key&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextMake&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA96D616B&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©mak&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextModel&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA96D6F64&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©mod&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextOriginalArtist&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA96F7065&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©ope&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextOriginalFormat&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9666D74&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©fmt&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextOriginalSource&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9737263&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©src&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextPerformers&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9707266&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©prf&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextProducer&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9707264&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©prd&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextProduct&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9505244&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©PRT&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextSoftware&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9737772&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©swr&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextSpecialPlayback&lt;br /&gt;
 Requirements&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9726571&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©req&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextTrack&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA974726B&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©trk&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextWarning&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA977726E&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©wrn&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextWriter&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9777274&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©wrt&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextURLLink&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA975726C&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©url&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 kUserDataTextEditDate1&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 0xA9656431&lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
 ©ed1&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Also, instead of requesting specific keys from the user data, can I just tour what's in there? Yes, you can use &amp;lt;tt&amp;gt;UserData.getNextType()&amp;lt;/tt&amp;gt; to discover the types of items in the user data. This method takes an &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; of the last discovered type (use &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; on the first call), and returns the next type after that one. When it returns &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;, there are no more types to discover. Given a type, you can get its data with &amp;lt;tt&amp;gt;getTextAsString()&amp;lt;/tt&amp;gt; , but because you can't know that a discovered piece of user data necessarily represents textual data, it might be safer to call &amp;lt;tt&amp;gt;getData( )&amp;lt;/tt&amp;gt; , which returns a &amp;lt;tt&amp;gt;QTHandle&amp;lt;/tt&amp;gt; , from which you can get a byte array with &amp;lt;tt&amp;gt;getBytes( )&amp;lt;/tt&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''This technique is a lot like the &amp;quot;Discovering All Installed Components&amp;quot; lab in [[QuickTime for Java: A Developer's Notebook/Working with Components|Chapter 4]]''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Reading Information from iTunes AAC Files ==&lt;br /&gt;
&lt;br /&gt;
If you read the last lab and thought about how ID3 metadata is imported into a QuickTime movie's &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt;, you might well expect that the same thing would be true of AAC files created by iTunes: ''.m4a'' files for songs &amp;quot;ripped&amp;quot; by the user and ''.m4p'' files sold by the iTunes Music Store. In fact, because these files use an MPEG-4 file format that is itself based on QuickTime, you might think that using the same user data scheme would be a slam dunk.&lt;br /&gt;
&lt;br /&gt;
But...you'd be wrong.&lt;br /&gt;
&lt;br /&gt;
These AAC files do put the metadata in the user data, but they do so in a way that resists straightforward retrieval via QuickTime. Fortunately, it's not ''too'' hard to get the values out with some parsing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Buckle up, this one is rough''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
For once, theory needs to come before code—you need to see the format to understand how to parse it. Here's a &amp;lt;tt&amp;gt;/usr/bin/hexdump&amp;lt;/tt&amp;gt; of an iTunes Music Store AAC file from my collection, ''Toto Dies.m4p'':&lt;br /&gt;
&lt;br /&gt;
 0000b010  00 3d 5f 3c 00 3d 7d 5e  00 3d 9a fb 00 03 18 da  |.=_&amp;lt;.=}^.=......|&lt;br /&gt;
 0000b020  75 64 74 61 00 03 18 d2  6d 65 74 61 00 00 00 00  |udta....meta....|&lt;br /&gt;
 0000b030  00 00 00 22 68 64 6c 72  00 00 00 00 00 00 00 00  |...&amp;quot;hdlr........|&lt;br /&gt;
 0000b040  6d 64 69 72 61 70 70 6c  00 00 00 00 00 00 00 00  |mdirappl........|&lt;br /&gt;
 0000b050  00 00 00 03 11 9b 69 6c  73 74 00 00 00 21 a9 6e  |......ilst...!.n|&lt;br /&gt;
 0000b060  61 6d 00 00 00 19 64 61  74 61 00 00 00 01 00 00  |am....data......|&lt;br /&gt;
 0000b070  00 00 54 6f 74 6f 20 44  69 65 73 00 00 00 24 a9  |..Toto Dies...$.|&lt;br /&gt;
 0000b080  41 52 54 00 00 00 1c 64  61 74 61 00 00 00 01 00  |ART....data.....|&lt;br /&gt;
 0000b090  00 00 00 4e 65 6c 6c 69  65 20 4d 63 4b 61 79 00  |...Nellie McKay.|&lt;br /&gt;
 0000b0a0  00 00 24 a9 77 72 74 00  00 00 1c 64 61 74 61 00  |..$.wrt....data.|&lt;br /&gt;
 0000b0b0  00 00 01 00 00 00 00 4e  65 6c 6c 69 65 20 4d 63  |.......Nellie Mc|&lt;br /&gt;
 0000b0c0  4b 61 79 00 03 0e 76 63  6f 76 72 00 03 0e 6e 64  |Kay...vcovr...nd|&lt;br /&gt;
 0000b0d0  61 74 61 00 00 00 0d 00  00 00 00 ff d8 ff e0 00  |ata.............|&lt;br /&gt;
 0000b0e0  10 4a 46 49 46 00 01 01  01 02 f9 02 f9 00 00 ff  |.JFIF...........|&lt;br /&gt;
&lt;br /&gt;
Granted, this is ''not'' easy to read, but I'll bet you can pick out the artist (Nellie McKay) and the song title (&amp;quot;Toto Dies&amp;quot;), so you know this is the relevant section of the file. In fact, you also might notice the string &amp;quot;&amp;lt;tt&amp;gt;udta&amp;lt;/tt&amp;gt;&amp;quot;...sounds a little like &amp;quot;user data,&amp;quot; doesn't it?&lt;br /&gt;
&lt;br /&gt;
At work here is the QuickTime file format and its concept of ''atoms'' , which are tree-structured pieces of data used to describe a movie, its contents, and its metadata. Without going too deeply into the details—there's a whole book on the format—each atom consists of 4 bytes of size, a 4-byte type, and then data. Atoms contain either data or other atoms, but not both. The 4 bytes before &amp;quot;&amp;lt;tt&amp;gt;udta&amp;lt;/tt&amp;gt;&amp;quot;, &amp;lt;tt&amp;gt;0x000318da&amp;lt;/tt&amp;gt;, indicate the size of all the user data. The first child is an atom called &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot;. Because its size is &amp;lt;tt&amp;gt;0x000318d2&amp;lt;/tt&amp;gt;, just 8 less than the size of &amp;quot;&amp;lt;tt&amp;gt;udta&amp;lt;/tt&amp;gt;&amp;quot;, the &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot; atom is clearly the only child of &amp;quot;&amp;lt;tt&amp;gt;udta&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Unfortunately, because this is user data, the contents don't have to adhere to any published standard, and they don't. The first thing after &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot; should be the 4-byte size of its first child atom, but the value is &amp;lt;tt&amp;gt;0x00000000&amp;lt;/tt&amp;gt;—an illegal &amp;quot;no size&amp;quot; value—so, a normal QuickTime parser would ignore the contents of &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Funny thing is, although these contents aren't real QuickTime atoms, they're ''awfully'' close. Start with the stuff that's obviously the metadata and work backward: &amp;quot;Toto Dies&amp;quot; is preceded by an 8-byte pad (&amp;lt;tt&amp;gt;0x00000001&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;0x00000000&amp;lt;/tt&amp;gt;), and before that is &amp;quot;&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;&amp;quot; and a 4-byte number. That number, &amp;lt;tt&amp;gt;0x00000019&amp;lt;/tt&amp;gt;, is the size of itself, plus &amp;quot;&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;&amp;quot;, plus the 8-byte pad, plus the string &amp;quot;Toto Dies.&amp;quot; And just before that, you'll find the string &amp;quot;&amp;lt;tt&amp;gt;©nam&amp;lt;/tt&amp;gt;&amp;quot;, preceded by a 4-byte size. Better yet, &amp;quot;&amp;lt;tt&amp;gt;©nam&amp;lt;/tt&amp;gt;&amp;quot; is one of the constants defined in ''Movies.h'' for metadata tagging.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''See the previous lab for a list of QuickTime's metadata tags''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dig further and you'll find that there's a run of these tag-name/data structures, each of which has the structure discovered earlier:&lt;br /&gt;
&lt;br /&gt;
;Full size&lt;br /&gt;
: 4 bytes&lt;br /&gt;
;Type&lt;br /&gt;
: 4 bytes&lt;br /&gt;
;Contents size&lt;br /&gt;
: 4 bytes&lt;br /&gt;
;&amp;quot;&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
: 4 bytes&lt;br /&gt;
;Unknown&lt;br /&gt;
: 8 bytes&lt;br /&gt;
;Value&lt;br /&gt;
: Variable number of bytes (size is implicit from earlier size data)&lt;br /&gt;
&lt;br /&gt;
The run of metadata blocks exists within a single pseudo-atom parent called &amp;quot;&amp;lt;tt&amp;gt;ilst&amp;lt;/tt&amp;gt;&amp;quot;. So, this analysis provides a strategy for getting iTunes AAC metadata:&lt;br /&gt;
&lt;br /&gt;
# Get the user data.&lt;br /&gt;
# Look for a user data item called &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot; and get it as a byte array.&lt;br /&gt;
# Inside this array, find &amp;quot;&amp;lt;tt&amp;gt;ilst&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
# Start reading 8-byte blocks as possible size/type combinations. If the type is known as a metadata type, skip past the 24 bytes of junk (the 8-byte pad, the &amp;quot;&amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;&amp;quot;, etc.) and read the &amp;lt;tt&amp;gt;String&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The sample program in [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-EX-2|Example 7-2]] implements this strategy.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Run this example with ant run-ch07-aactagreader''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-EX-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 7-2. Retrieving iTunes AAC metadata'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch07;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.std.movies.media.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
 import quicktime.util.*;&lt;br /&gt;
 import java.util.*;&lt;br /&gt;
 import java.math.BigInteger;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 public class AACTagReader extends Object {&lt;br /&gt;
  &lt;br /&gt;
   /* these values are straight out of Movies.h&lt;br /&gt;
   */&lt;br /&gt;
   final static int  kUserDataTextAlbum            = 0xA9616C62; /*'©alb' */&lt;br /&gt;
   final static int  kUserDataTextArtist           = 0xA9415254; &lt;br /&gt;
   final static int  kUserDataTextCreationDate     = 0xA9646179; /*'©day' */&lt;br /&gt;
   final static int  kUserDataTextFullName         = 0xA96E616D; /*'©nam' */&lt;br /&gt;
  &lt;br /&gt;
   /* This array maps all the tag constants to human-readable strings&lt;br /&gt;
   */&lt;br /&gt;
   private static final Object[  ][  ] TAG_NAMES = {&lt;br /&gt;
       {new Integer (kUserDataTextAlbum), &amp;quot;Album&amp;quot;},&lt;br /&gt;
       {new Integer (kUserDataTextArtist),&amp;quot;Artist&amp;quot; },&lt;br /&gt;
       {new Integer (kUserDataTextCreationDate), &amp;quot;Created&amp;quot;},&lt;br /&gt;
       {new Integer (kUserDataTextFullName), &amp;quot;Full Name&amp;quot;}&lt;br /&gt;
   };&lt;br /&gt;
  &lt;br /&gt;
   private static final HashMap TAG_MAP =&lt;br /&gt;
       new HashMap(TAG_NAMES.length);&lt;br /&gt;
   static {&lt;br /&gt;
       for (int i=0; i&amp;lt;TAG_NAMES.length; i++) {&lt;br /&gt;
           TAG_MAP.put (TAG_NAMES[i][0],&lt;br /&gt;
                        TAG_NAMES[i][1]);&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       new AACTagReader( );&lt;br /&gt;
       System.exit(0);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public AACTagReader( ) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           QTFile f = QTFile.standardGetFilePreview (null);&lt;br /&gt;
           OpenMovieFile omf = OpenMovieFile.asRead(f);&lt;br /&gt;
           Movie movie = Movie.fromFile (omf);&lt;br /&gt;
           // get user data&lt;br /&gt;
           UserData userData = movie.getUserData( );&lt;br /&gt;
           dumpTagsFromUserData(userData);&lt;br /&gt;
       } catch (Exception e) {&lt;br /&gt;
           e.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   protected void dumpTagsFromUserData (UserData userData)&lt;br /&gt;
       throws QTException {&lt;br /&gt;
       int metaFCC = QTUtils.toOSType(&amp;quot;meta&amp;quot;);&lt;br /&gt;
       QTHandle metaHandle = userData.getData (metaFCC, 1);&lt;br /&gt;
       System.out.println (&amp;quot;Found meta&amp;quot;);&lt;br /&gt;
       byte[  ] metaBytes = metaHandle.getBytes( );&lt;br /&gt;
  &lt;br /&gt;
       // locate the &amp;quot;ilst&amp;quot; pseudo-atom, ignoring first 4 bytes&lt;br /&gt;
       int ilstFCC = QTUtils.toOSType(&amp;quot;ilst&amp;quot;);&lt;br /&gt;
       PseudoAtomPointer ilst = findPseudoAtom (metaBytes, 4, ilstFCC);&lt;br /&gt;
  &lt;br /&gt;
       // iterate over the pseudo-atoms inside the &amp;quot;ilst&amp;quot;&lt;br /&gt;
       // building lists of tags and values from which we'll&lt;br /&gt;
       // create arrays for the DefaultTableModel constructor&lt;br /&gt;
       int off = ilst.offset + 8;&lt;br /&gt;
       ArrayList foundTags = new ArrayList (TAG_NAMES.length);&lt;br /&gt;
       ArrayList foundValues = new ArrayList (TAG_NAMES.length);&lt;br /&gt;
       while (off &amp;lt; metaBytes.length) {&lt;br /&gt;
           PseudoAtomPointer atom = findPseudoAtom (metaBytes, off, -1);&lt;br /&gt;
           String tagName = (String) TAG_MAP.get (new Integer(atom.type));&lt;br /&gt;
           if (tagName != null) {&lt;br /&gt;
               // if we match a type, read everything after byte 24&lt;br /&gt;
               // which skips size, type, size, 'data', 8 junk bytes&lt;br /&gt;
               byte[  ] valueBytes = new byte [atom.atomSize - 24];&lt;br /&gt;
               System.arraycopy (metaBytes,&lt;br /&gt;
                                 atom.offset+24,&lt;br /&gt;
                                 valueBytes,&lt;br /&gt;
                                 0,&lt;br /&gt;
                                 valueBytes.length);&lt;br /&gt;
               String value = new String (valueBytes);&lt;br /&gt;
               System.out.println (tagName + &amp;quot;: &amp;quot; + value);&lt;br /&gt;
           } // if tagName != null&lt;br /&gt;
           off = atom.offset + atom.atomSize;&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   /** find the given type in the byte array, starting at&lt;br /&gt;
       the start position.  Returns the offset within the&lt;br /&gt;
       byte array that begins this pseudo-atom.  a helper method&lt;br /&gt;
       to populateFromMetaAtom( ).&lt;br /&gt;
       @param bytes byte array to search&lt;br /&gt;
       @param start offset to start at&lt;br /&gt;
       @param type type to search for.  if -1, returns first&lt;br /&gt;
       atom with a plausible size&lt;br /&gt;
    */&lt;br /&gt;
   private PseudoAtomPointer findPseudoAtom (byte[  ] bytes,&lt;br /&gt;
                                             int start,&lt;br /&gt;
                                             int type) {&lt;br /&gt;
       // read size, then type&lt;br /&gt;
       // if size is bogus, forget it, increment offset, and try again&lt;br /&gt;
       int off = start;&lt;br /&gt;
       boolean found = false;&lt;br /&gt;
       while ((! found) &amp;amp;&amp;amp;&lt;br /&gt;
              (off &amp;lt; bytes.length-8)) {&lt;br /&gt;
           // read 32 bits of atom size&lt;br /&gt;
           // use BigInteger to convert bytes to long&lt;br /&gt;
           // (instead of signed int)&lt;br /&gt;
           byte sizeBytes[  ] = new byte[4];&lt;br /&gt;
           System.arraycopy (bytes, off, sizeBytes, 0, 4);&lt;br /&gt;
           BigInteger atomSizeBI = new BigInteger (sizeBytes);&lt;br /&gt;
           long atomSize = atomSizeBI.longValue( );&lt;br /&gt;
  &lt;br /&gt;
           // don't bother if the size would take us beyond end of&lt;br /&gt;
           // array, or is impossibly small&lt;br /&gt;
           if ((atomSize &amp;gt; 7) &amp;amp;&amp;amp;&lt;br /&gt;
               (off + atomSize &amp;lt;= bytes.length)) {&lt;br /&gt;
               byte[  ] typeBytes = new byte[4];&lt;br /&gt;
               System.arraycopy (bytes, off+4, typeBytes, 0, 4);&lt;br /&gt;
               int aType = QTUtils.toOSType (new String (typeBytes));&lt;br /&gt;
  &lt;br /&gt;
               if ((type =  = aType) ||&lt;br /&gt;
                   (type =  = -1))&lt;br /&gt;
                   return new PseudoAtomPointer (off, (int) atomSize, aType);&lt;br /&gt;
               else&lt;br /&gt;
                   off += atomSize;&lt;br /&gt;
                                   &lt;br /&gt;
           } else {&lt;br /&gt;
               System.out.println (&amp;quot;bogus atom size &amp;quot; + atomSize);&lt;br /&gt;
               // well, how did this happen?  increment off and try again&lt;br /&gt;
               off++;&lt;br /&gt;
           }&lt;br /&gt;
       } // while&lt;br /&gt;
       return null;&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   /** Inner class to represent atom-like structures inside&lt;br /&gt;
       the meta atom, designed to work with the byte array &lt;br /&gt;
       of the meta atom (i.e., just wraps pointers to the &lt;br /&gt;
       beginning of the atom and its computed size and type)&lt;br /&gt;
    */&lt;br /&gt;
   class PseudoAtomPointer {&lt;br /&gt;
       int offset;&lt;br /&gt;
       int atomSize;&lt;br /&gt;
       int type;&lt;br /&gt;
       public PseudoAtomPointer (int o, int s, int t) {&lt;br /&gt;
           offset=o;&lt;br /&gt;
           atomSize=s;&lt;br /&gt;
           type=t;&lt;br /&gt;
       }&lt;br /&gt;
       &lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run with ''Toto Dies.m4p'', the output to the console looks like this:&lt;br /&gt;
&lt;br /&gt;
 cadamson% ant run-ch07-aactagreader&lt;br /&gt;
 Buildfile: build.xml&lt;br /&gt;
  &lt;br /&gt;
 run-ch07-aactagreader:&lt;br /&gt;
    [java] Found meta&lt;br /&gt;
    [java] Full Name: Toto Dies&lt;br /&gt;
    [java] Artist: Nellie McKay&lt;br /&gt;
    [java] Album: Get Away from Me&lt;br /&gt;
    [java] Created: 2004-02-10T08:00:00Z&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''The &amp;quot;album&amp;quot; and &amp;quot;created&amp;quot; data didn't appear in the earlier hexdump because in the file they occur after the cover art data, which is several kilobytes long''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The program gets the &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt;, gets its &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot; atom as a byte array, and looks for the &amp;quot;&amp;lt;tt&amp;gt;ilst&amp;lt;/tt&amp;gt;&amp;quot; pseudo-atom. If it finds one, it skips ahead 8 bytes (over &amp;quot;&amp;lt;tt&amp;gt;ilst&amp;lt;/tt&amp;gt;&amp;quot; and its size) and goes into a loop of discovering and parsing potential pseudo-atoms.&lt;br /&gt;
&lt;br /&gt;
To parse, you look at the first 4 bytes and consider whether it's a plausible size—in other words, whether it's big enough to contain data, but small enough to not run past the end of the byte array. If so, interpret the next 4 bytes as a &amp;lt;tt&amp;gt;FOUR_CHAR_CODE&amp;lt;/tt&amp;gt; type and check against the list of known metadata types. If it matches one of the known types, you've got a valid piece of metadata, which this program simply writes to standard out.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...combining this with the MP3 approach of the previous lab so that there's just one codebase? A good strategy for that would be to get the &amp;lt;tt&amp;gt;UserData&amp;lt;/tt&amp;gt; and look for a &amp;quot;&amp;lt;tt&amp;gt;meta&amp;lt;/tt&amp;gt;&amp;quot; atom. If you get one, assume you have iTunes AAC and do the previous parsing. If not, assume you have an MP3, and start asking for the various metadata types with &amp;lt;tt&amp;gt;UserData.getTextAsString( )&amp;lt;/tt&amp;gt;, as in the previous lab.&lt;br /&gt;
&lt;br /&gt;
== Providing Basic Audio Controls ==&lt;br /&gt;
&lt;br /&gt;
Most audio applications provide some basic audio controls to allow the user to customize the sound output to suit his environment. The &amp;lt;tt&amp;gt;MovieController&amp;lt;/tt&amp;gt; provides a volume control, but you can do better than that: you can control balance, bass, and treble with simple method calls.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;AudioMediaHandler&amp;lt;/tt&amp;gt; class provides the methods &amp;lt;tt&amp;gt;setBalance( )&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;setSoundBassAndTreble( )&amp;lt;/tt&amp;gt;, so it's just a matter of getting the handler object. The key is to remember that:&lt;br /&gt;
&lt;br /&gt;
* Movies have tracks.&lt;br /&gt;
* Tracks have exactly one &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; each.&lt;br /&gt;
* Each &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; has a &amp;lt;tt&amp;gt;MediaHandler&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Iterate over the movie's tracks to get each track's media and handler. To figure out whether a given track is audio, you can use a simple &amp;lt;tt&amp;gt;instanceof&amp;lt;/tt&amp;gt; to see if the handler is an &amp;lt;tt&amp;gt;AudioMediaHandler&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;setBalance( )&amp;lt;/tt&amp;gt; takes a &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt;, which ranges from &amp;lt;tt&amp;gt;-1.0&amp;lt;/tt&amp;gt; (all the way to the left) to &amp;lt;tt&amp;gt;1.0&amp;lt;/tt&amp;gt; (all the way to the right), with &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; representing equal balance.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;setSoundBassAndTreble( )&amp;lt;/tt&amp;gt; is interesting because it's officially undocumented. As it turns out, you pass in &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;s for bass and treble, where &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; is normal, &amp;lt;tt&amp;gt;-256&amp;lt;/tt&amp;gt; is minimum bass or treble, and &amp;lt;tt&amp;gt;256&amp;lt;/tt&amp;gt; is maximum.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Well, the ''native'' version is undocumented. For once, the Javadocs have the useful info''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-EX-3|Example 7-3]] provides a simple GUI to exercise these methods.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Run this example with ant run-ch07-basicaudiocontrolsplayer''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-EX-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 7-3. Providing balance, bass, and treble controls'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch07;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.std.movies.media.*;&lt;br /&gt;
 import quicktime.app.view.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
  &lt;br /&gt;
 import java.awt.*;&lt;br /&gt;
 import javax.swing.*;&lt;br /&gt;
 import javax.swing.event.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 public class BasicAudioControlsPlayer extends Frame &lt;br /&gt;
   implements ChangeListener {&lt;br /&gt;
  &lt;br /&gt;
   JSlider balanceSlider, trebleSlider, bassSlider;&lt;br /&gt;
  &lt;br /&gt;
   AudioMediaHandler audioMediaHandler;&lt;br /&gt;
  &lt;br /&gt;
   public static void main (String[  ] args) {&lt;br /&gt;
       try {&lt;br /&gt;
           QTSessionCheck.check( );&lt;br /&gt;
           Frame f= new BasicAudioControlsPlayer( );&lt;br /&gt;
           f.pack( );&lt;br /&gt;
           f.setVisible(true);&lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public BasicAudioControlsPlayer ( ) throws QTException {&lt;br /&gt;
       super (&amp;quot;Basic Audio Controls&amp;quot;);&lt;br /&gt;
       // prompt for audio file&lt;br /&gt;
       QTFile file = QTFile.standardGetFilePreview(null);&lt;br /&gt;
       OpenMovieFile omf = OpenMovieFile.asRead (file);&lt;br /&gt;
       Movie movie = Movie.fromFile (omf);&lt;br /&gt;
       MovieController controller = new MovieController (movie);&lt;br /&gt;
       // get AudioMediaHandler for first audio track&lt;br /&gt;
       for (int i=1; i&amp;lt;=movie.getTrackCount( ); i++) {&lt;br /&gt;
           Track t = movie.getTrack(i);&lt;br /&gt;
           Media m = t.getMedia( );&lt;br /&gt;
           MediaHandler mh = m.getHandler( );&lt;br /&gt;
           if (mh instanceof AudioMediaHandler) {&lt;br /&gt;
               audioMediaHandler = (AudioMediaHandler) mh;&lt;br /&gt;
               break;&lt;br /&gt;
           }&lt;br /&gt;
       }&lt;br /&gt;
       if (audioMediaHandler =  = null) {&lt;br /&gt;
           System.out.println (&amp;quot;No audio track&amp;quot;);&lt;br /&gt;
           System.exit(-1);&lt;br /&gt;
       }&lt;br /&gt;
       // add controller to GUI&lt;br /&gt;
       setLayout (new BorderLayout( ));&lt;br /&gt;
       Component comp =&lt;br /&gt;
           QTFactory.makeQTComponent(controller).asComponent( );&lt;br /&gt;
       add (comp, BorderLayout.NORTH);&lt;br /&gt;
       // build balance, treble, bass controls in a panel&lt;br /&gt;
       Panel controls = new Panel(new GridLayout (3,2));&lt;br /&gt;
       controls.add (new JLabel (&amp;quot;Balance&amp;quot;));&lt;br /&gt;
       balanceSlider = new JSlider (-1000, 1000, 0);&lt;br /&gt;
       balanceSlider.addChangeListener (this);&lt;br /&gt;
       controls.add (balanceSlider);&lt;br /&gt;
       controls.add (new JLabel (&amp;quot;Treble&amp;quot;));&lt;br /&gt;
       trebleSlider = new JSlider (-256, 256, 0);&lt;br /&gt;
       trebleSlider.addChangeListener (this);&lt;br /&gt;
       controls.add (trebleSlider);&lt;br /&gt;
       controls.add (new JLabel (&amp;quot;Bass&amp;quot;));&lt;br /&gt;
       bassSlider = new JSlider (-256, 256, 0);&lt;br /&gt;
       bassSlider.addChangeListener (this);&lt;br /&gt;
       controls.add (bassSlider);&lt;br /&gt;
       add (controls, BorderLayout.SOUTH);&lt;br /&gt;
   }&lt;br /&gt;
  &lt;br /&gt;
   public void stateChanged (ChangeEvent ev) {&lt;br /&gt;
       Object source = ev.getSource( );&lt;br /&gt;
       try {&lt;br /&gt;
           if (source =  = balanceSlider) {&lt;br /&gt;
               // balance&lt;br /&gt;
               float newBal =&lt;br /&gt;
                   (float) (balanceSlider.getValue( ) / 1000f);&lt;br /&gt;
               audioMediaHandler.setBalance (newBal);&lt;br /&gt;
           } else {&lt;br /&gt;
               // bass &amp;amp; treble&lt;br /&gt;
               audioMediaHandler.setSoundBassAndTreble (&lt;br /&gt;
                                     bassSlider.getValue( ),&lt;br /&gt;
                                     trebleSlider.getValue( ));&lt;br /&gt;
           }&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
       } catch (QTException qte) {&lt;br /&gt;
           qte.printStackTrace( );&lt;br /&gt;
       }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run, the program asks the user to select a file to play, and then shows a GUI, as seen in [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-FIG-1|Figure 7-1]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-FIG-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 7-1. Balance, treble, and bass controls'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_7_tt200.png|Balance, treble, and bass controls]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
The key to this example is the use of Swing &amp;lt;tt&amp;gt;JSlider&amp;lt;/tt&amp;gt; s, which can be configured with appropriate bounds for the features they represent. For example, the bass and treble sliders run in a &amp;lt;tt&amp;gt;-256&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;256&amp;lt;/tt&amp;gt; range, with &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; as a default:&lt;br /&gt;
&lt;br /&gt;
 trebleSlider = new JSlider (-256, 256, 0);&lt;br /&gt;
&lt;br /&gt;
The balance slider needs to pass a &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; between &amp;lt;tt&amp;gt;-1&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;1&amp;lt;/tt&amp;gt;, but &amp;lt;tt&amp;gt;JSlider&amp;lt;/tt&amp;gt;s work with &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;s, so it uses a range of &amp;lt;tt&amp;gt;-1000&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;1000&amp;lt;/tt&amp;gt;, which is scaled to an appropriate &amp;lt;tt&amp;gt;float&amp;lt;/tt&amp;gt; before calling &amp;lt;tt&amp;gt;setBalance( )&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 balanceSlider = new JSlider (-1000, 1000, 0);&lt;br /&gt;
&lt;br /&gt;
All the sliders share a &amp;lt;tt&amp;gt;ChangeListener&amp;lt;/tt&amp;gt; implementation that reads the new value from the affected &amp;lt;tt&amp;gt;JSlider&amp;lt;/tt&amp;gt; and make a corresponding call to the &amp;lt;tt&amp;gt;AudioMediaHandler&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Providing a Level Meter ==&lt;br /&gt;
&lt;br /&gt;
Many audio applications also provide a graphical &amp;quot; level meter,&amp;quot; which is an on-screen display of the loudness or softness of certain frequencies within the audio. In QuickTime Player, this is shown as a set of bars on the right side of the control bar, as seen in [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-FIG-2|Figure 7-2]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-FIG-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 7-2. Audio level meter in QuickTime Player'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_7_tt203.png|Audio level meter in QuickTime Player]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The intensity of lower frequencies, like bass, is shown in the leftmost columns, while higher frequencies are to the right.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;AudioMediaHandler&amp;lt;/tt&amp;gt; provides two key methods: &amp;lt;tt&amp;gt;setSoundEqualizerBands()&amp;lt;/tt&amp;gt; to set up monitoring and &amp;lt;tt&amp;gt;getSoundLevelMeterLevels()&amp;lt;/tt&amp;gt; to actually get the data. &amp;lt;tt&amp;gt;setSoundEqualizerBands( )&amp;lt;/tt&amp;gt; indicates which frequencies you want to monitor for your graphics display. These are passed in the form of a &amp;lt;tt&amp;gt;MediaEqSpectrumBands&amp;lt;/tt&amp;gt; object, which is built up by constructing it with the number of bands you intend to monitor, then repeatedly calling &amp;lt;tt&amp;gt;setFrequency()&amp;lt;/tt&amp;gt; to indicate which frequency a given band will monitor.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Unfortunately, most of the level-metering methods are officially undocumented''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the audio plays, you can repeatedly call &amp;lt;tt&amp;gt;getSoundLevelMeterLevels( )&amp;lt;/tt&amp;gt;, which returns an array of &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt;s representing the measured levels.&lt;br /&gt;
&lt;br /&gt;
[[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-EX-4|Example 7-4]] creates a basic audio level meter in an AWT Canvas.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Run this example with ant run-ch07-levelmeterplayer''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-EX-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 7-4. Providing an audio level meter'''&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;package com.oreilly.qtjnotebook.ch07;&lt;br /&gt;
 &lt;br /&gt;
import quicktime.*;&lt;br /&gt;
import quicktime.std.*;&lt;br /&gt;
import quicktime.std.movies.*;&lt;br /&gt;
import quicktime.std.movies.media.*;&lt;br /&gt;
import quicktime.app.view.*;&lt;br /&gt;
import quicktime.io.*;&lt;br /&gt;
 &lt;br /&gt;
import java.awt.*;&lt;br /&gt;
import java.awt.event.*;&lt;br /&gt;
import javax.swing.*;&lt;br /&gt;
 &lt;br /&gt;
import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
 &lt;br /&gt;
public class LevelMeterPlayer extends Frame { &lt;br /&gt;
 &lt;br /&gt;
  // bands used by apple sndequalizer example; equivalent to qt player's&lt;br /&gt;
  // http://developer.apple.com/samplecode/sndequalizer/sndequalizer.html&lt;br /&gt;
  int[  ] EQ_LEVELS = {&lt;br /&gt;
      200,&lt;br /&gt;
      400,&lt;br /&gt;
      800,&lt;br /&gt;
      1600,&lt;br /&gt;
      3200,&lt;br /&gt;
      6400,&lt;br /&gt;
      12800,&lt;br /&gt;
      21000&lt;br /&gt;
  };&lt;br /&gt;
  static final Dimension meterMinSize =&lt;br /&gt;
      new Dimension (300, 150);&lt;br /&gt;
  LevelMeter meter;&lt;br /&gt;
  AudioMediaHandler audioMediaHandler;&lt;br /&gt;
 &lt;br /&gt;
  public static void main (String[  ] args) {&lt;br /&gt;
      try {&lt;br /&gt;
          QTSessionCheck.check( );&lt;br /&gt;
          Frame f= new LevelMeterPlayer( );&lt;br /&gt;
          f.pack( );&lt;br /&gt;
          f.setVisible(true);&lt;br /&gt;
      } catch (QTException qte) {&lt;br /&gt;
          qte.printStackTrace( );&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  public LevelMeterPlayer ( ) throws QTException {&lt;br /&gt;
      super (&amp;quot;Basic Audio Controls&amp;quot;);&lt;br /&gt;
      // prompt for audio file&lt;br /&gt;
      QTFile file = QTFile.standardGetFilePreview(null);&lt;br /&gt;
      OpenMovieFile omf = OpenMovieFile.asRead (file);&lt;br /&gt;
      Movie movie = Movie.fromFile (omf);&lt;br /&gt;
      MovieController controller = new MovieController (movie);&lt;br /&gt;
      // get AudioMediaHandler for first audio track&lt;br /&gt;
      for (int i=1; i&amp;lt;=movie.getTrackCount( ); i++) {&lt;br /&gt;
          Track t = movie.getTrack(i);&lt;br /&gt;
          Media m = t.getMedia( );&lt;br /&gt;
          MediaHandler mh = m.getHandler( );&lt;br /&gt;
          if (mh instanceof AudioMediaHandler) {&lt;br /&gt;
              audioMediaHandler = (AudioMediaHandler) mh;&lt;br /&gt;
              break;&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
      if (audioMediaHandler =  = null) {&lt;br /&gt;
          System.out.println (&amp;quot;No audio track&amp;quot;);&lt;br /&gt;
          System.exit(-1);&lt;br /&gt;
      }&lt;br /&gt;
      // add controller to GUI&lt;br /&gt;
      setLayout (new BorderLayout( ));&lt;br /&gt;
      Component comp =&lt;br /&gt;
          QTFactory.makeQTComponent(controller).asComponent( );&lt;br /&gt;
      add (comp, BorderLayout.NORTH);&lt;br /&gt;
      // add level meter to GUI&lt;br /&gt;
      meter = new LevelMeter( );&lt;br /&gt;
      add (meter, BorderLayout.SOUTH);&lt;br /&gt;
      // set up repainting timer&lt;br /&gt;
      Timer t = new Timer (50, new ActionListener( ) {&lt;br /&gt;
              public void actionPerformed (ActionEvent ae) {&lt;br /&gt;
                  meter.repaint( );&lt;br /&gt;
              }&lt;br /&gt;
          });&lt;br /&gt;
      t.start( );&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  class LevelMeter extends Canvas {&lt;br /&gt;
      public Dimension getPreferredSize( ) { return meterMinSize; }&lt;br /&gt;
      public Dimension getMinimumSize( ) { return meterMinSize; }&lt;br /&gt;
      public LevelMeter( ) throws QTException {&lt;br /&gt;
          MediaEQSpectrumBands bands =&lt;br /&gt;
              new MediaEQSpectrumBands (EQ_LEVELS.length);&lt;br /&gt;
          for (int i=0; i&amp;lt;EQ_LEVELS.length; i++) {&lt;br /&gt;
              bands.setFrequency (i, EQ_LEVELS[i]);&lt;br /&gt;
              audioMediaHandler.setSoundEqualizerBands (bands);&lt;br /&gt;
              audioMediaHandler.setSoundLevelMeteringEnabled (true);&lt;br /&gt;
          }&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      public void paint (Graphics g) {&lt;br /&gt;
          int gHeight = this.getHeight( );&lt;br /&gt;
          int gWidth = this.getWidth( );&lt;br /&gt;
 &lt;br /&gt;
          // draw baseline&lt;br /&gt;
          g.drawLine (0, gHeight, gWidth, gHeight);&lt;br /&gt;
          try {&lt;br /&gt;
              if (audioMediaHandler != null) {&lt;br /&gt;
                  int[  ] levels =&lt;br /&gt;
                     audioMediaHandler.getSoundEqualizerBandLevels(&lt;br /&gt;
                                                  EQ_LEVELS.length);&lt;br /&gt;
                  int maxHeight = gHeight - 1;&lt;br /&gt;
                  int barWidth = gWidth / levels.length;&lt;br /&gt;
                  int segInterval = gHeight / 20;&lt;br /&gt;
                  for (int i=0; i&amp;lt;levels.length; i++) {&lt;br /&gt;
                      // calculate height of each set of boxes,&lt;br /&gt;
                      // proportional to level&lt;br /&gt;
                      float levPct = ((float)levels[i]) / 255.0f;&lt;br /&gt;
                      // math is a little weird here; y axis has 0 at top,&lt;br /&gt;
                      // but we have 0 at bottom of this graph&lt;br /&gt;
                      int barHeight = (int) (levPct * maxHeight);&lt;br /&gt;
                      // draw the bar as set of 0-20 rectangles&lt;br /&gt;
                      int barCount = 0;&lt;br /&gt;
                      for (int j=maxHeight;&lt;br /&gt;
                           j &amp;gt; (maxHeight - barHeight);&lt;br /&gt;
                           j-=segInterval) {&lt;br /&gt;
                          switch (barCount) {&lt;br /&gt;
                          case 20:&lt;br /&gt;
                          case 19: &lt;br /&gt;
                          case 18:&lt;br /&gt;
                              g.setColor (Color.red);&lt;br /&gt;
                              break;&lt;br /&gt;
                          case 17:&lt;br /&gt;
                          case 16:&lt;br /&gt;
                          case 15:&lt;br /&gt;
                              g.setColor (Color.yellow);&lt;br /&gt;
                              break;&lt;br /&gt;
                          default:&lt;br /&gt;
                              g.setColor (Color.green);&lt;br /&gt;
                          }&lt;br /&gt;
                          g.fillRect (i * barWidth,&lt;br /&gt;
                                      j - segInterval,&lt;br /&gt;
                                      barWidth - 1,&lt;br /&gt;
                                      segInterval - 1);&lt;br /&gt;
                          barCount++;&lt;br /&gt;
                      }&lt;br /&gt;
                  }&lt;br /&gt;
 &lt;br /&gt;
              }&lt;br /&gt;
          } catch (QTException qte) {&lt;br /&gt;
              qte.printStackTrace( );&lt;br /&gt;
          }&lt;br /&gt;
          &lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
  }&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run, this example provides the graphics-level display as shown in [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-FIG-3|Figure 7-3]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-FIG-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 7-3. Frequency bands displayed as a level meter'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_7_tt204.png|Frequency bands displayed as a level meter]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
This example sets up levels that, according to a demo in the native API, correspond to the same frequency bands metered by QuickTime Player:&lt;br /&gt;
&lt;br /&gt;
   int[  ] EQ_LEVELS = {&lt;br /&gt;
       200,&lt;br /&gt;
       400,&lt;br /&gt;
       800,&lt;br /&gt;
       1600,&lt;br /&gt;
       3200,&lt;br /&gt;
       6400,&lt;br /&gt;
       12800,&lt;br /&gt;
       21000&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
When the user opens a movie, the program finds the &amp;lt;tt&amp;gt;AudioMediaHandler&amp;lt;/tt&amp;gt; of the first audio track and calls &amp;lt;tt&amp;gt;setSoundEqualizerBands()&amp;lt;/tt&amp;gt; with these bands. Then it creates an instance of the &amp;lt;tt&amp;gt;LevelMeter&amp;lt;/tt&amp;gt; inner class, along with a Swing &amp;lt;tt&amp;gt;Timer&amp;lt;/tt&amp;gt; to repaint the level meter every 50 milliseconds.&lt;br /&gt;
&lt;br /&gt;
When the repaint calls the meter's &amp;lt;tt&amp;gt;paint()&amp;lt;/tt&amp;gt; method, it divides its width by the number of bands to figure out how wide each bar should be. The height takes a little more work: the returned levels are in the range &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;255&amp;lt;/tt&amp;gt;, so the program calculates a &amp;quot;level percent&amp;quot; float by dividing by &amp;lt;tt&amp;gt;255&amp;lt;/tt&amp;gt;, then multiplying this by the height of the component. With the height and width of each frequency band, the component can draw a set of boxes, up to that height, to represent the band's level.&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...the values passed in for frequencies and the number that can be passed in? Unfortunately, with no documentation for this feature, there's only trial-and-error to fall back on. One thing I've found is that you can have only 10 bands—you can pass in as many frequencies as you want, and you'll get that many back in the &amp;lt;tt&amp;gt;int&amp;lt;/tt&amp;gt; array returned by &amp;lt;tt&amp;gt;getSoundLevelMeterLevels( )&amp;lt;/tt&amp;gt;, but only the first 10 will have nonzero values.&lt;br /&gt;
&lt;br /&gt;
== Building an Audio Track from Raw Samples ==&lt;br /&gt;
&lt;br /&gt;
As I've said many times before: movies have tracks, tracks have media, media have samples. But what are these samples? In the case of sound, they indicate how much voltage should be applied to a speaker at an instant of time. By itself, a sample is meaningless, but as a speaker is repeatedly excited and relaxed, it creates waves of sound that move through the air and can be picked up by the ear.&lt;br /&gt;
&lt;br /&gt;
So, why would you want to do this? One plausible scenario is that you have code that generates this uncompressed ''pulse code modulation'' (PCM) data, like a decoder for some format that QuickTime doesn't support. By writing the raw samples to an empty movie, you can expose it to QuickTime and then play it, export it to QT-supported formats, and use other QuickTime-related functions.&lt;br /&gt;
&lt;br /&gt;
=== How do I do that? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt; inherits an &amp;lt;tt&amp;gt;addSample( )&amp;lt;/tt&amp;gt; method from the &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; class. This can be used to pack samples into a &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt;, which in turn can be added to a &amp;lt;tt&amp;gt;Track&amp;lt;/tt&amp;gt;, which then can be added to a &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
But what values do you provide to create an audible sound? The example shown in [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-EX-5|Example 7-5]] creates a ''square wave'' at a constant frequency. A square wave is one in which the voltage is either fully on or completely off. To create a 1000-hertz (Hz) tone, you write samples to alternate between full voltage and zero voltage, 1,000 times per second. [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-FIG-4|Figure 7-4]] shows a graph of sample values for the square wave.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Run this example with ant run-ch07-audiosamplebuilder''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-FIG-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 7-4. Square wave'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_7_tt206.png|Square wave]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-EX-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Example 7-5. Building audio media by adding samples'''&lt;br /&gt;
&lt;br /&gt;
 package com.oreilly.qtjnotebook.ch07;&lt;br /&gt;
  &lt;br /&gt;
 import quicktime.*;&lt;br /&gt;
 import quicktime.std.*;&lt;br /&gt;
 import quicktime.std.movies.*;&lt;br /&gt;
 import quicktime.std.movies.media.*;&lt;br /&gt;
 import quicktime.io.*;&lt;br /&gt;
 import quicktime.util.*;&lt;br /&gt;
  &lt;br /&gt;
 import com.oreilly.qtjnotebook.ch01.QTSessionCheck;&lt;br /&gt;
  &lt;br /&gt;
 public class AudioSampleBuilder extends Object {&lt;br /&gt;
  &lt;br /&gt;
 static final int SAMPLING = 44100;&lt;br /&gt;
 static final byte[  ] ONE_SECOND_SAMPLE = new byte [SAMPLING * 2];&lt;br /&gt;
 static final int FREQUENCY = 262;&lt;br /&gt;
  &lt;br /&gt;
 public static void main (String[  ] args) {&lt;br /&gt;
   try {&lt;br /&gt;
       QTSessionCheck.check( );&lt;br /&gt;
  &lt;br /&gt;
       QTFile movFile = new QTFile (new java.io.File(&amp;quot;buildaudio.mov&amp;quot;));&lt;br /&gt;
       Movie movie =&lt;br /&gt;
           Movie.createMovieFile(movFile,&lt;br /&gt;
                         StdQTConstants.kMoviePlayer,&lt;br /&gt;
                         StdQTConstants.createMovieFileDeleteCurFile |&lt;br /&gt;
                         StdQTConstants.createMovieFileDontCreateResFile);&lt;br /&gt;
       &lt;br /&gt;
       System.out.println (&amp;quot;Created Movie&amp;quot;);&lt;br /&gt;
       &lt;br /&gt;
       // create an empty audio track&lt;br /&gt;
       int timeScale = SAMPLING; // 44100 units per second&lt;br /&gt;
       Track soundTrack = movie.addTrack (0, 0, 1);&lt;br /&gt;
                                          &lt;br /&gt;
       System.out.println (&amp;quot;Added empty Track&amp;quot;);&lt;br /&gt;
       &lt;br /&gt;
       // create media for this track&lt;br /&gt;
       Media soundMedia = new SoundMedia (soundTrack,&lt;br /&gt;
                                          timeScale);&lt;br /&gt;
       System.out.println (&amp;quot;Created Media&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
       // add samples&lt;br /&gt;
       soundMedia.beginEdits( );&lt;br /&gt;
       &lt;br /&gt;
       // see native docs for other format consts&lt;br /&gt;
       int format = QTUtils.toOSType (&amp;quot;NONE&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
       SoundDescription soundDesc = new SoundDescription(format);&lt;br /&gt;
       System.out.println (&amp;quot;Created SoundDescription&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
       soundDesc.setNumberOfChannels(1);&lt;br /&gt;
       soundDesc.setSampleSize(16);&lt;br /&gt;
       soundDesc.setSampleRate(SAMPLING);&lt;br /&gt;
  &lt;br /&gt;
       for (int i=0; i&amp;lt;5; i++) {&lt;br /&gt;
           // build the one-second sample&lt;br /&gt;
           QTHandle mediaHandle =  buildOneSecondSample (i);&lt;br /&gt;
           &lt;br /&gt;
           soundMedia.addSample(mediaHandle, // QTHandleRef data,&lt;br /&gt;
                                0, // int dataOffset,&lt;br /&gt;
                                mediaHandle.getSize( ), // int dataSize,&lt;br /&gt;
                                1, // int durationPerSample,&lt;br /&gt;
                                soundDesc, // SampleDescription sampleDesc,&lt;br /&gt;
                                SAMPLING, // int numberOfSamples,&lt;br /&gt;
                                0 // int sampleFlags)&lt;br /&gt;
                                );&lt;br /&gt;
       }&lt;br /&gt;
  &lt;br /&gt;
       // finish editing and insert media into track&lt;br /&gt;
       soundMedia.endEdits( );&lt;br /&gt;
       System.out.println (&amp;quot;Ended edits&amp;quot;);&lt;br /&gt;
       soundTrack.insertMedia (0, // trackStart&lt;br /&gt;
                               0, // mediaTime&lt;br /&gt;
                               soundMedia.getDuration( ), // mediaDuration&lt;br /&gt;
                               1); // mediaRate&lt;br /&gt;
       System.out.println (&amp;quot;inserted media&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
       // save up &lt;br /&gt;
       System.out.println (&amp;quot;Saving...&amp;quot;);&lt;br /&gt;
       OpenMovieFile omf = OpenMovieFile.asWrite (movFile);&lt;br /&gt;
       movie.addResource (omf,&lt;br /&gt;
                          StdQTConstants.movieInDataForkResID,&lt;br /&gt;
                          movFile.getName( ));&lt;br /&gt;
       System.out.println (&amp;quot;Done&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
       System.exit(0);&lt;br /&gt;
  &lt;br /&gt;
   } catch (QTException qte) {&lt;br /&gt;
       qte.printStackTrace( );&lt;br /&gt;
   }&lt;br /&gt;
 } // main&lt;br /&gt;
  &lt;br /&gt;
 /** Fill ONE_SECOND_SAMPLE with two-byte samples, according&lt;br /&gt;
   to some scheme (like square wave, sine wave, etc.)&lt;br /&gt;
   then wrap with QTHandle&lt;br /&gt;
  */&lt;br /&gt;
 public static QTHandle buildOneSecondSample (int inTime)&lt;br /&gt;
   throws QTException {&lt;br /&gt;
   // convert inTime to sample count (i.e., how many samples&lt;br /&gt;
   // past 0 we are)&lt;br /&gt;
   int wavelengthInSamples = SAMPLING / FREQUENCY;&lt;br /&gt;
   int halfWavelength = wavelengthInSamples / 2;&lt;br /&gt;
   int sample = inTime * SAMPLING;&lt;br /&gt;
   for (int i=0; i&amp;lt;SAMPLING*2; i+=2) {&lt;br /&gt;
       int offset = sample % wavelengthInSamples;&lt;br /&gt;
       // square wave - bytes are either 7fff or 0000&lt;br /&gt;
       if (offset &amp;lt; halfWavelength) {&lt;br /&gt;
           ONE_SECOND_SAMPLE[i] = (byte) 0x7f;&lt;br /&gt;
           ONE_SECOND_SAMPLE[i+1] = (byte) 0xff;&lt;br /&gt;
       } else {&lt;br /&gt;
           ONE_SECOND_SAMPLE[i] = (byte) 0x00;&lt;br /&gt;
           ONE_SECOND_SAMPLE[i+1] = (byte) 0x00;&lt;br /&gt;
       }&lt;br /&gt;
       sample ++;&lt;br /&gt;
   }&lt;br /&gt;
   return new QTHandle (ONE_SECOND_SAMPLE);&lt;br /&gt;
 }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Run this example with ant-ch07-audiosamplebuilder''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When run, this creates a five-second, audio-only movie file called ''buildaudio.mov''. Open it in QuickTime Player or an equivalent (like the level meter player from the previous lab) to listen to the file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''Square waves are ''not'' easy on the ears. Turn down your speakers or headphones before you play this file''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What just happened? ===&lt;br /&gt;
&lt;br /&gt;
Two constants at the beginning define important values. &amp;lt;tt&amp;gt;SAMPLING&amp;lt;/tt&amp;gt; is the number of samples to be played every second. This example uses 44,100, which is the same as on a compact disc.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tip&amp;quot;&amp;gt;&lt;br /&gt;
'''Tip'''&lt;br /&gt;
&lt;br /&gt;
An important consideration for choosing a sampling frequency is the ''Nyquist-Shannon Sampling Theorem'' , which states that you need to sample at a rate double the highest frequency you want to capture. So, a sampling rate of 44,100 will properly reproduce frequencies less than 22,050 Hz. Given that human hearing typically ranges from 20 to 20,000 Hz, this effectively covers any humanly audible sound.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;FREQUENCY&amp;lt;/tt&amp;gt; constant is the frequency of the sound wave to be produced. This example uses &amp;lt;tt&amp;gt;262&amp;lt;/tt&amp;gt;, which is approximately middle C on a piano.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''To be more precise, middle C is approximately 261.625565 Hz''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To start writing samples, you need a &amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt; object and a place to put your data. The example does this by:&lt;br /&gt;
&lt;br /&gt;
# Creating a new &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; with &amp;lt;tt&amp;gt;createMovieFile( )&amp;lt;/tt&amp;gt; . Using this approach—instead of the no-arg &amp;lt;tt&amp;gt;Movie&amp;lt;/tt&amp;gt; constructor—has the benefit of indicating where the samples are to be stored.&lt;br /&gt;
# Adding a new track to the movie, with no size, and a volume of 1 (full volume).&lt;br /&gt;
# Creating a new &amp;lt;tt&amp;gt;SoundMedia&amp;lt;/tt&amp;gt; object. This constructor takes the track the media is associated with and a time scale for the media. In this case, 44,100 is a good choice because then each sample will correspond to one unit of the media's time scale. You could use higher values, but not lower ones, because a sample can't be expressed as less than one unit of the time scale.&lt;br /&gt;
# Calling &amp;lt;tt&amp;gt;beginEdits()&amp;lt;/tt&amp;gt; on the media to indicate that the program will be making changes to the media.&lt;br /&gt;
&lt;br /&gt;
Most of the rest of the code in the example has to do with setting up the call to &amp;lt;tt&amp;gt;addSample()&amp;lt;/tt&amp;gt; , which is somewhat tricky. The method takes seven arguments:&lt;br /&gt;
&lt;br /&gt;
* A &amp;lt;tt&amp;gt;QTHandleRef&amp;lt;/tt&amp;gt; that points to the data to be added&lt;br /&gt;
* An offset into the handle&lt;br /&gt;
* The size of the data to be inserted&lt;br /&gt;
* The &amp;lt;tt&amp;gt;durationPerSample&amp;lt;/tt&amp;gt;—how much time the sample represents, in the media's time scale&lt;br /&gt;
* A &amp;lt;tt&amp;gt;SampleDescription&amp;lt;/tt&amp;gt; to describe the data in the handle&lt;br /&gt;
* The number of samples being added with this call&lt;br /&gt;
* Behavior flags&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
''See [[QuickTime for Java: A Developer's Notebook/Playing Movies|Chapter 2]] for more on time scales''.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first thing to do is to create a &amp;lt;tt&amp;gt;SampleDescription&amp;lt;/tt&amp;gt; that can be reused on every call to &amp;lt;tt&amp;gt;addSample( )&amp;lt;/tt&amp;gt;. To do this, create a &amp;lt;tt&amp;gt;SoundDescription&amp;lt;/tt&amp;gt; object. The constructor takes a &amp;quot;format&amp;quot; &amp;lt;tt&amp;gt;FOUR_CHAR_CODE&amp;lt;/tt&amp;gt;, which for uncompressed data is &amp;quot;&amp;lt;tt&amp;gt;NONE&amp;lt;/tt&amp;gt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;tip&amp;quot;&amp;gt;&lt;br /&gt;
'''Tip'''&lt;br /&gt;
&lt;br /&gt;
Other valid formats are defined in &amp;quot;QuickTime API Reference: S0und Formats&amp;quot; on Apple's developer site.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, you customize the &amp;lt;tt&amp;gt;SampleDescription&amp;lt;/tt&amp;gt; object with some setter methods to indicate the number of channels, the size of each sample in bits, and the sampling frequency. For this example, I used one channel and 16 bits per sample. This means that when the byte array with the data is parsed, QuickTime will take the data 2 bytes at a time and assume it to be a 16-bit value. If there were two channels, there would be 4 bytes per sample: two 2-byte samples, one for each speaker.&lt;br /&gt;
&lt;br /&gt;
You might expect that you'd then simply loop through, adding one sample at a time to the &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; and creating one second of audio every 44,100 times through the loop. Although this is legal, the resulting file won't actually play. The problem is that QuickTime wants you to put audio data in larger and more manageable chunks. To quote from the native AddMediaSample docs:&lt;br /&gt;
&lt;br /&gt;
You should set the value of this parameter so that the resulting sample size represents a reasonable compromise between total data retrieval time and the overhead associated with input and output. [ . . . ] For a sound media, choose a number of samples that corresponds to between 0.5 and 1.0 seconds of sound. In general, you should not create groups of sound samples that are less than 2 KB in size or greater than 15 KB.&lt;br /&gt;
&lt;br /&gt;
So, in this example, I've created a byte array to represent one second of samples, which is filled in a method called &amp;lt;tt&amp;gt;buildOneSecondSample( )&amp;lt;/tt&amp;gt;. This method figures out where the waveform is at each sample time and writes either &amp;lt;tt&amp;gt;0x7fff&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;0x0000&amp;lt;/tt&amp;gt; to each 2-byte pair. Because the &amp;quot;&amp;lt;tt&amp;gt;NONE&amp;lt;/tt&amp;gt;&amp;quot; format assumes signed &amp;lt;tt&amp;gt;short&amp;lt;/tt&amp;gt;s, &amp;lt;tt&amp;gt;0x7fff&amp;lt;/tt&amp;gt; is the maximum, not &amp;lt;tt&amp;gt;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
With the byte array filled, you can wrap it with a &amp;lt;tt&amp;gt;QTHandle&amp;lt;/tt&amp;gt;, and you're ready to call &amp;lt;tt&amp;gt;addSample( )&amp;lt;/tt&amp;gt; . The call looks like this:&lt;br /&gt;
&lt;br /&gt;
 soundMedia.addSample(mediaHandle, // QTHandleRef data,&lt;br /&gt;
                   0, // int dataOffset,&lt;br /&gt;
                   mediaHandle.getSize( ), // int dataSize,&lt;br /&gt;
                   1, // int durationPerSample,&lt;br /&gt;
                   soundDesc, // SampleDescription sampleDesc,&lt;br /&gt;
                   SAMPLING, // int numberOfSamples,&lt;br /&gt;
                   0 // int sampleFlags)&lt;br /&gt;
                   );&lt;br /&gt;
&lt;br /&gt;
Once you're done adding samples, it's cleanup time. You use &amp;lt;tt&amp;gt;endEdits()&amp;lt;/tt&amp;gt; to tell the &amp;lt;tt&amp;gt;Media&amp;lt;/tt&amp;gt; you're done editing, then actually put the media into the track with &amp;lt;tt&amp;gt;Track.insertMedia()&amp;lt;/tt&amp;gt; , which tells the track what parts of the media object to use and where it goes relative to the track's time scale. Finally, the movie is written to disk with the curiously named &amp;lt;tt&amp;gt;Movie.addResource( )&amp;lt;/tt&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
=== What about... ===&lt;br /&gt;
&lt;br /&gt;
...some other kind of wave because hearing that square wave is really unpleasant? A sine wave offers a nicer alternative, because it is much more like a naturally occurring sound. [[QuickTime for Java: A Developer's Notebook/Audio Media#quicktimejvaadn-CHP-7-FIG-5|Figure 7-5]] shows what its waveform looks like.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;quicktimejvaadn-CHP-7-FIG-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 7-5. Sine wave'''&lt;br /&gt;
&lt;br /&gt;
[[Image:QuickTime for Java: A Developer's Notebook_I_7_tt208.png|Sine wave]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following alternate implementation of &amp;lt;tt&amp;gt;buildOneSecondSample( )&amp;lt;/tt&amp;gt; produces a sine wave—I didn't want to put it in the preceding example, which is already complicated enough without having to use ''trigonometry'', like this does:&lt;br /&gt;
&lt;br /&gt;
 public static QTHandle buildOneSecondSample (int inTime)&lt;br /&gt;
   throws QTException {&lt;br /&gt;
   // convert inTime to sample count (i.e., how many samples&lt;br /&gt;
   // past 0 we are)&lt;br /&gt;
   int wavelengthInSamples = SAMPLING / FREQUENCY;&lt;br /&gt;
   int sample = inTime * SAMPLING;&lt;br /&gt;
   double twoPi = 2 * Math.PI;&lt;br /&gt;
   double radiansPerSample = twoPi / wavelengthInSamples;&lt;br /&gt;
   // each sample should be one n/th of twoPi&lt;br /&gt;
  &lt;br /&gt;
   for (int i=0; i&amp;lt;SAMPLING*2; i+=2) {&lt;br /&gt;
       int offset = sample % wavelengthInSamples;&lt;br /&gt;
       // sine wave&lt;br /&gt;
       double angle = offset * radiansPerSample;&lt;br /&gt;
       double sine = Math.sin (angle);&lt;br /&gt;
       // sines are -1&amp;lt;x&amp;lt;1.  we want from 0 to 0x7fff&lt;br /&gt;
       double heightD = (sine + 1) * (0x7fff / 2);&lt;br /&gt;
       // cast to int and fix endianness if on little (x86, etc.)&lt;br /&gt;
       short height = (short) heightD;&lt;br /&gt;
       // pack this into array as two bytes&lt;br /&gt;
       ONE_SECOND_SAMPLE [i] = (byte) ((height &amp;amp; 0xff00) &amp;gt;&amp;gt; 8);&lt;br /&gt;
       ONE_SECOND_SAMPLE [i+1] = (byte) (height &amp;amp; 0xff);&lt;br /&gt;
       sample ++;&lt;br /&gt;
   }&lt;br /&gt;
   return new QTHandle (ONE_SECOND_SAMPLE);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
This implementation calculates the width of a wavelength in samples, then divides that into equal segments of a 2 radius for its calls to &amp;lt;tt&amp;gt;Math.sin( )&amp;lt;/tt&amp;gt; . The returned values are then translated so that instead of running from &amp;lt;tt&amp;gt;-1.0&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;1.0&amp;lt;/tt&amp;gt;, they run from &amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;0x7fff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
It's also worth noting that the middle C sine wave is pretty hard to hear over basic computer speakers. You might have better results with a frequency of 440, which is the A above middle C.&lt;/div&gt;</description>
			<pubDate>Thu, 06 Mar 2008 23:50:56 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:QuickTime_for_Java:_A_Developer%27s_Notebook/Audio_Media</comments>		</item>
	</channel>
</rss>