Wednesday, September 30, 2015

Sudoku App for Android

Today some offtopic-theme: Next to my Sudoku page I now wrote an Android app, with which the Sudokus can be solved easily and conveniently on the smartphone. I would be happy, if some checked it out, or even got interested themselves in app programming. I wrote this app in Java, about the creation of Android apps with C# I wrote an introduction on this blog.
The app can be downloaded for free via Google Play Store.

Saturday, September 19, 2015

Matlab Tutorial Part 5 - Plots

In today's post I want to give a short introduction into the creation of plots with Matlab. It will only be a short summary, for more details I refer to the documentation of Matlab.  There all kinds of plots are listed with parameters, it is explained for example how to label axis, change colors etc.
Here I want to describe 2 kinds of 2 - dimensional plots, namely line and bar plots, as well as the 3 -dimensional surface plot.
We create a line plot with the function plot(). For this we first create some test data via x = rand(8, 1), a new vector with 8 random values between 0 and 1.
Then plot(x) gives us the following result:






















bar() creates a bar chart from the given data. bar(x) looks as follows:






















Now to a 3 - dimensional plot, the surface plot. This displays (for example) an inputted 2 -dimensional matrix in the third dimension (through height and color). On the point with the coordinates (i, j) thus the (i, j)th - entry of the matrix is displayed, meaning its value is represented by the z - coordinate and additionally colored corrrespondingly.
As an example via A = rand(32) we create a random 32 x 32 matrix. surf(A) then creates the following diagram:



Friday, September 18, 2015

Matlab Tutorial Part 4 - Scripts and Functions

In Matlab we have the possibility to create scripts and functions containing often used code, helping us to not having to type it frequently.
The scripts and functions are saved in files with the ending .m. Scripts are simply collections of lines of code, whereas functions have some return value.
We can edit these files conveniently out of Matlab: For that we edit the command edit Name.m and confirm. Then an editor opens with this file.
As an example we create the script MyScript.m with the following content:

A = rand(100);
d = det(A)

So a random 100 x 100 matrix A is created and the determinant d calculated. In Matlab we can call this script by entering the name MyScript. Then the script is executed and the variable d outputted. What is outputted we can control via the character ";". If we end one line with a semicolon, it is executed without output. If we omit it, the result of the operation is outputted. So if we remove the semicolon in the first line of the script, the complete matrix is displayed as well.

As a second example we now create a function which calculates and returns the average over the given values. For this we enter edit MyFunction.m.
As content we input:

function [y] = MyFunction(x)
y = sum(x);
y = y / numel(x);
end

As one can see a function declaration starts with the keyword function and ends with end. In square brackets we first list the return values - here only y is returned, multiple parameters are simply separated by comma. After the equal sign we write the name of the function (which should coincide with the file name) as well as the input parameters in round brackets - here only x.
In the function we then sum over x (thus we expect a vector) and then divide this by the number of elements in x. The result is then returned by the function in y. In Matlab we then can call the function and use the return value as follows: test = MyFunction([1,2,3,])
(Note: In Matlab of course the average value can be calculated easier - for example via the predefined function mean(). I only chose this example for explanation.)

Thursday, September 17, 2015

Matlab Tutorial Part 3 - Solve a System of Linear Equations

In today's part I want to show how to solve a system of linear equations. A system of linear equations has the form A * x = b, where A is the matrix representing the coefficients and b the right side of the equation system. We want to solve for x.
For this we simpy have to input A and x in Matlab and then call the command

x = linsolve(A, b)

One example:
We want to solve

x1   + x2     + x3   = 5
2x1             + 3x3 = 2
          10x2 - x3    = 1

Thus in Matlab we enter the matrix of coefficients (A = [1, 1, 1; 2, 0, 3; 0, 10, -1]) as well as the vector b (b = [5;2;1]).
After entering x = linsolve(A, b) Matlab returns the correct answer

x =

   15.6250
   -0.8750
   -9.7500

Tuesday, September 15, 2015

Matlab Tutorial Part 2 - Matrices and Vectors

After I gave in the previous post a little introduction into the programming language Matlab, I want to continue with this post in that topic.
Here I want to write about the usage of matrices and vectors, for which the language is optimized and which can be used very conveniently.
A matrix is defined in square brackets, entries of one row are separated by comma, rows by semicolon, so for example: A = [1, 2; 3, 4]
Vectors of course are only special cases of matrices, namely one-dimensional ones. Thus they can be defined via V1 = [1, 2] (row vector) or V2 = [3;4] (column vector) - in the following I will only use the term matrix.
There are different predefined Matlab function for creating certain matrices: Here I want to mention ones(), zeros() and rand().
ones(a, b) creates a a x b matrix (a rows, b columns) with all entries a 1. This can also be done for higher dimensions, if only one parameter is passed over a 2-dimensional square matrix is created.
zeros() and rand() do the same, zeros() fills the resulting matrix with zeros, rand() with random entries between 0 and 1.
With matrices we can calculate as we are used to. Via +, -, * we can do matrix addition, subtraction and multiplication. * is overloaded and can also be used for a scalar multiplication between a scalar (a number) and a matrix.
In the Matlab documentation all possible functions regarding matrices are listed, like for example determining the rank (rank()) and and and.
Another intesting function when using matrices is the extraction of submatrices.
We can define a submatrix of the matrix A consisting of the rows a to b and columns c to d as follows: A(a:b, c:d)
When emitting the colon the dimension is taken completely: A(:, c:d)
Via the function sum() we thus can for example conveniently sum over the rows / colums of a matrix, for row i the command for this is: sum(A(1,:))
In the next post I will show another interesting application, there we describe the solving of equation systems.

Wednesday, September 2, 2015

Matlab Tutorial Part 1 - Introduction

After excursions into app programming for Android and internet programming with PHP I now want to extend the theme field of this blog a bit further and give an overview about the programming language Matlab. This is a commercial software by the company The MathWorks and is especially suitable for solving and visualizing mathematical problems. Matlab is very popular and used for example in the industry a lot. This is due to its simplicity, it was designed for mathematical use cases, quickly problems can be modelled and solutions tested. One tradeoff though is the performance, optimized C++ code can be faster by a factor of 50 - 100.
First Matlab has to be installed. As already mentioned the software is commercial, but luckily in many universities for example for students free. In this case Matlab can be installed from these sources. After a successfull installation and registration the program can be started, one should see roughly this picture:



In the middle window, the Command Window, we now can directly enter commands and this way execute code. Here one can grasp the simplicity of the scripting language Matlab quickly: Variables for example do not have to be defined, there are no types, numbers, matrices etc. can just be used.
Let us enter A = 1 and confirm with Enter, after that B = 2 and confirm too. In the Matlab environment now A and B are saved as the corresponding numbers, which we then can use, for example via A + B.
Just like that we can also define matrices (and thus vectors): Values in one row are separated by a comma, rows with semicolon, the whole matrix is cornered by brackets. C = [1, 2; 3, 4] defines the corresponding matrix, after pressing Enter we then also see this graphically in the output window.
With these numbers and matrices we can now operate as we are used to, try for example B * C + C to execute a scalar multiplication followed by matrix addition.
This should suffice for a first introduction, soon other posts will follow.

Thursday, August 20, 2015

Publish Posts on Blogger.com - API v3.0

