{"id":1886,"date":"2017-02-06T01:08:05","date_gmt":"2017-02-06T06:08:05","guid":{"rendered":"http:\/\/www.phpied.com\/?p=1886"},"modified":"2017-02-06T01:14:03","modified_gmt":"2017-02-06T06:14:03","slug":"intervals","status":"publish","type":"post","link":"https:\/\/www.phpied.com\/intervals\/","title":{"rendered":"Intervals"},"content":{"rendered":"<p>Here's my new tool called <a href=\"https:\/\/www.onlinemusictools.com\/intervals\/\">intervals<\/a><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.phpied.com\/wp-content\/uploads\/2017\/02\/intervalsui.png\" alt=\"intervalsui\" width=\"650\" \/><\/p>\n<p><a href=\"https:\/\/www.onlinemusictools.com\/intervals\/\">Play with it here<\/a>. <\/p>\n<p>Learn about <a href=\"http:\/\/music.stoyanstefanov.com\/2017\/01\/16\/table-of-intervals-part-1\/\">the theory behind it here<\/a>.<\/p>\n<p>The <a href=\"https:\/\/github.com\/stoyan\/intervals\/\">code for the tool<\/a>.<\/p>\n<h2>What does it do?<\/h2>\n<p>Generates a random music interval, shows it on the musical staff. You try to guess it. Clicking on the staff reveals the answer. You can also play the interval.<\/p>\n<h2>How was it built?<\/h2>\n<p>It's a React app. What's React? Get <a href=\"https:\/\/www.amazon.com\/dp\/1491931825\/?tag=w3clubs-20\">the best React book<\/a> and find out \ud83d\ude42<\/p>\n<p>But these days you don't need to start a React app from scratch (as described in the book), you have <a href=\"https:\/\/github.com\/facebookincubator\/create-react-app\">create-react-app<\/a> which generates a new app and sets up all auxiliary tools you need. Furthermore, you don't need to start a new app from an empty canvas, you can start building off of a template, thanks to <a href=\"https:\/\/github.com\/stoyan\/craft\">CRAFT<\/a>.<\/p>\n<p>The template used is <a href=\"https:\/\/github.com\/stoyan\/flashcards\">flashcards<\/a>.<\/p>\n<p>So to get an app like this off the ground you go:<\/p>\n<pre>\r\n$ npm i -g create-react-app\r\n$ npm i -g craftool\r\n$ craft intervals https:\/\/github.com\/stoyan\/flashcards\/archive\/master.zip\r\n$ cd intervals\r\n$ npm install .\r\n$ npm start\r\n<\/pre>\n<p>Tada! Sudden flashcard app, ready to go. All you need to do is <a href=\"https:\/\/github.com\/stoyan\/flashcards#getquestion\">implement the functions <code>getAnswer()<\/code> and <code>getQuestion()<\/code><\/a>.<\/p>\n<p>This is a bit of a specialized app, so no need to go into the gory details of the Questions and Answers. But overall:<\/p>\n<ol>\n<li>generate a random first note. e.g. F\u00e2\u2122\u00af on the third octave<\/li>\n<li>generate a random interval, e.g. a perfect forth<\/li>\n<li>use <a href=\"https:\/\/github.com\/saebekassebil\/teoria\">teoria<\/a> to give you the correct second note, given a start note and an interval<\/li>\n<li>draw the two on the staff using <a href=\"https:\/\/github.com\/0xfe\/vexflow\">Vex<\/a><\/li>\n<li>play the notes<\/li>\n<li>random pretty-printing and conversion from my note conventions to teoria to vex<\/li>\n<\/ol>\n<h2>Weirdness and hacks<\/h2>\n<h3>danger<\/h3>\n<p>Vex wants to draw an SVG inside a DOM element. (AFAIK. There may be better APIs I did not uncover.)<\/p>\n<p>So I draw the SVG in a hidden div then copy it over to React, like so:<\/p>\n<pre>\r\n  &lt;div dangerouslySetInnerHTML={{__html: someSVG.outerHTML}} \/&gt;\r\n<\/pre>\n<p>Ooooh, danger!<\/p>\n<h3>try-catch<\/h3>\n<p>Sometimes (rarely!) in all this randomness either <code>teoria<\/code> or <code>vex<\/code> deserts me. I think I worked out most of the kinks but still... I have a try-catch that simply generates another random question. This is pretty bad as it can theoretically freeze the browser if it fails to generate a valid question but in <a href=\"https:\/\/www.facebook.com\/stoyan.stefanov\/posts\/10154957748200960\">my testing<\/a> it hasn't happened. And sometimes you gotta do what you gotta do \ud83d\ude42<\/p>\n<h3>Playing audio<\/h3>\n<p>No WebAudio, just the ole <code>new Audio(url).play()<\/code>. I play the first note, subscribe to its <code>ended<\/code> event, play the second, subscribe to its <code>ended<\/code> and play both. Awesome. <a href=\"https:\/\/github.com\/stoyan\/intervals\/blob\/4e27117ca9ee1de3a42a37b418f90ec22f4eb039\/src\/App.js#L125-L147\">Here it goes.<\/a><\/p>\n<p>Except iPhone still refuses to play without human intervention, so I just play both together when iPhone is detected.<\/p>\n<h2>Thanks for reading!<\/h2>\n<p>I hope you learned a quick and easy way to <a href=\"https:\/\/github.com\/stoyan\/flashcards\">create quiz apps<\/a>. And also learned there's a place you can go to <a href=\"https:\/\/www.onlinemusictools.com\/intervals\/\">practice them intervals<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here&#8217;s my new tool called intervals Play with it here. Learn about the theory behind it here. The code for the tool. What does it do? Generates a random music interval, shows it on the musical staff. You try to guess it. Clicking on the staff reveals the answer. You can also play the interval. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,7,366,22],"tags":[],"_links":{"self":[{"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/posts\/1886"}],"collection":[{"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/comments?post=1886"}],"version-history":[{"count":0,"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/posts\/1886\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/media?parent=1886"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/categories?post=1886"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.phpied.com\/wp-json\/wp\/v2\/tags?post=1886"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}