Latest build (version 2.2)

This commit is contained in:
2013-11-18 20:11:53 +02:00
parent 8954fd2635
commit 9c3b53d4a6
503 changed files with 186904 additions and 1139 deletions

View File

@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Windows.Storage;
namespace DrumKit.Repository
{
class DataRepository
{
#region Properties
public AppSettings Settings { get; private set; }
public AppInstallInfo InstallInfo { get; private set; }
public ApplicationData RepositoryLocation { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Creates a new instance of drumkit.
/// </summary>
public DataRepository()
{
this.InstallInfo = null;
this.Settings = null;
this.RepositoryLocation = null;
}
#endregion
#region Initialize
/// <summary>
/// And initializes the data using that information, and sets the location.
/// Note that you cannot call this method multiple times on the same instance.
/// </summary>
/// <exception cref="InvalidOperationException if location was already set" />
public async Task Initialize(ApplicationData where)
{
// Set up location
if (this.RepositoryLocation != null)
throw new InvalidOperationException("You cannot change data repository location once set.");
this.RepositoryLocation = where;
Log.Write("[DataRepository] Location set: {0}", where.RoamingFolder.Path);
// Read installation information
this.InstallInfo = await this.ReadInstallInfo();
// Version changed, or no info (new install)?
if (this.IsFirstLaunch())
{
// Clean up any junk
await this.FactoryReset();
// Copy local assets to app data
await this.InstallAssets();
// Generate "installed.xml" file
await this.WriteInstallInfo();
}
// Load settings
this.Settings = await this.ReadSettings();
// No settings? Use default.
if (this.Settings == null)
this.Settings = new AppSettings();
}
#endregion
/// <summary>
/// Reads the install info.
/// </summary>
/// <returns>An AppInstallInfo structure, or null if file does not exist.</returns>
private async Task<AppInstallInfo> ReadInstallInfo()
{
// See if 'installed.xml' exists
var files = await this.RepositoryLocation.RoamingFolder.GetFilesAsync();
StorageFile file = files.FirstOrDefault(x => x.Name == "installed.xml");
if (file == null)
return null;
// Read info
object info = await IOHelper.DeserializeFile(file, typeof(AppInstallInfo));
return info as AppInstallInfo;
}
private async Task<AppSettings> ReadSettings()
{
// See if 'settings.xml' exists
var files = await this.RepositoryLocation.RoamingFolder.GetFilesAsync();
StorageFile file = files.FirstOrDefault(x => x.Name == "settings.xml");
if (file == null)
return null;
// Read info
object settings = await IOHelper.DeserializeFile(file, typeof(AppSettings));
return settings as AppSettings;
}
private bool IsFirstLaunch()
{
// Get current assembly information
Assembly current_asm = typeof(DataRepository).GetTypeInfo().Assembly;
int version = current_asm.GetName().Version.Major * 1000 + current_asm.GetName().Version.Minor;
// If no install info, this is probably first launch
if (this.InstallInfo == null)
{
Log.Write("[DataRepository] First launch!");
return true;
}
// Smaller version, upgrade necessary
if (this.InstallInfo.Version != version)
{
Log.Write("[DataRepository] Version upgrade ({0} => {1}).", this.InstallInfo.Version, version);
return true;
}
// Nothing new
return false;
}
/// <summary>
/// Installs the assets at first launch.
/// </summary>
private async Task InstallAssets()
{
// Read content of 'ApplicationData'
var reader = new Tarball.TarballReader();
await reader.Unpack(new Uri("ms-appx:///Assets/ApplicationData.tar"), this.RepositoryLocation.RoamingFolder);
}
/// <summary>
/// Creates the 'installed.xml' file.
/// </summary>
private async Task WriteInstallInfo()
{
// Create file
StorageFile file = await this.RepositoryLocation.RoamingFolder.CreateFileAsync("installed.xml");
// Create app info
AppInstallInfo info = new AppInstallInfo();
// Serialize info
await IOHelper.SerializeFile(file, info, typeof(AppInstallInfo));
}
/// <summary>
/// Resets to factory settings
/// </summary>
/// <returns></returns>
public async Task FactoryReset()
{
await this.RepositoryLocation.ClearAsync();
}
/// <summary>
/// Saves the current settings.
/// </summary>
public async Task WriteSettings()
{
// Get settings file
var file = await ApplicationData.Current.RoamingFolder.CreateFileAsync("settings.xml", CreationCollisionOption.ReplaceExisting);
// Serialize settings
await IOHelper.SerializeFile(file, this.Settings, typeof(AppSettings));
}
/// <summary>
/// Releases the current resources.
/// </summary>
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,322 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
namespace DrumKit.Repository
{
public class DrumkitRepository
{
#region Properties
public Dictionary<string, Drumkit> AvailableDrumKits { get; private set; }
public StorageFolder RepositoryLocation { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Creates a new instance of drumkit.
/// </summary>
public DrumkitRepository()
{
this.AvailableDrumKits = new Dictionary<string, Drumkit>();
this.RepositoryLocation = null;
}
#endregion
#region (private) AddDrumkit
/// <summary>
/// Adds a drumkit to the dictionary.
/// </summary>
/// <param name="kit">Drumkit to add</param>
/// <returns>True if item added successfully, false otherwise.</returns>
private bool AddDrumkit(Drumkit kit)
{
// If drumkit is null
if (kit == null)
return false;
// If name is unique
if (this.AvailableDrumKits.ContainsKey(kit.Name))
{
Log.Error("[DrumkitRepository] Did not add kit, name not unique: name = {0}, location = {1} ", kit.Name, kit.RootFolder.Path);
return false;
}
// Add to list
this.AvailableDrumKits.Add(kit.Name, kit);
Log.Write("[DrumkitRepository] Added kit: name = {0}, location = {1}", kit.Name, kit.RootFolder.Path);
return true;
}
#endregion
#region (private) ReadDrumkit
/// <summary>
/// Reads information about a drumkit.
/// </summary>
/// <param name="where">Where drumkit located</param>
/// <returns>Drumkit object, null if not a valid drumkit.</returns>
private async Task<Drumkit> ReadDrumkit(StorageFolder where)
{
// Get manifest file
var files = await where.GetFilesAsync();
var manifest = files.FirstOrDefault(x => x.Name == "drumkit.xml");
// No manifest? Not drumkit
if (manifest == null)
return null;
// Read drumkit object
object kitobj = await IOHelper.DeserializeFile(manifest, typeof(Drumkit));
var kit = kitobj as Drumkit;
// Set root folder if possible
if (kit != null)
kit.RootFolder = where;
// Return
return kit;
}
#endregion
#region ReadLayouts
/// <summary>
/// Reads the layouts of the specified drumkit.
/// </summary>
/// <param name="drumkit_name">Name of drumkit</param>
public async Task<DrumkitLayoutCollection> ReadLayouts(string drumkit_name)
{
Drumkit kit = null;
// Get the drumkit
if (!this.AvailableDrumKits.TryGetValue(drumkit_name, out kit))
return null;
// Get layouts file
StorageFile file = await IOHelper.GetFileRelativeAsync(kit.RootFolder, kit.LayoutFilePath);
// Read layouts
object layouts = await IOHelper.DeserializeFile(file, typeof(DrumkitLayoutCollection));
return layouts as DrumkitLayoutCollection;
}
#endregion
#region WriteLayouts
/// <summary>
/// Rewrites the layouts for the specified drumkit.
/// </summary>
/// <param name="drumkit_name">Name of drumkit.</param>
/// <param name="layouts">Layout collection to be saved.</param>
public async Task WriteLayouts(string drumkit_name, DrumkitLayoutCollection layouts)
{
Drumkit kit = null;
// Sanity check
if (layouts == null)
throw new RepositoryException("Cannot write null layout collection!");
// Get the drumkit
if (!this.AvailableDrumKits.TryGetValue(drumkit_name, out kit))
throw new RepositoryException("No such drumkit.");
// Delete old layouts file
StorageFile old = await IOHelper.GetFileRelativeAsync(kit.RootFolder, kit.LayoutFilePath);
await old.DeleteAsync();
// Create new file
StorageFile file = await IOHelper.CreateFileRelativeAsync(kit.RootFolder, kit.LayoutFilePath);
// Write
await IOHelper.SerializeFile(file, layouts, typeof(DrumkitLayoutCollection));
}
#endregion
#region ReadConfig
/// <summary>
/// Reads the configuration file for the specified drumkit.
/// </summary>
/// <param name="drumkit_name">Name of drumkit</param>
public async Task<DrumkitConfig> ReadConfig(string drumkit_name)
{
Drumkit kit = null;
// Get the drumkit
if (!this.AvailableDrumKits.TryGetValue(drumkit_name, out kit))
return null;
// Get layouts file
StorageFile file = await IOHelper.GetFileRelativeAsync(kit.RootFolder, kit.ConfigFilePath);
// Read layouts
object config = await IOHelper.DeserializeFile(file, typeof(DrumkitConfig));
return config as DrumkitConfig;
}
#endregion
#region WriteConfig
/// <summary>
/// Rewrites the configuration file for the specified drumkit.
/// </summary>
/// <param name="drumkit_name">Name of drumkit</param>
/// <param name="config">Configuration</param>
public async Task WriteConfig(string drumkit_name, DrumkitConfig config)
{
Drumkit kit = null;
// Sanity check
if (config == null)
throw new RepositoryException("Cannot write null configs!");
// Get the drumkit
if (!this.AvailableDrumKits.TryGetValue(drumkit_name, out kit))
throw new RepositoryException("No such drumkit.");
// Delete old layouts file
StorageFile old = await IOHelper.GetFileRelativeAsync(kit.RootFolder, kit.ConfigFilePath);
await old.DeleteAsync();
// Create new file
StorageFile file = await IOHelper.CreateFileRelativeAsync(kit.RootFolder, kit.ConfigFilePath);
// Write
await IOHelper.SerializeFile(file, config, typeof(DrumkitConfig));
}
#endregion
#region Initialize
/// <summary>
/// Initializes the repository set to one location.
/// Note that you cannot call this method multiple times for the same instance.
/// </summary>
/// <exception cref="InvalidOperationException if location was already set" />
public async Task Initialize(StorageFolder where)
{
// Set up location
if (this.RepositoryLocation != null)
throw new InvalidOperationException("You cannot change drumkit repository location once set.");
this.RepositoryLocation = where;
Log.Write("[DrumkitRepository] Location set: {0}", where.Path);
// Get possible drumkits
var folders = await where.GetFoldersAsync();
// Load each drumkit
foreach (var i in folders)
{
Drumkit kit = await this.ReadDrumkit(i);
// If it is a drumkit
if (kit != null)
this.AddDrumkit(kit);
}
}
#endregion
#region InstallTarball
/// <summary>
/// Adds a new drumkit to the repository.
/// The drumkit should be an uncompressed tarball file, which will be
/// unpacked to the repository's location.
/// </summary>
/// <param name="tarball">The tarball file.</param>
/// <exception cref="ArgumentException if file is not a valid drumkit." />
/// <exception cref="RepositoryException if name of drumkit is not unique." />
public async Task InstallTarball (StorageFile tarball)
{
Log.Write("[DrumkitRepository] Installing tarball: {0}", tarball.Path);
// Create destination folder
string dest_name = System.IO.Path.GetFileNameWithoutExtension(tarball.Name);
var dest = await this.RepositoryLocation.CreateFolderAsync(dest_name, CreationCollisionOption.GenerateUniqueName);
// Unpack tarball
var reader = new Tarball.TarballReader();
await reader.Unpack(tarball, dest);
// Read information
Drumkit kit = await this.ReadDrumkit(dest);
// If there was a problem
if (kit == null || !this.AddDrumkit(kit))
{
Log.Error("[DrumkitRepository] Failed to install tarball: {0}", tarball.Path);
// Cleanup
await dest.DeleteAsync(StorageDeleteOption.PermanentDelete);
// Throw exception
if (kit == null)
throw new ArgumentException("Tarball not a drumkit.");
else
throw new RepositoryException("Drumkit name not unique.");
}
}
#endregion
#region ExportTarball
/// <summary>
/// Exports a drumkit to a tarball file.
/// </summary>
/// <param name="drumkit_key">The key of the drumkit to export.</param>
/// <param name="tarball">The destination tarball file.</param>
/// <exception cref="ArgumentException">Raised if key is not valid.</exception>
/// <exception cref="ArgumentNullException">Raised if destination tarball is null.</exception>
public async Task ExportTarball(string drumkit_key, StorageFile tarball)
{
// Sanity checks
if (!AvailableDrumKits.ContainsKey(drumkit_key))
throw new ArgumentException("Invalid key!");
if (tarball == null)
throw new ArgumentNullException("Tarball cannot be null.");
// Log
Log.Write("[DrumkitRepository] Exporting drumkit \"{0}\" to tarball : {1}", drumkit_key, tarball.Path);
// Get drumkit's folder
StorageFolder folder = AvailableDrumKits[drumkit_key].RootFolder;
// Create tarball writer
Tarball.TarballWriter writer = new Tarball.TarballWriter();
writer.AddItems(await folder.GetItemsAsync());
await writer.Pack(tarball);
}
#endregion
#region Remove
/// <summary>
/// Removes a drumkit from the repository (and system)
/// </summary>
/// <param name="name">Name of drumkit</param>
/// <exception cref="ArgumentException if name does not exist." />
public async Task Remove(string name)
{
// Make sure such name exists
if (!this.AvailableDrumKits.ContainsKey(name))
throw new ArgumentException("Invalid name");
// Remove folder
if (this.AvailableDrumKits[name].RootFolder != null)
{
// Log
Log.Write("[DrumkitRepository] Removing drumkit: name = {0}, location = {1}", name, this.AvailableDrumKits[name].RootFolder.Path);
await this.AvailableDrumKits[name].RootFolder.DeleteAsync(StorageDeleteOption.PermanentDelete);
}
// Remove entry
this.AvailableDrumKits.Remove(name);
}
#endregion
/// <summary>
/// Cleans the used resources.
/// </summary>
public void Dispose()
{
this.AvailableDrumKits.Clear();
}
}
}

View File

@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
namespace DrumKit.Repository
{
public static class LogRepository
{
private static StorageFile OutputFile = null;
private static StorageFolder RootDirectory = null;
private static List<string> Buffer = new List<string>();
public static DateTime CurrentLogDate { get; private set; }
public static List<DateTime> Dates { get; private set; }
/// <summary>
/// Initializes the log repository.
/// </summary>
public static async Task Initialize(StorageFolder location)
{
// Create/open log file
CurrentLogDate = new DateTime(DateTime.Now.Ticks);
OutputFile = await location.CreateFileAsync(CurrentLogDate.Ticks.ToString() + ".log", CreationCollisionOption.OpenIfExists);
// Set root directory
RootDirectory = location;
}
/// <summary>
/// Writes a line to the log file
/// </summary>
/// <param name="text">The text to write.</param>
public static async void WriteLine(string text)
{
// Append text
if (OutputFile != null)
try {
await FileIO.AppendTextAsync(OutputFile, text + "\n");
}
catch { }
// No file? write to a temporary buffer
else Buffer.Add(text);
// Also write to console
System.Diagnostics.Debug.WriteLine(text);
}
/// <summary>
/// Reads the list of log files
/// </summary>
/// <returns></returns>
public static async Task ReadLogFiles()
{
// Make sure we have a root directory
if (RootDirectory == null)
throw new RepositoryException("No location set!");
// Get files in root directory
var files = await RootDirectory.GetFilesAsync();
// Clear old dates
Dates = new List<DateTime>();
// Get dates
long ticks;
foreach (var i in files)
{
string file_name = Path.GetFileNameWithoutExtension(i.Name);
if (long.TryParse(file_name, out ticks))
Dates.Add(new DateTime(ticks));
}
}
/// <summary>
/// Deletes all log files except the current one.
/// </summary>
/// <returns></returns>
public static async Task Clear()
{
// Make sure we have a root directory
if (RootDirectory == null)
throw new RepositoryException("No location set!");
// Get files in root directory
var files = await RootDirectory.GetFilesAsync();
// Calculate current date
string current = CurrentLogDate.Ticks.ToString() + ".log";
// Delete everything except current
foreach (var i in files)
if (i.Name != current)
await i.DeleteAsync();
}
/// <summary>
/// Reads a log file.
/// </summary>
/// <param name="time">The date and time linked to this log file.</param>
/// <returns>The list of lines for this file.</returns>
public static async Task<IList<string>> ReadLog(DateTime time)
{
// Make sure we have a root directory
if (RootDirectory == null)
throw new RepositoryException("No location set!");
// Find the file
var file = await RootDirectory.GetFileAsync(time.Ticks.ToString() + ".log");
// Return result
return await FileIO.ReadLinesAsync(file);
}
/// <summary>
/// Copies a log file to another location.
/// </summary>
/// <param name="log">Date and time for the log entry.</param>
/// <param name="dest">Destination folder</param>
public static async Task SaveAs (DateTime log, StorageFolder dest)
{
// Make sure we have a root directory
if (RootDirectory == null)
throw new RepositoryException("No location set!");
// Find the file
var file = await RootDirectory.GetFileAsync(log.Ticks.ToString() + ".log");
// Copy
await file.CopyAsync(dest);
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DrumKit.Repository
{
class RepositoryException : Exception
{
public RepositoryException() :
base() { }
public RepositoryException(string message) :
base(message) { }
public RepositoryException(string message, Exception innerException) :
base(message, innerException) { }
}
}

View File

@ -0,0 +1,131 @@
using SharpDX.XAudio2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.Storage;
using SharpDX.Multimedia;
namespace DrumKit.Repository
{
class SoundRepository
{
#region Properties
public StorageFolder RepositoryLocation { get; private set; }
public Dictionary<string, Sound> LoadedSounds { get; private set; }
#endregion
#region Constructor
/// <summary>
/// Creates a new instance of sound repository.
/// </summary>
public SoundRepository(StorageFolder where)
{
this.RepositoryLocation = null;
this.LoadedSounds = new Dictionary<string, Sound>();
this.Initialize(where);
}
#endregion
#region Initialize
/// <summary>
/// Initializes the repository set to one location.
/// </summary>
private void Initialize(StorageFolder where)
{
// Set up location
this.RepositoryLocation = where;
Log.Write("[SoundRepository] Location set: {0}", where.Path);
}
#endregion
/// <summary>
/// Loads a sound into memory.
/// </summary>
/// <param name="drumid">The id of the drum which will hold the sound.</param>
/// <param name="source">A sound source.</param>
private async Task LoadSound(string drumid, SoundSource source)
{
// Get file
StorageFile file = await IOHelper.GetFileRelativeAsync(RepositoryLocation, source.Source);
// Open file
var stream = await file.OpenReadAsync();
var iostream = stream.AsStream();
var soundStream = new SoundStream(iostream);
// Read data
var buffer = new AudioBuffer()
{
Stream = soundStream,
AudioBytes = (int)soundStream.Length,
Flags = BufferFlags.EndOfStream
};
iostream.Dispose();
// Create sound object
Sound sound = new Sound();
sound.Buffer = buffer;
sound.DecodedPacketsInfo = soundStream.DecodedPacketsInfo;
sound.WaveFormat = soundStream.Format;
// Add sound to dictionary
this.LoadedSounds.Add(String.Format("{0}#{1}", drumid, source.Intensity), sound);
}
/// <summary>
/// Loads all the sounds associated with a drum to memory.
/// </summary>
/// <param name="drum">The drum.</param>
public async Task LoadSounds(Drum drum)
{
// Load each sound
foreach (var i in drum.Sounds)
await this.LoadSound(drum.Id, i);
}
/// <summary>
/// Unloads all the sounds associated with a drum from memory.
/// </summary>
/// <param name="drum">The drum</param>
public void UnloadSounds(Drum drum)
{
// Unload each sound
foreach (var i in drum.Sounds)
{
string key = String.Format("{0}#{1}", drum.Id, i.Intensity);
if (this.LoadedSounds.ContainsKey(key))
this.LoadedSounds.Remove(key);
}
}
/// <summary>
/// Gets a loaded sound from the dictionary.
/// </summary>
/// <param name="drumid">ID of the drum.</param>
/// <param name="intensity">Sound intensity.</param>
public Sound? GetLoadedSound(string drumid, int intensity)
{
Sound sound;
string key = String.Format("{0}#{1}", drumid, intensity);
// Try to get sound
if (!this.LoadedSounds.TryGetValue(key, out sound))
return null;
// OK
return sound;
}
/// <summary>
/// Cleans the currently used resources.
/// </summary>
public void Dispose()
{
this.LoadedSounds.Clear();
}
}
}