In January I wrote a post about how to publish posts automatically on Blogger.com. This however used for that the API v2.0, which is now deprecated, therefore I here want to show how to do this with the current API v3.0.
Unfortunately I did not find a way (and I do not know if there is one) to really publish the posts without the user having to interact, now he has to log in in the browser and copy some code.
From a high level view the procedure in this version is as follows:
Via the Google Developer Console a new project has to be created and the Blogger API has to be enabled. Information about this step and the general usage of the API can be found here.
Then, to be able to use the API, we need to authenticate via OAuth 2.0. For this, we have to send a request to Google. We can do so by calling a specific URL in the browser, as parameters we specify amongst others the ID of our project, the scope for which we want to use the access etc. The user then logs in in the browser and a authorization code is presented. This code the program then sends via an HTTP request to Google and we now get back a token. With this we can eventually call the API and thus publish posts on Blogger. This procedure is decribed here.

After this high level overview, let us come to concrete implementation: First we create a new project in the Google Developer Console. Then we look for the API Blogger API v3 in the menu APIs and enable it.
Now, in our C# program, we first have to call an URL to do our initial request. The needed URL is https://accounts.google.com/o/oauth2/auth. One parameter we pass over is scope, which describes for which application we want to authenticate, for this we send https://www.googleapis.com/auth/blogger. The next parameter is the redirect URL (redirect_uri), which determines to where the answer is send. When setting this to urn:ietf:wg:oauth:2.0:oob the answer is shown in the opened browser. Via response_type=code we determine to get a code back. As the last parameter we set client_id to the ID of our created project in the Google Developer Console. This is NOT the Project ID which can be found on the mainpage, but to get the client id one has to navigate to APIs & auth - Credentials and then click on (if not already done) Add credentials - OAuth 2.0 client ID. Then we select Other (because we are designing a native application) and click on Create - then we get the client id.
All in all the URL to be called should look like this:

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/blogger&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=client-id


We simply use Process.Start on the URL to start the default browser with it. In this, the user is presented with a login and consent screen. If he clicks accept, a success code is presented. We copy this.
With the code, we can get an access token for using the Blogger API. For this we now have to do a HTTP Post Request. The URL to be called is https://www.googleapis.com/oauth2/v3/token, as parameters we have to send the obtained code (code), the client id (client_id), the redirect url (redirect_uri, same as before), the grant type (grant_type=authorization_code - describes how we want to authenticate) and the client secret (client_secret). The latter we can see when clicking on the client id under Credentials.
With the method HTTPPost() presented in the linked post this looks as follows:

            string Code = "code=" + Code1 + "&";
            string ID = "client_id=id&";
            string uri = "redirect_uri=urn:ietf:wg:oauth:2.0:oob&";
            string grant = "grant_type=authorization_code&";
            string secret = "client_secret=secret";

            string Code2 = HTTPPost("https://www.googleapis.com/oauth2/v3/token", Code + ID + uri + grant + secret);

We read out the answer of the server since this contains (if successful) the access token. The answer is given in the JSON format, we use the library Newtonsoft.Json to interpret this. Maybe I will write a post about the library, for now I just refer to this post where it is also used.
Thus we obtain the access token via the following code, where AccessToken is a custom class with the desired attribute:

AccessToken JsonAccToken = (AccessToken)JsonConvert.DeserializeObject(Code2, typeof(AccessToken));
string StrAccToken = JsonAccToken.access_token;
With this token we can now use the API to publish posts on Blogger. We use a WebRequest to send the correct POST request to the Blogger server. As the target adress we select https://www.googleapis.com/blogger/v3/blogs/.
First we set the correct content type, select the authentication header etc:

var http = (HttpWebRequest)WebRequest.Create(new Uri("https://www.googleapis.com/blogger/v3/blogs/" + sid + "/posts/"));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
http.Headers.Add("Authorization", "Bearer " + token);

sid is the ID of the blog to which we want to publish. Next we describe the post in JSON format, for that we first write it as a string and then convert it.
var vm = new { kind = "blogger#post", blog = new { id = sid }, title = stitle, content = scontent };
var dataString = JsonConvert.SerializeObject(vm);
string parsedContent = dataString;

In the code stitle denotes the title of the post, scontent the content (which is expected in the HTML format).
Eventually we upload this via the WebRequest.
The complete code looks as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Net;
using System.IO;
using Newtonsoft.Json;

namespace Blogger
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/blogger&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&client_id=client-id");
        }

        private string HTTPPost(string url, string postparams)
        {
            string responseString = "";

            // performs the desired http post request for the url and parameters
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            // request.CookieContainer = Cookie; // explicitely use the cookiecontainer to save the session

            string postData = postparams;
            byte[] data = Encoding.UTF8.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();

            responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            return responseString;

        }

        private void Form1_Click(object sender, EventArgs e)
        {
            string Code = "code=" + textBox1.Text + "&";
            string ID = "client_id=client-id&";
            string uri = "redirect_uri=urn:ietf:wg:oauth:2.0:oob&";
            string grant = "grant_type=authorization_code&";
            string secret = "client_secret=secret";

            string Code2 = HTTPPost("https://www.googleapis.com/oauth2/v3/token", Code + ID + uri + grant + secret);

            AccessToken JsonAccToken = (AccessToken)JsonConvert.DeserializeObject(Code2, typeof(AccessToken));
            string StrAccToken = JsonAccToken.access_token;

            JSONPublish(BlogID, "Testpost", "This is a <b>Test</b>.", StrAccToken);
        }

        private void JSONPublish(string sid, string stitle, string scontent, string token)
        {
            var http = (HttpWebRequest)WebRequest.Create(new Uri("https://www.googleapis.com/blogger/v3/blogs/" + sid + "/posts/"));
            http.Accept = "application/json";
            http.ContentType = "application/json";
            http.Method = "POST";
            http.Headers.Add("Authorization", "Bearer " + token);

            var vm = new { kind = "blogger#post", blog = new { id = sid }, title = stitle, content = scontent };
            var dataString = JsonConvert.SerializeObject(vm);
            string parsedContent = dataString;

            Byte[] bytes = Encoding.UTF8.GetBytes(parsedContent);

            Stream newStream = http.GetRequestStream();
            newStream.Write(bytes, 0, bytes.Length);
            newStream.Close();

            var response = http.GetResponse();

            var stream = response.GetResponseStream();
            var sr = new StreamReader(stream);
            var content = sr.ReadToEnd();
        }

        public class AccessToken
        {
            [JsonProperty(PropertyName = "access_token")]
            public string access_token { get; set; }
        }
    }
}

Wednesday, July 29, 2015

.Net and C# Alternative to Matlab

Note: For this post I was paid by the ILNumerics GmbH, but I was allowed and supposed to choose the content freely and express my personal opinion.

In today's post I want to present the class library ILNumerics and share my experiences with it.
ILNumerics is a class library for .Net with the aim of allowing faster and easier implementations of numerical calculations, plots etc. Of course one could do this in theory with .Net means alone, but this could turn out to be very tedious (just think of the representation of vectors, multiplying matrices etc.). With ILNumerics now a language extension very similar to Matlab is available, with which complex algorithms can be implemented efficiently. In the following I  will now, as stated, give an introduction to this topic and test the product which is subject to a charge but which I rate in total as very good.

Let us start with the installation: The library can be downloaded via the homepage. Available is only a trial version, this fact and the price is the only negative point in my opinion. The program is relatively costly, starting from 89 Euros per month, so probably not suited for the hobby user. But for universities, companies etc., here I can think of ILNumerics as a real alternative to Matlab, especially since I personally like C# and .Net a lot. A free version for students would be highly appreciated.
After the installation the trial version can be tested respectively the version activated. More information you find on the support page. On this you also find a tutorial and a more precise documentation, which also served me as a reference.

The library contains basically two components: The computation engine and the visualization engine. First I will explain the usage of the computation engine, then that of the visualization engine.

