<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
applicationComplete="init()"
verticalScrollPolicy="off"
horizontalScrollPolicy="off"
width="400"
height="530"
showFlexChrome="false"
showStatusBar="false"
viewSourceURL="srcview/index.html"
xmlns:Comp="components.*" xmlns:display="flash.display.*">
<mx:Script>
<![CDATA[
import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
import mx.events.DragEvent;
import com.ericcarlisle.PlayModes;
import com.ericcarlisle.PlayList;
import com.ericcarlisle.Utility;
import flash.desktop.NativeDragManager;
import flash.media.Sound;
import mx.controls.Alert;
import mx.controls.FileSystemList;
import mx.core.UIComponent;
import mx.events.CloseEvent;
import mx.events.FileEvent;
import mx.events.ListEvent;
private var playMode:String;
private var volume:uint;
private const panning:int = 0;
private var selectedFileCount:uint;
private var loadedFileCount:uint;
private var soundIndex:uint;
private var SoundObj:Sound;
private var Channel:SoundChannel;
private var Transform:SoundTransform;
private var thumbTimer:Timer;
private var PlayList:com.ericcarlisle.PlayList;
private var SoundFilter:FileFilter = new FileFilter("Sounds", "*.mp3;*.wav");
private var Spectrum:ByteArray;
private const VISUALIZER_HEIGHT:Number = 50;
private const VISUALIZER_COLOR:Number = 0x336699;
private var ID3:ID3Info;
private var Duration:int;
private function init():void
{
playMode = PlayModes.STOP;
selectedFileCount = 0;
loadedFileCount = 0;
soundIndex = 0;
this.height= cvsControlBar.height + cvsPlayer.height;
volume = sldrVolume.value;
Channel = new SoundChannel();
Transform = new SoundTransform(volume/100, panning);
PlayList = new com.ericcarlisle.PlayList();
dgPlaylist.dataProvider = PlayList.Sounds;
thumbTimer = new Timer(500);
thumbTimer.addEventListener(TimerEvent.TIMER, onTimerTick);
this.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onPlayerDragInto);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onPlayerDropInto);
this.addEventListener(InvokeEvent.INVOKE, onInvoke);
}
private function onInvoke(event:InvokeEvent):void
{
if (event.arguments.length > 0)
{
var file:File;
var files:Array = new Array();
for (var i:int = 0; i < event.arguments.length; i++)
{
file = new File(event.arguments[i]);
files.push(file);
}
if (PlayList.Sounds.length > 0) removeAllSounds();
loadFiles(files);
}
}
private function onFileSelect(event:FileListEvent):void
{
loadFiles(event.files);
}
private function onDirectorySelect(event:Event):void
{
var directory:File = event.target as File;
loadFiles(directory.getDirectoryListing());
}
private function loadFiles(files:Array):void
{
var file:File;
selectedFileCount = 0;
for (var i:uint = 0; i < files.length; i++)
{
file = files[i];
if (file.extension == "mp3") selectedFileCount++;
}
loadedFileCount = 0;
if (PlayList.Sounds.length == 0) playMode = PlayModes.LOADTOPLAY;
for(var j:uint = 0; j < files.length; j++)
{
file = files[j];
if (file.extension == "mp3" || file.extension == "wav")
{
var sound:Sound = new Sound(new URLRequest(file.url));
sound.addEventListener(Event.ID3,onID3);
}
}
}
private function browseForFiles():void
{
var SoundFile:File = new File();
SoundFile.browseForOpenMultiple("Open", [SoundFilter]); SoundFile.addEventListener(FileListEvent.SELECT_MULTIPLE, onFileSelect);
}
private function browseForFolder():void
{
var directory:File = File.documentsDirectory;
directory.browseForDirectory("Select Directory");
directory.addEventListener(Event.SELECT, onDirectorySelect);
}
private function onPlayerDragInto(event:Event):void
{
NativeDragManager.acceptDragDrop(this);
}
private function onPlayerDropInto(event:NativeDragEvent):void
{
if (event.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
{
var dragFiles:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
loadFiles(dragFiles);
}
}
private function loadSound():void
{
SoundObj = new Sound();
SoundObj.load(new URLRequest(PlayList.Sounds[soundIndex]["url"]));
SoundObj.addEventListener(Event.COMPLETE, onSoundLoaded);
}
private function onSoundLoaded(event:Event):void
{
var soundData:Object = PlayList.Sounds[soundIndex];
txtID3.htmlText = Utility.ReadoutHTML(soundData["title"], soundData["track"], soundData["album"], soundData["artist"], soundData["year"], soundData["duration"]);
sldrPosition.maximum = soundData["duration"];
dgPlaylist.selectedIndex = soundIndex;
if (playMode == PlayModes.LOADTOPLAY)
{
playSound();
}
else
{
playMode = PlayModes.LOADED;
}
}
public function playSound():void
{
Channel.stop();
Channel = SoundObj.play(sldrPosition.value,0,Transform);
playMode = PlayModes.PLAY;
thumbTimer.start();
btnPlay.visible = false;
btnPause.visible = true;
sldrPosition.enabled = true;
btnPlay.enabled = true;
btnStop.enabled = true;
setBackForwardButtons();
Channel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
}
private function setBackForwardButtons():void
{
if (soundIndex == PlayList.Sounds.length-1 || PlayList.Sounds.length == 0)
{
btnForward.enabled = false;
}
else
{
btnForward.enabled = true;
}
if (soundIndex == 0 || PlayList.Sounds.length == 0)
{
btnBack.enabled = false;
}
else
{
btnBack.enabled = true;
}
}
public function stopSound():void
{
Channel.stop();
thumbTimer.stop();
sldrPosition.value = 0;
playMode = PlayModes.STOP;
Visualizer.graphics.clear();
btnPlay.visible = true;
btnPause.visible = false;
}
private function pauseSound():void
{
Channel.stop();
thumbTimer.stop();
btnPlay.visible = true;
btnPause.visible = false;
}
private function changeSoundIndex(delta:int):void
{
stopSound();
playMode = PlayModes.LOADTOPLAY;
soundIndex = soundIndex + delta;
loadSound();
}
private function ChangeSoundTransform():void
{
volume = Math.round(sldrVolume.value);
Channel.soundTransform = new SoundTransform(volume/100, panning);
}
private function onSoundComplete(event:Event):void
{
stopSound();
soundIndex++;
if (soundIndex < PlayList.Sounds.length)
{
playMode = PlayModes.LOADTOPLAY;
loadSound();
}
}
private function onID3(event:Event):void
{
var sound:Sound = Sound(event.target);
ID3 = ID3Info(sound.id3);
Duration = Math.floor(sound.length);
PlayList.AddSound(ID3.songName, ID3.album, ID3.artist, ID3.track, ID3.year, ID3.genre, Duration, sound.url);
loadedFileCount++;
if (loadedFileCount == selectedFileCount * 2)
{
PlayList.Sounds.refresh();
selectedFileCount = 0;
loadedFileCount = 0;
soundIndex = 0;
if (playMode == PlayModes.LOADTOPLAY) loadSound();
}
}
private function UpdateVisualizer():void
{
Spectrum = new ByteArray();
Visualizer.graphics.clear();
SoundMixer.computeSpectrum(Spectrum,false,0);
var f:Number;
var i:int;
var ave:int;
Visualizer.graphics.lineStyle(1, VISUALIZER_COLOR,1);
Visualizer.graphics.beginFill(VISUALIZER_COLOR, 0.75);
for (i = 0; i < 512; i=i+10)
{
f = Spectrum.readFloat();
Visualizer.drawRoundRect(Math.floor(i*0.7) + 7, cvsReadout.height - 10, 4, -Math.abs(f) * (cvsReadout.height-10));
}
Visualizer.graphics.endFill();
}
private function onTimerTick(event:TimerEvent):void
{
sldrPosition.value = Math.round(Channel.position);
}
private function onEnterFrame(event:Event):void
{
if (playMode == PlayModes.PLAY)
{
UpdateVisualizer();
}
}
private function showHowlerInfo():void
{
cvsAbout.visible = true;
}
private function togglePlayList():void
{
if (this.height == cvsControlBar.height + cvsPlayer.height)
{
this.height = cvsControlBar.height + cvsPlayer.height + cvsPlaylist.height;
}
else
{
this.height = cvsControlBar.height + cvsPlayer.height;
}
}
private function onItemDoubleClick(event:ListEvent):void
{
soundIndex = event.rowIndex;
this.playMode = PlayModes.LOADTOPLAY;
thumbTimer.stop();
sldrPosition.value = 0;
loadSound();
}
private function onIOError(event:IOErrorEvent):void
{
Alert.show("File load error: " + event.text);
}
private function startMove():void
{
stage.nativeWindow.startMove();
}
private function onPlaylistDragDrop(event:DragEvent):void
{
var item:Array = event.dragSource.dataForFormat("items") as Array;
var target:DataGrid = DataGrid(event.currentTarget);
var index:int = target.calculateDropIndex(event);
PlayList.AddSoundAt(item[0].title, item[0].album, item[0].artist, item[0].track, item[0].year, item[0].genre, item[0].duration, item[0].url, index);
}
private function unloadSound():void
{
stopSound();
txtID3.text = "";
btnPlay.visible = true;
btnPause.visible = false;
btnPlay.enabled = false;
btnStop.enabled = false;
}
private function removeSound():void
{
var index:int = dgPlaylist.selectedIndex;
if (index >= 0)
{
if (index == soundIndex)
{
unloadSound();
}
PlayList.RemoveSoundAt(index);
PlayList.Sounds.refresh();
setBackForwardButtons();
}
}
private function removeAllSounds():void
{
unloadSound();
PlayList.Sounds.removeAll();
PlayList.Sounds.refresh();
setBackForwardButtons();
}
private function onKeyDown(event:KeyboardEvent):void
{
if (event.charCode.toString() == "8" || event.charCode.toString() == "127")
{
removeSound();
}
}
]]>
</mx:Script>
<mx:Style source="howler.css" />
<mx:Canvas id="cvsControlBar"
styleName="ControlBar"
mouseDown="startMove()"
width="400"
height="20"
x="0"
y="0"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:Text text="HOWLER v0.5"
styleName="Title"
selectable="false"
y="1"
x="3"/>
<mx:Button styleName="Close"
click="close()"
x="383"
y="4"/>
<mx:Button styleName="Minimize"
click="minimize()"
x="368"
y="4"/>
</mx:Canvas>
<mx:Canvas id="cvsPlayer"
styleName="Player"
horizontalScrollPolicy="off"
verticalScrollPolicy="off" y="20" width="400" x="0" height="160">
<mx:Canvas id="cvsReadout"
styleName="Readout"
width="385"
height="80"
x="8"
y="7">
<mx:Text x="2"
y="5"
id="txtID3"
color="#000000"
height="74"
fontSize="17"
fontFamily="Arial"
selectable="false"
width="383" />
<mx:UIComponent id="Visualizer"
height="65"
width="375"
x="5"
y="5"
alpha="0.25" />
</mx:Canvas>
<mx:Button id="btnBack"
styleName="Back"
x="10"
y="113"
click="changeSoundIndex(-1)"
enabled="false" />
<mx:Button id="btnStop"
styleName="Stop"
x="47"
y="113"
click="stopSound()"
enabled="false" />
<mx:Button id="btnPlay"
styleName="Play"
x="84"
y="113"
width="37"
height="30"
click="playSound()"
enabled="false" />
<mx:Button id="btnPause"
styleName="Pause"
x="84"
y="113"
width="37"
height="30"
click="pauseSound()"
visible="false" />
<mx:Button id="btnForward"
styleName="Forward"
x="121"
y="113"
click="changeSoundIndex(1)"
enabled="false" />
<mx:Button id="btnAbout"
styleName="About"
toolTip="About Howler"
x="327"
y="109"
click="showHowlerInfo()" />
<mx:Button styleName="TogglePlaylist"
x="293"
y="109"
click="togglePlayList()"
toolTip="Toggle Playlist" />
<mx:Button id="btnAddFile"
styleName="AddFile"
click="browseForFiles()"
x="222"
y="109"
width="34"
height="36"
toolTip="Add Files" />
<mx:Button id="btnAddFolder"
styleName="AddFolder"
click="browseForFolder()"
x="256"
y="109"
width="37"
height="36"
toolTip="Add Folder" />
<mx:Image x="158"
y="113"
source="@Embed('assets/Toolbar_Border.png')"/>
<mx:HSlider id="sldrPosition"
x="8"
y="92"
width="354"
minimum="0"
enabled="false"
change="playSound()"
mouseDown="thumbTimer.stop()"
mouseUp="thumbTimer.start()"
dataTipFormatFunction="Utility.FormatDuration" height="12"/>
<mx:VSlider id="sldrVolume"
x="372"
y="102"
height="50"
minimum="0"
maximum="100"
value="100"
change="ChangeSoundTransform()"
dataTipFormatFunction="Utility.FormatVolume" width="17"/>
<mx:Label x="371" y="89" text="VOL" fontSize="8" color="#FFFFFF" width="24" height="16" fontWeight="bold"/>
</mx:Canvas>
<mx:Canvas id="cvsPlaylist"
styleName="Playlist"
width="400"
height="350"
x="0"
y="179"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<mx:DataGrid x="6"
y="7"
width="388"
height="310"
id="dgPlaylist"
keyDown="onKeyDown(event)"
dragMoveEnabled="true"
doubleClickEnabled="true"
dragEnabled="true"
dropEnabled="true"
dragComplete="onPlaylistDragDrop(event)"
itemDoubleClick="onItemDoubleClick(event)">
<mx:columns>
<mx:DataGridColumn width="168" headerText="Title" dataField="title" />
<mx:DataGridColumn width="160" headerText="Album" dataField="album"/>
<mx:DataGridColumn width="60" headerText="Duration" dataField="duration" textAlign="right" itemRenderer="components.DurationFormatter"/>
</mx:columns>
</mx:DataGrid>
<mx:Button x="6"
y="323"
styleName="Remove"
width="20"
height="18"
click="removeSound()"
/>
<mx:Button x="31"
y="323"
styleName="RemoveAll"
width="47"
height="18"
click="removeAllSounds()"
/>
</mx:Canvas>
<mx:Canvas id="cvsAbout"
width="360"
height="120"
top="35"
left="20"
styleName="About"
visible="false">
<mx:Text fontWeight="bold" fontSize="14" fontFamily="Arial" text="Howler v0.5" x="0" width="360" textAlign="center" y="8"/>
<mx:Text fontSize="12" fontFamily="Arial" text="An MP3 Player for the AIR platform
(c) Copyright 2008, Eric Carlisle" y="27" x="79" width="202" height="40" textAlign="center"/>
<mx:LinkButton x="97" y="63" label="http://www.ericcarlisle.com" fontWeight="normal" fontSize="12" color="#003366" fontFamily="Arial" textAlign="center" textDecoration="underline" click="navigateToURL(new URLRequest('http://www.ericcarlisle.com'),'_blank')"/>
<mx:Button x="147" y="91" width="59" height="18" styleName="Groovy" click="cvsAbout.visible = false" />
<mx:filters>
<mx:DropShadowFilter />
</mx:filters>
</mx:Canvas>
</mx:WindowedApplication>