Before I make my comments about Silverlight 2 Beta 2, I've first had to get the darn thing working with Visual Studio 2008. Anytime I'd go to open a Silverlight project, I'd be greeted with "The project type is not supported by this installation".
Unfortunately, I was foolish enough to install the VS2008 SP1 beta/.NET 3.5 SP1 beta (largely thanks to the cool stuff mentioned at Remix) which apparently was the original cause of this problem. It wouldn't be too bad if Blend had any IntelliSense, but unfortunately the only way to develop the C# behind the SL2 project is to use VS2008.
After several uninstall/reinstalls of everything I could find relating to VS2008 (and no more reinstalls of SP1 Beta), I stumbled across Michael Sync's tips for Silverlight 2 Beta 1 Tools + VS2008. I uninstalled and reinstalled everything according to that post…but it turns out all I needed (no reinstalling required) was but one parameter while launching VS2008…
devenv.exe /resetskippkgs
Now I'm "enjoying" Silverlight 2 content again, but hopefully future versions of the SL2Chainer will fix this on install!
Update: Okay, so SL2B2 is coming out next week apparently, and it addresses at least some of the control issues! Maybe I'll get some of my wants sooner rather than later.
No, this isn't a leaked announcement of SL2B2, but things I want (need?) into Silverlight before v3. I've been playing with SL2B1 lately, and while I'd love to say it totally rocks and I'll be using it everywhere from now on…but I just can't bring myself to that level of fanboyism.
- Native WrapPanel, yes I know of the WrapPanel on CodeProject, but its not the same.
- Tile/TileBrush/Ability to tile images. I'm sure I'm not the only one who wants to use a tile background in parts of my app which can't overlay HTML.
- "BitmapEffects". While these have sort of been depreciated in WPF 3.5 in favour of PixelShaders, Silverlight doesn't have the ability to do Inner/Outer Glow, Drop Shadows, etc.
- More controls - Think of this point as <em><em'ier><EM'iest!'>! I attempted some Silverlight 1 stuff, but it was a nightmare building anything "rich" because all controls had to be built by hand. Don't get me wrong, SL2B1 has a lot more controls (and very common/useful ones at that), but there are still a fair few missing from WPF.
- Webcam support; Flash can do it, but I personally think the amount of media stuff that Silverlight can do would make it even more useful. Webcam support in Silverlight, along with additional controls like TreeView…you could replace whatever instant messenger you currently use with a completely web based/silverlight without losing any of the rich experience!
And on a more minor note (from me)…
- VS2008SP1 breaks Blend 2.5/Silverlight support? Argh!
- Perhaps less restrictive port ranges for Sockets, currently only 4502->4532 & 80 are supported. According to Robert Folkesson "the site of origin restriction will go away in future release", maybe the port restrictions will too.
- can has Silverlight for WinMo now pleeeeease?
To me, Silverlight 1 was interesting in the aiblity to deliver WMV, but failed to really get my interesting. Silverlight 1.1/2 is a lot more powerful by bringing .NET into things as well as inbuilt controls (and yes, I know a host of other things), but it still doesn't seem all there.
I can now see the obvious reason for why it was rebranded from the seemingly "good" codename of "WPF/E" (where the E stood for everywhere) - it's not WPF, its sort of a subset, but not really.
Hopefully somebody is listening..
</Rant>
Like Nero, PowerDVD is one of those applications you see bundled with nearly all (non-OEM) DVD drives these days. And again, like Nero, it has now become an obsolete application to me. And if it's not bundled with a DVD drive, it's bundled with a graphics card. Or if the motherboard has sufficient graphic prowess itself, it may even be bundled with the motherboard!
Nero's downfall was because it became too bloated. I didn't want to have to install a 1 gigabyte program to burn files to a discs or the occasional ISO, so ISORecorder and Vista's DVD burner have replaced them - free. One could argue that Nero was just trying to stay relevant by adding in features it perceived its users wanted, and I'm sure some users do make use of it, but I don't really see the need for video, audio and photo editing bundled with my CD/DVD burning software.
PowerDVD's downfall is seemingly by their own design. In the "old" PowerDVD 7 Ultra, both HD-DVD and Bluray playback is present. It works perfectly fine for my usage, except for two things.
- The first problem, it doesn't integrate into Windows Media Center, with the best way to do so is a script to launch the application when HD/BD discs are detected.
- The second is that subtitles on many of my HD-DVDs are permanently on. They're not encoded into the main stream (as I can switch between subtitle languages fine), but PowerDVD won't disable them.
So, I thought upgrading to PowerDVD 8 Ultra would be the way to go. Unfortunately Cyberlink has decided that since Toshiba has dropped HD-DVD support, they would too. PowerDVD 8 Ultra no longer plays back HD-DVD.
To paraphrase from Bender
"No HD-DVD playback? Fine. I'll go build my own HD-DVD player with blackjack and hookers. In fact, forget the HD-DVD player and the blackjack. Eh, screw the whole thing."
I'm considering building my own MCML based plugin (so it can, potentially, stream across to Media Centre Extenders), using DirectShow Graphs and AVISynth to patch it in. Initial tests are looking good, I just need to figure out MCML a bit better first ;)
During my adventures to find a replacement for WordPress, I tried out a few different blogging packages.
Please note I was trying to find blogging software with the path of least resistance. This roundup is very critical for my needs/wants. I'm know they're all fine (if you can get them to install) if you're starting a new blog, but porting from one system to another is never fun, even less so when the system has serious platform changes that include the database!
dasBlog
Installed fine, worked perfectly, uses XML instead of SQL (no dramas there), the only 'importer' for it was a BlogML importer. Fine, install BlogML exporter to Wordpress, exported fine and then….dasBlog BlogML importer failed to run.
It was pretty damn fast, I'll give it that. It comes with a fair few different themes, which is always nice, but the admin panel was certainly not overly friendly. I don't really want to write my own importer for it, so I decided not to use it.
BlogEngine.NET
Defaults to XML, but does have SQL capabilities, but failed to 'run' properly. Couldn't get it running (either errors with the Web.Config, or with the software, depending on what I changed).
Apparently BlogEngine.NET is really nice, but I didn't want to have to fight the software just so I could trial it!
Later on I decided to install it locally, to see what I could get going. It's BlogML importer did a much better job than the others (that is, it actually imported most of my blog posts and maintained most formatting) - but it still wasn't flawless. This may be because of how Wordpress exported BlogML, or the BlogML definition, I'm not sure but the problems with it are/were:
- Posts from 2006 were dropped.
- "pages" get converted to blog posts
- "attachments", that is, something I've uploaded through Wordpress or Live Writer get converted to posts (ie, title = img-2786.jpg, with no post content)
- A few blog post titles were totally fubar'd
- Because I'm now using tags rather than categories, BlogEngine didn't pick up any imported categories/tags.. argh!
SubText
Unlike the others, SubText requires a MSSQL database. After I got over modifying the ConnectionString (I guess I can't blame them for my stupidity), things appear to be good.
SubText has Import/Export to/from BlogML baked into it, which is definitely a plus. Of course, it failing to import was not exactly a good sign. I reuploaded the DLL, and it managed to process 16 of my blog posts…but still failed. Even the 16 it processed weren't of any use to me, the formatting was destroyed, and it split one post into three!
I don't even want to describe GraffitiCMS' horrible job of install instructions.
From trying all of these different projects, its hard to conclude anything but ASP.NET sucks as a blogging platform. Now, we know that ASP.NET is more than fine for any webapp, be it blog or ecommerce, but the current open source or free blog software for ASP.NET sucks. While this might be a tad unfair, there is at least one or more component in each of the four I tried that sucked all the fun out of blogging. Maybe because of my LAMP background, I just expect things to 'work' when you upload them…
I'm seriously considering writing my own (MahBlog?), but adding support for trackbacks, pingpacks, the metablog API (I suppose if it does have full metablog API/WLM support, it doesn't need to have a web interface to post…hrm…), as well as being able to import WordPress, 'clean' URL's, etc, just doesn't sound like an overly fun thing to just 'whip up'.
I had planned to migrate over to xHostSolutions as soon as possible, I just had to make sure that the migration would be transparent with WordPress acting the same on both the old and new host. Wordpress is designed to run in a LAMP environment, and it wouldn't be unreasonable to assume 90%+ of WordPress installs/users are run that way. If you want to run it on IIS, things start to go down hill quickly.
For a start, there is little/no documentation on getting "clean" url's working using Permalinks. For me, running ISAPI_REWRITE, I was able to (mostly) copy and paste the contents of my .htaccess file into the http.ini.
RewriteEngine on
RewriteBase /blog/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /blog/index.php/$1 [L]
In WordPress' configuration, I chose year/month/day/title for the Permalink type:
/index.php/%year%/%monthnum%/%day%/%postname%/
Although it has index.php in it, if you removed the index.php in a browser it worked fine. Take it out of the WordPress config? It all dies.
Oh well, that's all fixed, I better navigate around my site to make sure things work…oh…none of the "pages" (as in, what WordPress calls a page - something different from a blog post) work. The server returns
CGI Error
The specified CGI application misbehaved by not returning a complete set of HTTP headers.
I stumbled across a post on the WordPress support forums, which (apparently) has a fix for the 2.3x versions of WordPress, but not v2.5+.
Then today there comes Jeff Atwood's post today about the CPU usage of WordPress under IIS(v7, which runs PHP faster).
The conclusions I've reached are
- If I want a current version of WordPress, use a LAMP host,
- If I want to have an IIS host, use either another PHP based or ASP.NET based Blog.
I've got BlogEngine.NET (which I've been having trouble installing; their wiki has been offline for awhile too, although now seems to be online), GraffitiCMS, (and in the PHP/Perl corner) TextPattern, MovableType, ExpressionEngine to give a try I guess. Argh!
Thanks to the super reliable Dreamhost, you may have noticed I had no blog yesterday. Or email. Or Jabber. It took them over 12 hours after contact them that, yes, my site has mysteriously vanished, as have all the automagic backups.
In all fairness, you pay peanuts, you get monkeys - that sort of thing. Given DreamHost's last year has been abysmal, I can no longer 'afford' to defend them.
I've finally got the site back, so I'm backing it up like crazy and will be moving the blog to another host as soon as I can. I'm looking into VPS', spending about AUD$50/m. Any suggestions?
In the meantime while I'm hunting around for a new host (I'll have one by the 11th), I'll probably not be blogging so it is less effort to continuously backup.
Recently I've had a lot of problems with the wireless PCI card I bought (D-LINK DWA-510), and it made me reflect on many purchases I've made, which have ended up being a waste of money, troublesome or both, just so I could save a dollar or two.
Speciality store are generally more expensive, but more often than not the quality of stock or quality of service is well worth it.
One example I've used before is PCCaseGear, who specialise in PC Cases and cooling. Sure, they have other things too, but their range isn't nearly diverse in those sections as it is in their case and cooling sections. You'll also notice from time to time they don't carry a certain brand fan or case. The reason is that product probably sucks, not that they can't sell it.
(Recently loving the Noctua 92mm fan I bought from them, dropped CPU temperatures by 10->15c, while being under 20dBa)
Same goes for my favourite place to buy headphones, Headphonics. Marcus sells a huge range of headphones, for very good prices. Apart from having a generous 20-day trial of headphones, their forum's have recommendations for half a dozen price brackets - perfect for me!
(Audiotechnia ATH-AD700's are yum, but now I want a pair of Beyerdynamic DT250's!)
Back onto the trouble with the D-Link card, I'm very much regretting not spending the time to research the card, and look around for alternatives. If I had of, I would have bought from Cormain, who specialise in ADSL networking gear. They don't sell gear they can't recommend. Aaron from Cormain is very active in the Whirlpool forums, but without trying to peddle his own goods. I bought my ADSL2+ router from those guys, and I haven't regretted any part of the purchase, from delivery, price, and finally, the actual performance of the device.
(Netcomm NBPlus4W is a great router for the price!)
I know this probably sounds like a huge ad for these three stores, but it is more of a reminder to myself than to others that buying from specialty stores will always result in a better experience.
Oh, sorry, that should read 'AllowTransparency=True creates poor performance'. In WPF, if you have AllowTransparency=True (and thus WindowStyle=None) set, you're able to create non-rectangular applications as well as making use of semi-transparency. It is certainly a welcome 'feature', especially when you're trying to go along the general guidelines of WPF of bringing design back to the desktop.
Unfortunately in reality, it sucks. Using WPFPerf, the same animation (in this case, resizing of text from 16 to 24 over 0.5s) goes from ~50FPS with AllowTransparency=False to between 3 and 14FPS with it set to True. I can manipulate multiple high definition video fine, but throw in just the mere thought of transparency, and it slows to a crawl. This is extremely disappointing, as I've said the performance of WPF isn't too bad.
There is a solution however, an entirely unworkable solution! That solution is….disable hardware rendering. Yes, that's right, if you force software rendering, performance of AllowTranparency=True goes up to usable levels. It wasn't as good as hardware acceleration + AllowTransparency=False, but it never dipped below 30FPS which is more than usable.. You can do disable hardware rendering by adding a registry key (note, the page says 'Microsof' as the key, but it needs 'Microsoft'). There is meant to be a way to disable it on a per-application basis, but I can't seem to find many details apart from the one blog post that mentioned it.
Yahoo's Vista/WPF IM client has been noted to have poor performance, particularly around their emoticon selection popup. Sure enough, disabling hardware acceleration saw a large improvement to the speed which it popped up, and how smoothly the emoticons animated. Some things were slower with it disabled, but that isn't really the point. Hardware acceleration was supposed to bring an age of enhanced performance with more complex/prettier UI's!
Knowledge base article 937106 acknowledges the performance issue…for Windows XP and Server 2003. That's just great, good thing nobody would run WPF on Vista, eh? Apparently .NET 3.0 SP1, .NET 3.5 and Vista SP1 address these performance concerns, but unfortunately, my application was targeting .NET 3.5, and I already have .NET 3.0 SP1 installed.
Long story short, the idea of WPF/XAML rocks, but the odd performance of it needs to be fixed, and in the meantime much better documentation on what triggers poor hardware (or poor software) rendering performance.
Introduction
When Vista's codename was still Longhorn, there were grand plans which never eventuated such as WinFS, the global notifications system, and NGSCB, which would have all been rather significant features to the operating system. However, some of the more disappointing features that were dropped (that the general public would have noticed) were to do with the UI. Many elements of the system (such as Explorer) utilised WinFX (which became WPF) - thats right, Explorer was coded in .NET (which in itself is very interesting, such as why was it .NET? why is Vista's Explorer not .NET? What was the realistic performance of it?)
If you compare the animations between Vista's Explorer and those we're able to see in the Longhorn preview video above (and this isn't necessarily the best Longhorn preview video out there), it is easy to see that WPF is capable of some very cool thing, but again, it is disappointing to see that Microsoft isn't "dog-fooding" such capabilities (except ironically in XAML tools such as Expression Blend and Design). This is emphasised when you look at some of the new applications coming out from Microsoft, such as those under the "Live" brand. Live Photo could have very well been Phodeo, which would have actually been a great application to demonstrate some "wow" with Vista.
Now that my rant is out of the way, this CodeSnippet will be about recreating the "Music" view from Explorer in the video above (1:22 to 1:25, so not much to really go on, but enough to get something pretty). This will be done using WPF, both its 2D and 3D elements, and API calls to Windows Media Player (so, if you don't already use WMP, you'll need to add one or two items to its library otherwise you wont' see anything appear).
Download
Source
Exe
Requirements
The Interface
Because Blend is particularly good at prototyping interfaces, I started with piecing together roughly what I wanted it to look like. If you've never used Blend before, it is much like Visual Studio's visual interface editor, but with a dark (by default) theme, and somewhat more powerful for creating custom interfaces. If you are unfamiliar with Expression Blend, the included help file is actually pretty useful - its what has taught me all I know about Blend!
For the time being, lets just use a boring 2D element for the large album art view. Later on we'll replace this with a 3D object created using Zam3D, exported to XAML.
The Logic
Switching over to Visual Studio, open up the project. Since we're working with WMP's library, we need a reference to wmp.dll, its under COM under the Add Reference Dialog, Windows Media Player (make sure you select wmp.dll, not msdxm.dll). Any time we need to access WMP, don't forget to add a "Using WMPLib;"
The general idea is to let WPF's databinding power do as much work as possible, so we'll need to arrange our data in a particular way. This isn't entirely necessary to get the concept working, but in the long run its better practice and allows further flexibility in the program.

public class Albums
{
private List<String> TempAlbumList = new List<String>();
private ObservableCollection<Album> albumList;
public ObservableCollection<Album> AlbumList
{
get { return albumList; }
}
public Albums()
{
albumList = new ObservableCollection<Album>();
WindowsMediaPlayer wmp = new WindowsMediaPlayer();
IWMPPlaylist playlist = wmp.mediaCollection.getByAttribute("MediaType", "Audio");
for (int i = 0; i < playlist.count; i++)
{
IWMPMedia tempPl = playlist.get_Item(i);
String artist = tempPl.getItemInfo("AlbumArtist");
String title = tempPl.getItemInfo("Title");
String album = tempPl.getItemInfo("Album");
String sourceurl = tempPl.getItemInfo("SourceUrl");
String alba = album + artist;
if (!TempAlbumList.Contains(alba) && alba != "") {
try
{
if (artist == "")
artist = tempPl.getItemInfo("Artist");
albumList.Add(new Album(album, artist, Path.GetDirectoryName(sourceurl)));
TempAlbumList.Add(alba);
}
catch (Exception e)
{
// MessageBox.Show(e.Message + " on " + album +title + sourceurl);
}
}
for (int j = 0; j < albumList.Count; j++)
{
if (albumList[j].Title == album)
{
albumList[j].AddTrack(new Track(title, sourceurl));
break;
}
}
}
}
}
ObservableCollections are much like any other generic collections, except WPF laps these up like there is no tomorrow. ObservableCollections don't reside in System.Collections.Generic, however, they are in System.Collections.ObjectModel, so don't forget to add a using statement. The reason ObservableCollections is loved by WPF so much is because it implements INotifyCollectionChanged, which allows for dynamic binding to UI elements (such as our ListBoxes) so that when we add, remove or modify anything in our collection, the UI is updated automagically.
public class Album
{
private String title;
public String dir;
private String coverart;
private String artist;
private ObservableCollection<Track> trackList;
public Album(String title, String artist, string dir)
{
this.title = title;
this.dir = dir;
this.artist = artist;
this.coverart = GetArtwork();
trackList = new ObservableCollection<Track>();
}
public String Title
{
get { return title; }
set
{
title = value;
}
}
public String Artist
{
get { return artist; }
set
{
artist = value;
}
}
public String CoverArt
{
get { return coverart; }
set
{
coverart = value;
}
}
public void AddTrack(Track t)
{
trackList.Add(t);
}
public ObservableCollection<Track> TrackList
{
get { return trackList; }
}
private string GetArtwork()
{
string filename = null;
string[] filenames = Directory.GetFiles(this.dir, "AlbumArt*Large.jpg");
if (filenames.Length > 0)
filename = filenames[0];
else
{
FileInfo file = new FileInfo(Path.Combine(dir, "Folder.jpg"));
if (file.Exists)
{
filename = file.FullName;
}
}
return filename;
}
}
public class Track
{
public String Title;
public String path;
public Track(String title, String path)
{
this.Title = title;
this.path = path;
}
public override string ToString()
{
return Title;
}
}
If this was production code, I'd implement INotifyPropertyChanged on both the Track and Album classes, so that the UI would automatically update when changes were made to any of the properties.
Now we switch over to XAML (Window1.xaml) - this can be done via Blend or Visual Studio (or even Notepad), but I find VS a bit more powerful/useful.
<Window.Resources>
<local:Albums x:Key="Albums" />
<!-- this style makes the format gridlike rather than just a list -->
<Style x:Key="AlbumListStyle" TargetType="{x:Type ListBox}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
<!-- Change the artwork from text to actual images -->
<DataTemplate x:Key="AlbumListTemplate">
<StackPanel>
<Border Margin="10,10,10,10">
<Image Source="{Binding Path=CoverArt}" Width="50" Height="50"/>
</Border>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="TrackListTemplate">
<TextBlock Text="{Binding Path=Title}" />
</DataTemplate>
</Window.Resources>
By making local:Albums (note, to get the local prefix, add xmlns:local="clr-namespace:MediaHorn" to the Window tag) available through the Albums key, we're able to bind all our elements in XAML markup rather than in C#. In Albums constructor, it populates its albumList, because when the program launches, it immediately calls the class.
<ListBox
x:Name="lbAlbums"
Style="{StaticResource AlbumListStyle}"
ItemsSource="{Binding Source={StaticResource Albums}, Path=AlbumList}"
IsSynchronizedWithCurrentItem="True"
ItemTemplate="{DynamicResource AlbumListTemplate}"
SelectedIndex="0"
MouseDoubleClick="lbAlbums_MouseDoubleClick" />
<ListBox
x:Name="lbTracks"
DataContext="{Binding ElementName=lbAlbums, Path=Items}"
ItemsSource="{Binding Path=TrackList}"
IsSynchronizedWithCurrentItem="True"
MouseDoubleClick="lbTracks_MouseDoubleClick" />
<TextBlock
x:Name="tbTitle"
Text="{Binding Path=Title}"
DataContext="{Binding ElementName=lbAlbums, Path=Items}" />
<TextBlock
DataContext="{Binding ElementName=lbAlbums, Path=Items}"
x:Name="tbArtist"
Text="{Binding Path=Artist}"/>
<Image DataContext="{Binding ElementName=lbAlbums, Path=Items}"
Source="{Binding Path=CoverArt}" />
The Dimensions of Three
Zam3D is a pretty cool little application by Electric Rain. It won't win awards for sheer power in high end, bump mapped, megatextures; but then again…neither will WPF. If you are into higher end 3D modelling and animation, Zam3D will import from 3DS files (3D Studio Max), and Electric Rain have plugins for other 3D applications.
They've released four training/introductory videos, which are a little lengthy but are nice at getting your way around their program.
I'm not going to go into lengths about creating the 3D Model we need using Zam3D because that's an article in itself. All we want is a box primitive, resized, slightly skewed, and animated such that it does 1.25 revolutions, and then at a slower rate rotates -.25 revolutions. Switch into the advanced editor, hit 'edit mesh', select 'faces selection' mode, and select the two triangles that make up the front of the box, and apply a bitmap texture. Save, export to XAML, and we're done with Zam3D.
For simplicity sake, I cut and paste the entirety of the exported XAML file to inside the grid (below the listboxes), then moved it around in Blend.
We're almost done with our WPF 3D, but there are a few things we need to adjust. First, find the texture you applied, and rename it to "AlbumArtTextureMR2" (making sure you rename all instances of it), as well as deleting the contents of that material group. Next, any time we add our own material, you might notice it is upside down, so find the object (it will be a GeometryModel3D, the name will be something meaningful like Box01OR10GR12, and add to it:
<GeometryModel3D.Transform>
<Transform3DGroup>
<RotateTransform3D >
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="180" Axis="0 0 1"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
<ScaleTransform3D ScaleX="-1" ScaleY="1" ScaleZ="1"/>
</Transform3DGroup>
</GeometryModel3D.Transform>
The placeholder we had for the 3D element had its source databound to the selected album. Unfortunately, MaterialGroup/ImageBrushes can't be databound, so we'll need to handle that in code.
public void onSelectAlbum(Object sender, EventArgs e)
{
if (lbAlbums.SelectedIndex > 0)
{
Album temp = ((Album)lbAlbums.SelectedItem);
if (temp.CoverArt != null)
{
BitmapImage img = new BitmapImage(new Uri(temp.CoverArt, UriKind.Relative));
ImageBrush iB = new ImageBrush(img);
MaterialGroup AlbumArtMaterial = (MaterialGroup)ZAM3DViewport3D.FindResource("AlbumArtTextureMR2");
AlbumArtMaterial.Children.Clear();
AlbumArtMaterial.Children.Add(new DiffuseMaterial(iB));
}
((Storyboard)ZAM3DViewport3D.FindResource("OnLoaded")).Begin(this);
}
}
The line with the storyboard starts our animation every time a new album is selected.
Finishing Touches
To make it a proper media player/viewer, we need to actually allow audio playback. Again we can make use of WMPLib.
public void lbAlbums_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (lbAlbums.SelectedItem != null)
{
Album tempAlb = (Album)lbAlbums.SelectedItem;
IWMPPlaylist tempPL = wmp.playlistCollection.newPlaylist(tempAlb.Title);
foreach(Track t in tempAlb.TrackList)
{
tempPL.appendItem(wmp.newMedia(t.path));
}
wmp.currentPlaylist = tempPL;
}
}
private void lbTracks_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (lbTracks.SelectedItem != null)
{
wmp.URL = ((Track)lbTracks.SelectedItem).path;
}
}
These two functions provide playback for albums and individual tracks respectively. In the first function, we need to create a temporary playlist so that we can play more than one item, which is achieved through simple iteration.
In the second function, we only need to set the URL of the current file to play back a single track.
private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
switch (e.Key)
{
case System.Windows.Input.Key.MediaStop:
wmp.controls.stop();
break;
case System.Windows.Input.Key.MediaNextTrack:
if (wmp.playState == WMPPlayState.wmppsPaused)
wmp.controls.play();
wmp.controls.next();
break;
case System.Windows.Input.Key.MediaPlayPause:
if (wmp.playState == WMPPlayState.wmppsPaused || wmp.playState == WMPPlayState.wmppsStopped)
wmp.controls.play();
else
wmp.controls.pause();
break;
case System.Windows.Input.Key.MediaPreviousTrack:
wmp.controls.previous();
break;
}
}
Since we don't have any media controls, I added play/pause/skip/stop through 'media keys' on keyboards (or some laptops that have 'special' function keys). This works for that, but the only problem is that it only works when the application has focus.
Conclusion
There are still bugs in this, but remember, it is more of a 'proof of concept' application that production ready. Several of the errors are derived from the WMP library which seems to keep a hold of albums that no longer exist, and thus while processing generate a few exceptions (so I've just chucked a few try/catch blocks around the offenders).
If you would like to further extend this, I've got a couple of ideas
- Add progress bars for how far you are through the track
- Add "+" buttons to build custom playlists
- Different views (ie, video, or list, grid, text, by song name, by artist etc)
- Sorting in different views (artist, a->z, most recently played, etc)
- Implement a way to add to the WMP Library, or create your own library structure that doesn't rely on WMPLib (maybe just for 'importing' a library)
- Add "Now Playing" functionality so that it communicates with WLM
References
A little known company called Valve released "The Orange Box" to the world a little while ago, and while it unarguably is a good value buy given the average game these days, I've been a little under whelmed by the actual content. This will probably be a series of posts broken up into each game.
Half-Life 2
Half-Life (1, the original, the first) was hailed as a break through in the First Person Shooter for it having a story line, a unique concept back in those days. For those who haven't played it (I didn't play it myself until the weeks before its sequel), the story can be found easily enough by searching for it, but I'll summarise it for the lazy
You're a physicist, Gordron Freeman, incapable of speech, hygiene (you never leave that suit), or actually doing physics, set to save the world after the Black Mesa research complex goes ape after a failed portal based research experiment. Since you've looked at guns before, you instantly know how to use them with better-than-military grade precision, and you have to save the world/your own ass by escaping Black Mesa.
But wait, there is more, once you do beat the impossible odds of battling Security Guards, Military Personal and random aliens, you'll teleport yourself to their planet, and beat the shit out of them, be 'liberated' by the "G-Man", and the games over. Congratulations.
In 1998/9, sure, story telling was weak in games because the budgets weren't there to hire non-geeks (ie, those who can write coherent sentences), and don't get me wrong, the game is fairly solid in gameplay and overall presentation - I just don't get why its hailed as the best thing to come out in the history of History.
Like all quality sequels, you start off where you were in the last game, except throw that into the HL universe and you start off in the nothingness which the G-Man left us in. Oh, and it's ten to twenty years in the future - you don't find out and official sources aren't sure. Once a company finds a good formula for making games/books/movies, they tend to stick to it, and Half-Life 2 is no different. You play Gordon Freeman, you wear a special suit, you don't talk, and you have to save the world.
There are some mind boggling changes to the game though. No longer do the evil aliens hail from the terrifying floating rocks called Xen, in fact some of them are even our new allies, for our new enemy is the Combine, who were behind the original invasion as-if-you-didn't-already-guess-that; Physics can now be handled by even the lowliest of physicists thanks to the Gravity Gun; and finally, Head Crab Zombies come in many different flavours.
Don't get me wrong, HL2 had some solid gameplay to it; AI was decent, weapons varied and interesting, and it was especially beautiful when it came out. However just like it's predecessor, it was hailed for having an incredibly rich story. The game was fairly short, the stories had plot holes that you could drive a small truck through, and the ending was incredibly lame; but that was overlooked by most because you had the gravity gun where you could cut zombies up with circular saw blades.
Half-Life 2: Episode One was meant to be the first in a rapid succession of episodic content for the Half Life saga which would give shorter game play but be more regularly produced, and at a reduced cost. Given it took six years for the sequel of Half-Life, slightly more regularly produced isn't setting their standards particularly high, and with Ep1, they certainly did give the shorter game play and more regular - only totaling about two-to-four hours of gameplay, and released a year after HL2.
Half-Life 2 and Doom3 were released close together, and HL2 was hailed as being much better because it actually had environments (plural) rather than just one-super-long-dark-corridor-with-a-poor-flashlight. The majority of Ep1 is made up of areas where you have little-to-no ammo, in the dark, shooting zombies. Sounds original and awesome right?
I suppose it would be wrong of me if I failed to mention just how cinematic Ep1 was. For a large slab of the game, it was like a movie, I forgot I was simply playing a game. I'm sure many industry analysts are wondering how you can achieve such immersion. Valves answer to that question is as simple as it is elegant…give the player no ammo in a First Person Shooter, but give them a "cute" female NPC that follows them around who has unlimited ammo but simply won't share. It wasn't that I was immersed, it was that I had to watch Alyx have all the fun.
I'm not far enough in to Half-Life 2: Episode Two to critisise it to the inevitable pointless rant I'll undoubtedly have in my head, but it certainly isn't promising much. It starts off with a train crash, and all of your weapons have been vapourised, yet Alex retains hers. You've also inexplicitly developed a separate battery pack so that the flashlight and running are no longer connected.
In all fairness, the Half Life games aren't bad. That is to say, they're not terrible, but they're not awesome. They fall somewhere in between, kind of what Yahtzee said about Halo 3. The Source engine is certainly good looking, and scales well, and etcetera and so forth about their technical capabilities, but at the end of the day, we've got a overly-hyped-underdelivered-game which for some reason, gets 95% or higher in "real" reviews.
Previous Entries