To include the computation engine easily we create a new Windows-Forms project and then click on Project - Add New Item in the menu. In the new window we select "Computing Module" and with that add a new .cs file in the form of a computing module to the project. In this already some example methods are implemented which demonstrate the usage of ILNumerics, but which can of course be deleted. We do this but leave the Main method since we want to use the computing module as entry point for the program. We have to set this in the project since also the created Form class contains a main method. We do this by selecting in the project properties the computing module as Application - Startup Object.
The code of the file Computing Module1.cs should look as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ILNumerics;
using System.IO;

namespace IlNumericsTest
{

    public class Computing_Module1 : ILMath
    {
        public static void Main(params string[] parameter)
        {
        }
    }

}

Let us start with some easy operations for acclimatization.
Matrices are managed by the ILNumerics class ILArray. With this via +, -, *, / the expected calculation operations can be executed, which are matrix addition / subtraction and element wise multiplication / division. The following code creates 3 matrices of the size 10 x 10, the first is filled with ones, the second with zeros and the third with random values between 0 and 1. Then A + C and A * (-1) is outputted in the console.

ILArray<double> A = ones(10, 10);
ILArray<double> B = zeros(10, 10);
ILArray<double> C = rand(10, 10);
Console.WriteLine(A + C);
Console.WriteLine(-A);

Now some more complex examples, I want to show some operators on graphs and networks. Who does not know graphs is referred to Wikipedia, they are an often used data structure in computer science and mathematics. The research area Web Science especially deals with the investigation and analysis of networks (like the internet), for this graphs are used to represent the data, which can
take on huge sizes. Because of the thematic relevance (for example often Matlab is used) I decided to show some examples from this area as for examle the PageRank algorithm of Google.
But first a function for reading in data:

            var file = File.ReadAllText("Graph.txt");
            ILArray AdjMatrix = csvread(file);

In the first line the file is read to a string, which is then read to a matrix via the ILNumerics function csvread(). csvread() splits the read values (for example) by commas. The input file should contain the comma separatued adjacency matrix of a graph, which contains a 1 on position i, j if the nodes i and j are connected by an edge, otherwise 0. For a graph with 4 nodes the file could look as follows:

0, 1, 0, 0
1, 0, 1, 1
0, 1, 0, 1
0, 1, 1, 0

Now we want to determine the Laplacian Matrix out of the adjacency matrix, which contains the degree of node i in the i-th diagonal entry and -1 on position i, j if the nodes i, j, are connected. For this we create a new function. Since ILNumerics puts special emphasis on performance / memory management (or has to put if it wants to handle big data), we here have to watch some things. On the one hand there is not only the presented type ILArray, but also ILInArray, ILOutArray and ILRetArray (and in general also other types than Array). For more information I point to the documentation, here, just briefly, ILInArray is for example used for input parameters, is immutable and is immediately deleted after leaving the corresponding scope (because of memory / performance reasons). Because of this we have to enclose every function in a new scope, which contains the input parameters.
The function for calculating the Laplacian looks as follows:

public static ILRetArray<double> CalcLaplacian(ILInArray<double> AdjMatrix)
{
    using (ILScope.Enter(AdjMatrix))
    {
        ILArray<double> Degrees = sum(AdjMatrix);
        ILArray<double> LaplacianMatrix = Degrees * eye(AdjMatrix.Length, AdjMatrix.Length);
        LaplacianMatrix = LaplacianMatrix - AdjMatrix;
        return LaplacianMatrix;
    }
}

Input parameter is the adjacency matrix. In the first line in the scope the degree of the nodes is calculated, which is done via the function sum(). This sums over all columns of the matrix and then outputs a vector with the result, which equals exactly the sequence of degrees. eye() creates a matrix with ones in the diagonal, multiplying the degree vector and substracting it from the adjacency matrix gives us the desired matrix.

As a next example we calculate the density of a network. This is an important measure in networks, it is calcualted by dividing the number of present edges by the number of possible edges and thus points out how dense and centralized a network is. With a double summation over the matrix dimensions the density can simply be calculated:

public static ILRetArray<double> CalcDensity(ILInArray<double> AdjMatrix)
{
    using (ILScope.Enter(AdjMatrix))
    {
        ILArray<double> NrLinks = sum(sum(AdjMatrix));
        return (double)NrLinks / (AdjMatrix.Length * (AdjMatrix.Length - 1));
    }
}

Now to an algorithm, which made its inventors rich and world famous, but is in principal so easy that we implement it now here (in principal - of course there is much more to it than just these lines of code). I am talking about Google's Pagerank algorithm, which was for a long time the basis of the ranking of websites in the Google search. The algorithm assigns to every page a pagerank (a populariy), which is made up of the pageranks of the pages linking to this page. The formula for calculating it is explained in the linked Wikipedia article, in practise though the pagerank is approximated iteratively: Start with an arbitrary pagerank vector P, then the new pagerank is calculated by P = (1 - d) * e * A'T*P. Here d is a damping factor (e.g. 0.5), e is the unity vector and A' the matrix which results of the adjacency matrix A by substituting all rows with only zeros by rows with the entries 1/n (n = number of nodes). We repeat this until old and new pagerank are sufficiently close, that means the procedure does not change much any more with the next iterations. In ILNumerics this looks as follows:

        public static ILRetArray<double> CalcPageRank(ILArray<double> AdjMatrix)
        {
            using (ILScope.Enter(AdjMatrix))
            {
                ILArray<double> Degrees = sum(AdjMatrix.T);
                double epsilon = 0.00001;
                double d = 0.5;
                for (int i = 0; i < AdjMatrix.Length; i++)
                {
                    for (int j = 0; j < AdjMatrix.Length; j++)
                    {
                        if (Degrees[i] != 0)
                            AdjMatrix[i, j] /= Degrees[i];
                    }
                    if (AdjMatrix["0", ":"].Equals(zeros(1, AdjMatrix.Length)))
                        AdjMatrix["0", ":"] = ones(AdjMatrix.Length) / AdjMatrix.Length;
                }
                ILArray<double> POld = zeros(AdjMatrix.Length);
                ILArray<double> PNew = ones(AdjMatrix.Length);

                do
                {
                    POld = PNew;
                    PNew = (1 - d) * ones(AdjMatrix.Length) + d * multiply(AdjMatrix.T, POld);
                }
                while (norm(POld - PNew, 1) > epsilon);

                return PNew;
            }
        }

So with the previously described method first the adjacency matrix of an arbitrary graph has to be read, the function then calculates for every node in the graph the Pagerank and returns the vector of Pageranks. As one can see, also the selection of submatrices is possible like in Matlab. Matrix["a:b", "c:d"] chooses the submatrix which consists of the rows a - b and the columns c - d of Matrix.

