using System; using System.Runtime.InteropServices; using System.IO.Ports; using System.IO; using System.Management; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using iTunesLib; namespace TapApp { /// /// This is the main type for your game /// public class Game1 : Microsoft.Xna.Framework.Game { private GraphicsDeviceManager graphics; private SpriteBatch spriteBatch; private SpriteFont font; private SerialPort port; private iTunesApp itunes; private String state; private Texture2D whiteRectangle; private int barSize; private int verticleOffset; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// protected override void Initialize() { port = new SerialPort("COM6", 9600); port.Open(); itunes = new iTunesApp(); this.Window.Title = "HapTunes - Haptic Interface for iTunes"; this.Window.AllowUserResizing = true; this.Window.ClientSizeChanged += new EventHandler(Window_ClientSizeChanged); verticleOffset = this.Window.ClientBounds.Height / 2 - 50; base.Initialize(); } void Window_ClientSizeChanged(object sender, EventArgs e) { barSize = this.Window.ClientBounds.Width - 100 - (int)font.MeasureString("00:00").X; verticleOffset = this.Window.ClientBounds.Height / 2 - 50; } /// /// LoadContent will be called once per game and is the place to load /// all of your content. /// protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load("testFont"); barSize = this.Window.ClientBounds.Width - 100 - (int)font.MeasureString("00:00").X; whiteRectangle = new Texture2D(GraphicsDevice, 1, 1); whiteRectangle.SetData(new[] { Color.White }); } /// /// UnloadContent will be called once per game and is the place to unload /// all content. /// protected override void UnloadContent() { spriteBatch.Dispose(); whiteRectangle.Dispose(); } /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// /// Provides a snapshot of timing values. protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); try { // We treat the queue of waiting bytes as a queue of waiting commands while (port.BytesToRead > 0) { executeCommand(port.ReadByte()); } // set the status string switch (itunes.PlayerState) { case ITPlayerState.ITPlayerStatePlaying: state = "Playing"; break; case ITPlayerState.ITPlayerStateStopped: state = "Stopped"; break; case ITPlayerState.ITPlayerStateFastForward: state = "Fast-Forwarding"; break; case ITPlayerState.ITPlayerStateRewind: state = "Rewinding"; break; } } catch(Exception e) { this.Exit(); } base.Update(gameTime); } /// /// Execute the command associated with the passed in integer /// /// the command to execute private void executeCommand(int command) { // These numbers are decided by the arduino // any changes should also be made there too switch (command) { case 0: itunes.VisualsEnabled = !itunes.VisualsEnabled; break; case 1: if (itunes.PlayerState.Equals(ITPlayerState.ITPlayerStateRewind) || itunes.PlayerState.Equals(ITPlayerState.ITPlayerStateFastForward)) { itunes.Pause(); itunes.Play(); } else itunes.PlayPause(); break; case 2: itunes.NextTrack(); break; case 3: itunes.PreviousTrack(); break; case 4: itunes.FastForward(); break; case 5: itunes.Rewind(); break; case 6: itunes.CurrentPlaylist.Shuffle = !itunes.CurrentPlaylist.Shuffle; break; } } /// /// This is called when the game should draw itself. /// /// Provides a snapshot of timing values. protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); try { spriteBatch.Begin(); spriteBatch.DrawString(font, "iTunes State: " + state, new Vector2(50, verticleOffset), Color.Black); string duration = String.Format("{0:D2}:{1:D2}", itunes.CurrentTrack.Duration / 60, itunes.CurrentTrack.Duration % 60); string position = String.Format("{0:D2}:{1:D2}", itunes.PlayerPosition / 60, itunes.PlayerPosition % 60); int offset = barSize * itunes.PlayerPosition / itunes.CurrentTrack.Duration; spriteBatch.Draw(whiteRectangle, new Rectangle(49, verticleOffset + 34, barSize + 2, 22), Color.Black); spriteBatch.Draw(whiteRectangle, new Rectangle(50, verticleOffset + 35, barSize, 20), Color.Gray); spriteBatch.DrawString(font, duration, new Vector2(barSize + 55, verticleOffset + 30), Color.Black); spriteBatch.Draw(whiteRectangle, new Rectangle(49, verticleOffset + 34, offset + 2, 22), Color.Black); spriteBatch.Draw(whiteRectangle, new Rectangle(50, verticleOffset + 35, offset, 20), Color.Green); spriteBatch.DrawString(font, position, new Vector2(Math.Max(offset - 10, 50), verticleOffset + 32), Color.White); // the mass of try/catch blocks are because of the possibility of tracks // having unicode characters which through exceptions when being drawn. try { spriteBatch.DrawString(font, "Album: " + itunes.CurrentTrack.Album, new Vector2(50, verticleOffset + 100), Color.Black); } catch { spriteBatch.Draw(whiteRectangle, new Rectangle(50, verticleOffset + 100, this.Window.ClientBounds.Width - 50, 20), Color.CornflowerBlue); spriteBatch.DrawString(font, "Album: N/A", new Vector2(50, verticleOffset + 100), Color.Black); } try { spriteBatch.DrawString(font, "Artist: " + itunes.CurrentTrack.Artist, new Vector2(50, verticleOffset + 80), Color.Black); } catch { spriteBatch.Draw(whiteRectangle, new Rectangle(50, verticleOffset + 80, this.Window.ClientBounds.Width - 50, 20), Color.CornflowerBlue); spriteBatch.DrawString(font, "Artist: N/A", new Vector2(50, verticleOffset + 80), Color.Black); } try { spriteBatch.DrawString(font, "Track: " + itunes.CurrentTrack.Name, new Vector2(50, verticleOffset + 60), Color.Black); } catch { spriteBatch.Draw(whiteRectangle, new Rectangle(50, verticleOffset + 60, this.Window.ClientBounds.Width - 50, 20), Color.CornflowerBlue); spriteBatch.DrawString(font, "Track: N/A", new Vector2(50, verticleOffset + 60), Color.Black); } spriteBatch.End(); } catch { //ignore } base.Draw(gameTime); } } }