But, like this the Pagerank should not be implemented in ILNumerics. I simply wrote the code in this style first to give an intuitive introduction, and then show how to better use the possibilites of ILNumerics.
In general the usage of custom ILNumerics functions is recommended over the usage of self made ones, like looping with for - loops over big matrices etc. Thus we use the type ILLogical instead of looping over the matrix and testing the rows for 0. This gives us a vector which describes which elements from some given vector fulfill a certain condition. We choose as a condition Degrees = 0, then select the submatrix with the corresponding rows and replace them by 1/n. We do the same to divide entries of nodes with degree unequal to zero by n. Further we pull unneccessary calculation operations out of the loop, like generating a vector of ones and transposing the matrix. The resulting code is much more simpler and quicker and looks as follows:

        public static ILRetArray<double> CalcPageRank(ILArray<double> AdjMatrix)
        {
            using (ILScope.Enter(AdjMatrix))
            {
                ILArray<double> Degrees = sum(AdjMatrix, 1);
                double epsilon = 0.00001;
                double d = 0.5;

                ILLogical dummy = Degrees == 0;

                AdjMatrix[dummy, full] = 1.0 / AdjMatrix.Length;
                dummy = Degrees != 0;

                AdjMatrix[dummy, full] = AdjMatrix[dummy, full] / Degrees[dummy];
                AdjMatrix = AdjMatrix.T;

                ILArray<double> POld = zeros(AdjMatrix.Length);
                ILArray<double> PNew = ones(AdjMatrix.Length);
                ILArray<double> ILOnes = (1.0 - d) * ones(AdjMatrix.Length);

                do
                {
                    POld = PNew;
                    PNew = ILOnes + d * multiply(AdjMatrix, POld);
                }
                while (norm(POld - PNew, 1) > epsilon);

                return PNew;
            }
        }

This algorithm implemented in Matlab takes about 5s for a graph of size 20 MB (about 3000 nodes), in ILNumerics as well. Such short running times of course do not give a reliable performance measure, but I think the two tools prove to be comparable. According to the producers ILNumerics has a somewhat bigger overhead, but is supposed to be faster for longer running times.

To conclude the topic about the computation engine here an example of how to solve a linear equation system:

            ILArray<double> A = ILMath.zeros(3, 3);
            A["0;:"] = new double[] { 1, 2, 1 };
            A["1;:"] = new double[] { 3, 4, 0 };
            A["2;:"] = new double[] { -1, 0, 1 };

            ILArray<double> B = new double[] { 5, 4, 7};

            ILArray<double> x = ILMath.linsolve(A, B);

Let us come to the visualization engine. For this there are of course many many possibilities and settings to create the desired plots, therefore I will here just give a brief introduction and point out to the online documentation for the rest.
As also for the computation engine we here follow the quick start guide and create a new Windows-Form project. Then we add via Project - Add New Item a new Plotting form. In the file Program.cs we change the line Application.Run(new Form1()); to Application.Run(new Plotting_Form1()); to tell the program to start with the plotting form.
This already contains example plots, but we first delete the code to create a new plot from scratch. The plotting form provides a control named ilPanel1, in its Load() function we create a simple line plot with 6 points when starting the form:

        private void ilPanel1_Load(object sender, EventArgs e)
        {
            var scene = new ILScene();
            // create some data

            ILArray<float> A = new float[] { 1, 2, 3, 4, -1, -2 };
            // add a plot cube
            scene.Add(new ILPlotCube {
  new ILLinePlot(A)
});
            ilPanel1.Scene = scene;
        }

Basic components are so called scenes. We here create a new one and add to this then a new lineplot with the given data. The result looks as follows:


By default the plotting area can be moved, rescaled etc. For this it has to be redrawn.









This shall already be enough, here some interesting plots of the homepage which also can be implemented quickly:



As a conclusion I can once again say that I see as a negative point the price, but that I otherwise liked the product a lot. It provides a fast and easy to use calculation and visualization toolkit and I am also convinced of the performance of the code. In ILNumerics see a real alternative to Matlab and would be happy to see it being used more often.

Saturday, July 18, 2015

Play Guitar Tabs with C#

In this post I want to show how one can read in guitar tabs and thus can automatically play songs with C# and the MIDI format. So called tabs are a popular and easy variant to notate songs. In the textformat simply the 6 guitar strings are represented by ---, on positions, where the strings have to be played a number is displayed which describes in which fret the string should be touched. This way a song can be represented pretty well, the tones definitely all can be described, only the tone duration cannot be represented, but often "-" between the numbers denote pauses. Since nearly all songs are (freely) available in this format I wrote a little program which reads in the tabs and then plays the interpreted song with the techniques from the previous posts.
First the function ReadTab() is called with an URL, its sourcecode is then downloaded with a Webclient. If 6 successive lines contain at least 3 "-", we interpret these lines as tabs and save then, eventually to a file (one line per guitar string).
Then the function ReadSong() is called. In this the file is read, the 6 lines are read simultaneously. For every point in time a pause is added if on no string a note is played, or a list with all played notes. For this we calculate the number of the to the tone corresponding piano key. We do this by starting from the enumeration Tone, which saves the to the 6 strings belonging keys, and add to this the number of half tones (keys), by which the string tone has to be incremented.
Finally we pass this list of lists of key numbers to the function Play(). It runs through all points in time and either plays the list of tones simultaneously or a break, as described in the previous post.

The code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO;
using Midi;
using System.Threading;

namespace TabReader
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ReadTab("http://tabs.ultimate-guitar.com/m/metallica/master_of_puppets_tab.htm");    
        }

        int NoteDuration = 70;

        protected enum Tone
        {
            E2 = 20,
            A = 25,
            D = 30,
            G = 35,
            B = 39,
            E4 = 44,
        }

        public void ReadTab(string url)
        {
            System.Net.WebClient wc = new System.Net.WebClient();
            string HTML = wc.DownloadString(url);
            string[] Lines = HTML.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
            string[] Tabs = new string[6];

            for (int i = 0; i < Lines.Length - 6; i++)
            {
                bool Found = true;
                for (int j = 0; j < 6; j++)
                {
                    if (Lines[i + j].Count(f => f == '-') <= 3)
                    {
                        Found = false;
                        break;
                    }
                }
                if (Found)
                {
                    for (int j = 0; j < 6; j++)
                    {
                        Tabs[j] += Lines[i + j];
                    }
                    i += 6;
                }
            }

            string FileName = url.Replace("/", "").Replace("http", "").Replace(":", "");
            StreamWriter sw = new StreamWriter(FileName);
            for (int i = 0; i < 6; i++)
            {
                sw.WriteLine(Tabs[i]);
            }
            sw.Close();

            List<List<int>> Result = ReadSong(FileName);
            Play(Result);
        }

        public List<List<int>> ReadSong(string path)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(path);
            string[] Strings = new string[6];
            for (int i = 0; i < 6; i++)
            {
                Strings[i] = "";
            }

            string Temp = "";
            while ((Temp = sr.ReadLine()) != null)
            {
                Strings[5] += Temp;
                for (int i = 4; i >= 0; i--)
                {
                    Strings[i] += sr.ReadLine();
                }
            }
            sr.Close();

            List<List<int>> Song = new List<List<int>>();

            for (int i = 0; i < Strings[0].Length; i++)
            {

                bool ToneFound = false;

                List<int> Current = new List<int>();

                for (int j = 0; j < 6; j++)
                {
                    if (Strings[j][i] != '-' && Strings[j][i] != '/' && Strings[j][i] != '|')
                    {
                        int Dummy;

                        if (int.TryParse(Strings[j][i].ToString(), out Dummy))
                        {
                            Current.Add(((int)((Tone[])(Enum.GetValues(typeof(Tone))))[j] + int.Parse(Strings[j][i].ToString())));
                            ToneFound = true;
                        }
                    }

                }

                if (!ToneFound && Strings[0][i] == '-')
                    Song.Add(null);
                else
                    Song.Add(Current);
            }

            Play(Song);
            return Song;
        }

        public void Play(List<List<int>> keys)
        {
            OutputDevice outputDevice = OutputDevice.InstalledDevices[0];
            outputDevice.Open();

            foreach (List<int> t in keys)
            {
                if (t == null)
                    Thread.Sleep(NoteDuration);
                else
                {
                    foreach (int s in t)
                    {
                        outputDevice.SendNoteOn(Channel.Channel1, GetFreq(s), 80);
                    }
                    Thread.Sleep(NoteDuration);
                }
            }
        }

        public Pitch GetFreq(int key)
        {
            return ((Pitch[])Enum.GetValues(typeof(Pitch)))[key + 21];
        }
    }
}

As an example I here recorded the song Master of Puppets by Metallica. As already mentioned, of course the rhytm often is not correct and the melody sometimes seems off. But still I find it fascinating how good for example the intro riff is hit and how easy we can create such music outputs.
Also I recorded Yesterday and Wonderwall.

Friday, July 17, 2015

Create MIDI Tones with C#

After I explained in the previous posts the creation of basic musical tones via Beep, I today want to enhance the sound drastically, which we do with the MIDI format. MIDI is a standard for the exchange of musical control information. It was mainly designed for the communication between synthesizers and consists of messages which describe the playing of tones. With an external library we can play MIDI tones very easily with C#, which also sound pretty well. This kind of surprised and fascinated me - with only some lines of code one can play actual songs.

For this we use the MIDI library midi-dot-net. This has to be downloaded, and then the file "midi.dll" has to be included in the project (Project - Add Reference). After using Midi; then an OutputDevice can be created, which we set via InstalledDevices[0] to our standard speaker. Via SendNoteOn() we then can play a note. For this we have to pass over the desired channel as the first parameter, as a second one the tone and finally the velocity as an int value (it measures, how forcefully the virtual key is pressed).  The note is specified as an object of the enumeration Pitch, which contains a broad spectrum of tones.
I liked the approach from the previous though, to use the keyboard keys, therefore we use this here: We convert the enumeration into an array of the type Pitch and then choose the tone belonging to the pressed key (the desired tone of key n is the entry n + 21).
The tone is played until another command is send, for example we can send SendNoteOff() to turn off the tone. We here simply wait via Sleep() the corresponding tone duration and then play the next one.
The following program plays the anthems from the previous post with MIDI tones:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Midi;
using System.Threading;

namespace Beep
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PlayAmericanAnthem();
            PlayGermanAnthem();
        }

        OutputDevice outputDevice;

        public void PlayNote(int key, double duration)
        {
            Pitch Note = ((Pitch[])Enum.GetValues(typeof(Pitch)))[key + 21];
            outputDevice.SendNoteOn(Channel.Channel1, Note, 80);
            Thread.Sleep((int)duration);
        }

        public void PlayGermanAnthem()
        {
            outputDevice = OutputDevice.InstalledDevices[0];
            outputDevice.Open();

            PlayNote(31, 700);
            PlayNote(33, 300);

            PlayNote(35, 500);
            PlayNote(33, 500);
            PlayNote(36, 500);
            PlayNote(35, 500);

            PlayNote(33, 250);
            PlayNote(30, 250);
            PlayNote(31, 500);
            PlayNote(40, 500);
            PlayNote(38, 500);

            PlayNote(36, 500);
            PlayNote(35, 500);
            PlayNote(33, 500);
            PlayNote(35, 250);
            PlayNote(31, 250);

            PlayNote(38, 800);
            outputDevice.Close();
        }

        public void PlayAmericanAnthem()
        {
            outputDevice = OutputDevice.InstalledDevices[0];
            outputDevice.Open();

            PlayNote(20, 300 * 1.3);
            PlayNote(17, 170 * 1.3);

            PlayNote(13, 333 * 1.3);
            PlayNote(17, 333 * 1.3);
            PlayNote(20, 333 * 1.3);

            PlayNote(25, 666 * 1.3);
            PlayNote(29, 200 * 1.3);
            PlayNote(27, 130 * 1.3);

            PlayNote(25, 333 * 1.3);
            PlayNote(17, 333 * 1.3);
            PlayNote(19, 333 * 1.3);

            PlayNote(20, 666 * 1.3);
            PlayNote(20, 170 * 1.3);
            PlayNote(20, 170 * 1.3);

            PlayNote(29, 450 * 1.3);
            PlayNote(27, 220 * 1.3);
            PlayNote(25, 333 * 1.3);

            PlayNote(24, 666 * 1.3);
            PlayNote(22, 200 * 1.3);
            PlayNote(24, 100 * 1.3);

            PlayNote(25, 333 * 1.3);
            PlayNote(25, 333 * 1.3);
            PlayNote(20, 333 * 1.3);

            PlayNote(17, 333 * 1.3);
            PlayNote(13, 333 * 1.3);
            outputDevice.Close();
        }
    }
}

Thursday, July 16, 2015

Piano Keyboard

After I explained in a previous post how to create musical tones via Beep(), I today want to simply show a little program which simulates a basic playable piano keyboard. The tones are calculated by the formula out of the previous post, the surface of the program looks as follows:











Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace KeyboardTone
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void PlayKey(int key)
        {
            Console.Beep((int)(Math.Pow(Math.Pow(2, 1 / (double)12), key - 49) * 440), 500);
        }

        private void button_Click(object sender, EventArgs e)
        {
            PlayKey(int.Parse(((Button)sender).Name.Substring(6)));
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button13.Click += button_Click;
            button14.Click += button_Click;
            button15.Click += button_Click;
            button16.Click += button_Click;
            button17.Click += button_Click;
            button18.Click += button_Click;
            button19.Click += button_Click;
            button20.Click += button_Click;
            button21.Click += button_Click;
            button22.Click += button_Click;
            button23.Click += button_Click;
            button24.Click += button_Click;
            button25.Click += button_Click;
            button26.Click += button_Click;
            button27.Click += button_Click;
            button28.Click += button_Click;
            button29.Click += button_Click;
            button30.Click += button_Click;
            button31.Click += button_Click;
            button32.Click += button_Click;
            button33.Click += button_Click;
            button34.Click += button_Click;
            button35.Click += button_Click;
            button36.Click += button_Click;
            button37.Click += button_Click;
            button38.Click += button_Click;
            button39.Click += button_Click;
            button40.Click += button_Click;
            button41.Click += button_Click;
            button42.Click += button_Click;
            button43.Click += button_Click;
            button44.Click += button_Click;
            button45.Click += button_Click;
            button46.Click += button_Click;
            button47.Click += button_Click;
            button48.Click += button_Click;
            button49.Click += button_Click;
            button50.Click += button_Click;
            button51.Click += button_Click;
            button52.Click += button_Click;
            button53.Click += button_Click;
            button54.Click += button_Click;
            button55.Click += button_Click;
            button56.Click += button_Click;
            button57.Click += button_Click;
            button58.Click += button_Click;
            button59.Click += button_Click;
            button60.Click += button_Click;
        }

    }
}
And here the content of the file Form1.Designer.cs:
namespace KeyboardTone
{
    partial class Form1
    {
        /// <summary>
       /// Erforderliche Designervariable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
       /// Verwendete Ressourcen bereinigen.
        /// </summary>
        /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Vom Windows Form-Designer generierter Code

        /// <summary>
       /// Erforderliche Methode für die Designerunterstützung.
       /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
        /// </summary>
        private void InitializeComponent()
        {
            this.button13 = new System.Windows.Forms.Button();
            this.button15 = new System.Windows.Forms.Button();
            this.button14 = new System.Windows.Forms.Button();
            this.button16 = new System.Windows.Forms.Button();
            this.button17 = new System.Windows.Forms.Button();
            this.button18 = new System.Windows.Forms.Button();
            this.button19 = new System.Windows.Forms.Button();
            this.button20 = new System.Windows.Forms.Button();
            this.button21 = new System.Windows.Forms.Button();
            this.button22 = new System.Windows.Forms.Button();
            this.button23 = new System.Windows.Forms.Button();
            this.button24 = new System.Windows.Forms.Button();
            this.button35 = new System.Windows.Forms.Button();
            this.button36 = new System.Windows.Forms.Button();
            this.button33 = new System.Windows.Forms.Button();
            this.button34 = new System.Windows.Forms.Button();
            this.button31 = new System.Windows.Forms.Button();
            this.button32 = new System.Windows.Forms.Button();
            this.button30 = new System.Windows.Forms.Button();
            this.button28 = new System.Windows.Forms.Button();
            this.button29 = new System.Windows.Forms.Button();
            this.button26 = new System.Windows.Forms.Button();
            this.button27 = new System.Windows.Forms.Button();
            this.button25 = new System.Windows.Forms.Button();
            this.button47 = new System.Windows.Forms.Button();
            this.button48 = new System.Windows.Forms.Button();
            this.button45 = new System.Windows.Forms.Button();
            this.button46 = new System.Windows.Forms.Button();
            this.button43 = new System.Windows.Forms.Button();
            this.button44 = new System.Windows.Forms.Button();
            this.button42 = new System.Windows.Forms.Button();
            this.button40 = new System.Windows.Forms.Button();
            this.button41 = new System.Windows.Forms.Button();
            this.button38 = new System.Windows.Forms.Button();
            this.button39 = new System.Windows.Forms.Button();
            this.button37 = new System.Windows.Forms.Button();
            this.button59 = new System.Windows.Forms.Button();
            this.button60 = new System.Windows.Forms.Button();
            this.button57 = new System.Windows.Forms.Button();
            this.button58 = new System.Windows.Forms.Button();
            this.button55 = new System.Windows.Forms.Button();
            this.button56 = new System.Windows.Forms.Button();
            this.button54 = new System.Windows.Forms.Button();
            this.button52 = new System.Windows.Forms.Button();
            this.button53 = new System.Windows.Forms.Button();
            this.button50 = new System.Windows.Forms.Button();
            this.button51 = new System.Windows.Forms.Button();
            this.button49 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // button13
            //
            this.button13.BackColor = System.Drawing.Color.White;
            this.button13.Location = new System.Drawing.Point(17, 42);
            this.button13.Name = "button13";
            this.button13.Size = new System.Drawing.Size(21, 113);
            this.button13.TabIndex = 0;
            this.button13.UseVisualStyleBackColor = false;
            //
            // button15
            //
            this.button15.BackColor = System.Drawing.Color.White;
            this.button15.Location = new System.Drawing.Point(38, 42);
            this.button15.Name = "button15";
            this.button15.Size = new System.Drawing.Size(21, 113);
            this.button15.TabIndex = 1;
            this.button15.UseVisualStyleBackColor = false;
            //
            // button14
            //
            this.button14.BackColor = System.Drawing.Color.Black;
            this.button14.Location = new System.Drawing.Point(29, 22);
            this.button14.Name = "button14";
            this.button14.Size = new System.Drawing.Size(17, 87);
            this.button14.TabIndex = 2;
            this.button14.UseVisualStyleBackColor = false;
            //
            // button16
            //
            this.button16.BackColor = System.Drawing.Color.Black;
            this.button16.Location = new System.Drawing.Point(50, 22);
            this.button16.Name = "button16";
            this.button16.Size = new System.Drawing.Size(17, 87);
            this.button16.TabIndex = 4;
            this.button16.UseVisualStyleBackColor = false;
            //
            // button17
            //
            this.button17.BackColor = System.Drawing.Color.White;
            this.button17.Location = new System.Drawing.Point(59, 42);
            this.button17.Name = "button17";
            this.button17.Size = new System.Drawing.Size(21, 113);
            this.button17.TabIndex = 3;
            this.button17.UseVisualStyleBackColor = false;
            //
            // button18
            //
            this.button18.BackColor = System.Drawing.Color.White;
            this.button18.Location = new System.Drawing.Point(80, 42);
            this.button18.Name = "button18";
            this.button18.Size = new System.Drawing.Size(21, 113);
            this.button18.TabIndex = 5;
            this.button18.UseVisualStyleBackColor = false;
            //
            // button19
            //
            this.button19.BackColor = System.Drawing.Color.Black;
            this.button19.Location = new System.Drawing.Point(92, 22);
            this.button19.Name = "button19";
            this.button19.Size = new System.Drawing.Size(17, 87);
            this.button19.TabIndex = 7;
            this.button19.UseVisualStyleBackColor = false;
            //
            // button20
            //
            this.button20.BackColor = System.Drawing.Color.White;
            this.button20.Location = new System.Drawing.Point(101, 42);
            this.button20.Name = "button20";
            this.button20.Size = new System.Drawing.Size(21, 113);
            this.button20.TabIndex = 6;
            this.button20.UseVisualStyleBackColor = false;
            //
            // button21
            //
            this.button21.BackColor = System.Drawing.Color.Black;
            this.button21.Location = new System.Drawing.Point(112, 22);
            this.button21.Name = "button21";
            this.button21.Size = new System.Drawing.Size(17, 87);
            this.button21.TabIndex = 9;
            this.button21.UseVisualStyleBackColor = false;
            //
            // button22
            //
            this.button22.BackColor = System.Drawing.Color.White;
            this.button22.Location = new System.Drawing.Point(121, 42);
            this.button22.Name = "button22";
            this.button22.Size = new System.Drawing.Size(21, 113);
            this.button22.TabIndex = 8;
            this.button22.UseVisualStyleBackColor = false;
            //
            // button23
            //
            this.button23.BackColor = System.Drawing.Color.Black;
            this.button23.Location = new System.Drawing.Point(133, 22);
            this.button23.Name = "button23";
            this.button23.Size = new System.Drawing.Size(17, 87);
            this.button23.TabIndex = 11;
            this.button23.UseVisualStyleBackColor = false;
            //
            // button24
            //
            this.button24.BackColor = System.Drawing.Color.White;
            this.button24.Location = new System.Drawing.Point(142, 42);
            this.button24.Name = "button24";
            this.button24.Size = new System.Drawing.Size(21, 113);
            this.button24.TabIndex = 10;
            this.button24.UseVisualStyleBackColor = false;
            //
            // button35
            //
            this.button35.BackColor = System.Drawing.Color.Black;
            this.button35.Location = new System.Drawing.Point(285, 22);
            this.button35.Name = "button35";
            this.button35.Size = new System.Drawing.Size(17, 87);
            this.button35.TabIndex = 23;
            this.button35.UseVisualStyleBackColor = false;
            //
            // button36
            //
            this.button36.BackColor = System.Drawing.Color.White;
            this.button36.Location = new System.Drawing.Point(294, 42);
            this.button36.Name = "button36";
            this.button36.Size = new System.Drawing.Size(21, 113);
            this.button36.TabIndex = 22;
            this.button36.UseVisualStyleBackColor = false;
            //
            // button33
            //
            this.button33.BackColor = System.Drawing.Color.Black;
            this.button33.Location = new System.Drawing.Point(264, 22);
            this.button33.Name = "button33";
            this.button33.Size = new System.Drawing.Size(17, 87);
            this.button33.TabIndex = 21;
            this.button33.UseVisualStyleBackColor = false;
            //
            // button34
            //
            this.button34.BackColor = System.Drawing.Color.White;
            this.button34.Location = new System.Drawing.Point(273, 42);
            this.button34.Name = "button34";
            this.button34.Size = new System.Drawing.Size(21, 113);
            this.button34.TabIndex = 20;
            this.button34.UseVisualStyleBackColor = false;
            //
            // button31
            //
            this.button31.BackColor = System.Drawing.Color.Black;
            this.button31.Location = new System.Drawing.Point(244, 22);
            this.button31.Name = "button31";
            this.button31.Size = new System.Drawing.Size(17, 87);
            this.button31.TabIndex = 19;
            this.button31.UseVisualStyleBackColor = false;
            //
            // button32
            //
            this.button32.BackColor = System.Drawing.Color.White;
            this.button32.Location = new System.Drawing.Point(253, 42);
            this.button32.Name = "button32";
            this.button32.Size = new System.Drawing.Size(21, 113);
            this.button32.TabIndex = 18;
            this.button32.UseVisualStyleBackColor = false;
            //
            // button30
            //
            this.button30.BackColor = System.Drawing.Color.White;
            this.button30.Location = new System.Drawing.Point(232, 42);
            this.button30.Name = "button30";
            this.button30.Size = new System.Drawing.Size(21, 113);
            this.button30.TabIndex = 17;
            this.button30.UseVisualStyleBackColor = false;
            //
            // button28
            //
            this.button28.BackColor = System.Drawing.Color.Black;
            this.button28.Location = new System.Drawing.Point(202, 22);
            this.button28.Name = "button28";
            this.button28.Size = new System.Drawing.Size(17, 87);
            this.button28.TabIndex = 16;
            this.button28.UseVisualStyleBackColor = false;
            //
            // button29
            //
            this.button29.BackColor = System.Drawing.Color.White;
            this.button29.Location = new System.Drawing.Point(211, 42);
            this.button29.Name = "button29";
            this.button29.Size = new System.Drawing.Size(21, 113);
            this.button29.TabIndex = 15;
            this.button29.UseVisualStyleBackColor = false;
            //
            // button26
            //
            this.button26.BackColor = System.Drawing.Color.Black;
            this.button26.Location = new System.Drawing.Point(181, 22);
            this.button26.Name = "button26";
            this.button26.Size = new System.Drawing.Size(17, 87);
            this.button26.TabIndex = 14;
            this.button26.UseVisualStyleBackColor = false;
            //
            // button27
            //
            this.button27.BackColor = System.Drawing.Color.White;
            this.button27.Location = new System.Drawing.Point(190, 42);
            this.button27.Name = "button27";
            this.button27.Size = new System.Drawing.Size(21, 113);
            this.button27.TabIndex = 13;
            this.button27.UseVisualStyleBackColor = false;
            //
            // button25
            //
            this.button25.BackColor = System.Drawing.Color.White;
            this.button25.Location = new System.Drawing.Point(169, 42);
            this.button25.Name = "button25";
            this.button25.Size = new System.Drawing.Size(21, 113);
            this.button25.TabIndex = 12;
            this.button25.UseVisualStyleBackColor = false;
            //
            // button47
            //
            this.button47.BackColor = System.Drawing.Color.Black;
            this.button47.Location = new System.Drawing.Point(439, 22);
            this.button47.Name = "button47";
            this.button47.Size = new System.Drawing.Size(17, 87);
            this.button47.TabIndex = 35;
            this.button47.UseVisualStyleBackColor = false;
            //
            // button48
            //
            this.button48.BackColor = System.Drawing.Color.White;
            this.button48.Location = new System.Drawing.Point(448, 42);
            this.button48.Name = "button48";
            this.button48.Size = new System.Drawing.Size(21, 113);
            this.button48.TabIndex = 34;
            this.button48.UseVisualStyleBackColor = false;
            //
            // button45
            //
            this.button45.BackColor = System.Drawing.Color.Black;
            this.button45.Location = new System.Drawing.Point(418, 22);
            this.button45.Name = "button45";
            this.button45.Size = new System.Drawing.Size(17, 87);
            this.button45.TabIndex = 33;
            this.button45.UseVisualStyleBackColor = false;
            //
            // button46
            //
            this.button46.BackColor = System.Drawing.Color.White;
            this.button46.Location = new System.Drawing.Point(427, 42);
            this.button46.Name = "button46";
            this.button46.Size = new System.Drawing.Size(21, 113);
            this.button46.TabIndex = 32;
            this.button46.UseVisualStyleBackColor = false;
            //
            // button43
            //
            this.button43.BackColor = System.Drawing.Color.Black;
            this.button43.Location = new System.Drawing.Point(398, 22);
            this.button43.Name = "button43";
            this.button43.Size = new System.Drawing.Size(17, 87);
            this.button43.TabIndex = 31;
            this.button43.UseVisualStyleBackColor = false;
            //
            // button44
            //
            this.button44.BackColor = System.Drawing.Color.White;
            this.button44.Location = new System.Drawing.Point(407, 42);
            this.button44.Name = "button44";
            this.button44.Size = new System.Drawing.Size(21, 113);
            this.button44.TabIndex = 30;
            this.button44.UseVisualStyleBackColor = false;
            //
            // button42
            //
            this.button42.BackColor = System.Drawing.Color.White;
            this.button42.Location = new System.Drawing.Point(386, 42);
            this.button42.Name = "button42";
            this.button42.Size = new System.Drawing.Size(21, 113);
            this.button42.TabIndex = 29;
            this.button42.UseVisualStyleBackColor = false;
            //
            // button40
            //
            this.button40.BackColor = System.Drawing.Color.Black;
            this.button40.Location = new System.Drawing.Point(356, 22);
            this.button40.Name = "button40";
            this.button40.Size = new System.Drawing.Size(17, 87);
            this.button40.TabIndex = 28;
            this.button40.UseVisualStyleBackColor = false;
            //
            // button41
            //
            this.button41.BackColor = System.Drawing.Color.White;
            this.button41.Location = new System.Drawing.Point(365, 42);
            this.button41.Name = "button41";
            this.button41.Size = new System.Drawing.Size(21, 113);
            this.button41.TabIndex = 27;
            this.button41.UseVisualStyleBackColor = false;
            //
            // button38
            //
            this.button38.BackColor = System.Drawing.Color.Black;
            this.button38.Location = new System.Drawing.Point(335, 22);
            this.button38.Name = "button38";
            this.button38.Size = new System.Drawing.Size(17, 87);
            this.button38.TabIndex = 26;
            this.button38.UseVisualStyleBackColor = false;
            //
            // button39
            //
            this.button39.BackColor = System.Drawing.Color.White;
            this.button39.Location = new System.Drawing.Point(344, 42);
            this.button39.Name = "button39";
            this.button39.Size = new System.Drawing.Size(21, 113);
            this.button39.TabIndex = 25;
            this.button39.UseVisualStyleBackColor = false;
            //
            // button37
            //
            this.button37.BackColor = System.Drawing.Color.White;
            this.button37.Location = new System.Drawing.Point(323, 42);
            this.button37.Name = "button37";
            this.button37.Size = new System.Drawing.Size(21, 113);
            this.button37.TabIndex = 24;
            this.button37.UseVisualStyleBackColor = false;
            //
            // button59
            //
            this.button59.BackColor = System.Drawing.Color.Black;
            this.button59.Location = new System.Drawing.Point(594, 22);
            this.button59.Name = "button59";
            this.button59.Size = new System.Drawing.Size(17, 87);
            this.button59.TabIndex = 47;
            this.button59.UseVisualStyleBackColor = false;
            //
            // button60
            //
            this.button60.BackColor = System.Drawing.Color.White;
            this.button60.Location = new System.Drawing.Point(603, 42);
            this.button60.Name = "button60";
            this.button60.Size = new System.Drawing.Size(21, 113);
            this.button60.TabIndex = 46;
            this.button60.UseVisualStyleBackColor = false;
            //
            // button57
            //
            this.button57.BackColor = System.Drawing.Color.Black;
            this.button57.Location = new System.Drawing.Point(573, 22);
            this.button57.Name = "button57";
            this.button57.Size = new System.Drawing.Size(17, 87);
            this.button57.TabIndex = 45;
            this.button57.UseVisualStyleBackColor = false;
            //
            // button58
            //
            this.button58.BackColor = System.Drawing.Color.White;
            this.button58.Location = new System.Drawing.Point(582, 42);
            this.button58.Name = "button58";
            this.button58.Size = new System.Drawing.Size(21, 113);
            this.button58.TabIndex = 44;
            this.button58.UseVisualStyleBackColor = false;
            //
            // button55
            //
            this.button55.BackColor = System.Drawing.Color.Black;
            this.button55.Location = new System.Drawing.Point(553, 22);
            this.button55.Name = "button55";
            this.button55.Size = new System.Drawing.Size(17, 87);
            this.button55.TabIndex = 43;
            this.button55.UseVisualStyleBackColor = false;
            //
            // button56
            //
            this.button56.BackColor = System.Drawing.Color.White;
            this.button56.Location = new System.Drawing.Point(562, 42);
            this.button56.Name = "button56";
            this.button56.Size = new System.Drawing.Size(21, 113);
            this.button56.TabIndex = 42;
            this.button56.UseVisualStyleBackColor = false;
            //
            // button54
            //
            this.button54.BackColor = System.Drawing.Color.White;
            this.button54.Location = new System.Drawing.Point(541, 42);
            this.button54.Name = "button54";
            this.button54.Size = new System.Drawing.Size(21, 113);
            this.button54.TabIndex = 41;
            this.button54.UseVisualStyleBackColor = false;
            //
            // button52
            //
            this.button52.BackColor = System.Drawing.Color.Black;
            this.button52.Location = new System.Drawing.Point(511, 22);
            this.button52.Name = "button52";
            this.button52.Size = new System.Drawing.Size(17, 87);
            this.button52.TabIndex = 40;
            this.button52.UseVisualStyleBackColor = false;
            //
            // button53
            //
            this.button53.BackColor = System.Drawing.Color.White;
            this.button53.Location = new System.Drawing.Point(520, 42);
            this.button53.Name = "button53";
            this.button53.Size = new System.Drawing.Size(21, 113);
            this.button53.TabIndex = 39;
            this.button53.UseVisualStyleBackColor = false;
            //
            // button50
            //
            this.button50.BackColor = System.Drawing.Color.Black;
            this.button50.Location = new System.Drawing.Point(490, 22);
            this.button50.Name = "button50";
            this.button50.Size = new System.Drawing.Size(17, 87);
            this.button50.TabIndex = 38;
            this.button50.UseVisualStyleBackColor = false;
            //
            // button51
            //
            this.button51.BackColor = System.Drawing.Color.White;
            this.button51.Location = new System.Drawing.Point(499, 42);
            this.button51.Name = "button51";
            this.button51.Size = new System.Drawing.Size(21, 113);
            this.button51.TabIndex = 37;
            this.button51.UseVisualStyleBackColor = false;
            //
            // button49
            //
            this.button49.BackColor = System.Drawing.Color.White;
            this.button49.Location = new System.Drawing.Point(478, 42);
            this.button49.Name = "button49";
            this.button49.Size = new System.Drawing.Size(21, 113);
            this.button49.TabIndex = 36;
            this.button49.UseVisualStyleBackColor = false;
            //
            // Form1
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(652, 180);
            this.Controls.Add(this.button59);
            this.Controls.Add(this.button60);
            this.Controls.Add(this.button57);
            this.Controls.Add(this.button58);
            this.Controls.Add(this.button55);
            this.Controls.Add(this.button56);
            this.Controls.Add(this.button54);
            this.Controls.Add(this.button52);
            this.Controls.Add(this.button53);
            this.Controls.Add(this.button50);
            this.Controls.Add(this.button51);
            this.Controls.Add(this.button49);
            this.Controls.Add(this.button47);
            this.Controls.Add(this.button48);
            this.Controls.Add(this.button45);
            this.Controls.Add(this.button46);
            this.Controls.Add(this.button43);
            this.Controls.Add(this.button44);
            this.Controls.Add(this.button42);
            this.Controls.Add(this.button40);
            this.Controls.Add(this.button41);
            this.Controls.Add(this.button38);
            this.Controls.Add(this.button39);
            this.Controls.Add(this.button37);
            this.Controls.Add(this.button35);
            this.Controls.Add(this.button36);
            this.Controls.Add(this.button33);
            this.Controls.Add(this.button34);
            this.Controls.Add(this.button31);
            this.Controls.Add(this.button32);
            this.Controls.Add(this.button30);
            this.Controls.Add(this.button28);
            this.Controls.Add(this.button29);
            this.Controls.Add(this.button26);
            this.Controls.Add(this.button27);
            this.Controls.Add(this.button25);
            this.Controls.Add(this.button23);
            this.Controls.Add(this.button24);
            this.Controls.Add(this.button21);
            this.Controls.Add(this.button22);
            this.Controls.Add(this.button19);
            this.Controls.Add(this.button20);
            this.Controls.Add(this.button18);
            this.Controls.Add(this.button16);
            this.Controls.Add(this.button17);
            this.Controls.Add(this.button14);
            this.Controls.Add(this.button15);
            this.Controls.Add(this.button13);
            this.Name = "Form1";
            this.Text = "Piano";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Button button13;
        private System.Windows.Forms.Button button15;
        private System.Windows.Forms.Button button14;
        private System.Windows.Forms.Button button16;
        private System.Windows.Forms.Button button17;
        private System.Windows.Forms.Button button18;
        private System.Windows.Forms.Button button19;
        private System.Windows.Forms.Button button20;
        private System.Windows.Forms.Button button21;
        private System.Windows.Forms.Button button22;
        private System.Windows.Forms.Button button23;
        private System.Windows.Forms.Button button24;
        private System.Windows.Forms.Button button35;
        private System.Windows.Forms.Button button36;
        private System.Windows.Forms.Button button33;
        private System.Windows.Forms.Button button34;
        private System.Windows.Forms.Button button31;
        private System.Windows.Forms.Button button32;
        private System.Windows.Forms.Button button30;
        private System.Windows.Forms.Button button28;
        private System.Windows.Forms.Button button29;
        private System.Windows.Forms.Button button26;
        private System.Windows.Forms.Button button27;
        private System.Windows.Forms.Button button25;
        private System.Windows.Forms.Button button47;
        private System.Windows.Forms.Button button48;
        private System.Windows.Forms.Button button45;
        private System.Windows.Forms.Button button46;
        private System.Windows.Forms.Button button43;
        private System.Windows.Forms.Button button44;
        private System.Windows.Forms.Button button42;
        private System.Windows.Forms.Button button40;
        private System.Windows.Forms.Button button41;
        private System.Windows.Forms.Button button38;
        private System.Windows.Forms.Button button39;
        private System.Windows.Forms.Button button37;
        private System.Windows.Forms.Button button59;
        private System.Windows.Forms.Button button60;
        private System.Windows.Forms.Button button57;
        private System.Windows.Forms.Button button58;
        private System.Windows.Forms.Button button55;
        private System.Windows.Forms.Button button56;
        private System.Windows.Forms.Button button54;
        private System.Windows.Forms.Button button52;
        private System.Windows.Forms.Button button53;
        private System.Windows.Forms.Button button50;
        private System.Windows.Forms.Button button51;
        private System.Windows.Forms.Button button49;
    }
}