A basic guitar tablature editor written in JavaScript
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tablaturejs.html 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
  4. <head>
  5. <!-- vim: set lbr sbr=@___ encoding=utf-8 columns=80 lines=999: -->
  6. <!--
  7. TODO:
  8. * work with insert/delete
  9. * add repeat symbol (:)
  10. CHANGELOG:
  11. v0.1.0 - 2010/12/20
  12. * Implemented import
  13. v0.0.9 - 2010/05/11
  14. * Implemented export
  15. v0.0.8 - 2010/01/14
  16. * Implemented mouse click
  17. v0.0.7 - 2010/01/11
  18. * Improved deletion when placed on a bar
  19. * Major refactoring
  20. * Automatically deletion of trailing empty staves
  21. * Added copy/paste feature
  22. v0.0.6 - 2009/10/16
  23. * Added quick help
  24. v0.0.5 - 2009/09/25
  25. * Basic styling
  26. v0.0.4 - 2009/09/24
  27. * Possibility to add new staves
  28. * Moving from staff to staff with keys
  29. v0.0.3 - 2009/09/23
  30. * Moving current cell with keys
  31. * Adding speed
  32. v0.0.2 - 2009/09/22
  33. * Current cell display
  34. v0.0.1 - 2009/09/21
  35. * Basic staff display
  36. -->
  37. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  38. <title>TablatureJS</title>
  39. <script type="text/javascript" src="mootools-1.2.4-core-yc.js"></script>
  40. <script type="text/javascript">
  41. //<![CDATA[
  42. var Tablature = {
  43. NUMBER_OF_LINES : 6,
  44. WIDTH : 78,
  45. MAX_SPEED : 64,
  46. BORDER : new Element('strong', { text : '|' }),
  47. LINE : new Element('span', { text : '-' }),
  48. BAR : new Element('span', { text : '|' }),
  49. _numberOfStaves : null,
  50. _currentStaffNumber : null,
  51. _currentColumnNumber : null,
  52. _currentLineNumber : null,
  53. _movingSpeed : null,
  54. _mousePosition : null,
  55. _copiedColumn : ['-', '-', '-', '-', '-', '-'],
  56. initialise: function() {
  57. Tablature._numberOfStaves = 0;
  58. Tablature._addStaff();
  59. Tablature._currentColumnNumber = 0;
  60. Tablature._currentLineNumber = 0;
  61. Tablature._currentStaffNumber = 0;
  62. Tablature._setMovingSpeed(1);
  63. Tablature._displayCursor();
  64. Tablature.hideExport();
  65. Tablature.hideImport();
  66. $('tab').addEvent('click', Tablature._onClick);
  67. $('tab').addEvent('mouseover', Tablature._onMouseOver);
  68. $('export').addEvent('click', Tablature.export);
  69. $('import').addEvent('click', Tablature.showImport);
  70. $('close-export').addEvent('click', Tablature.hideExport);
  71. $('close-import').addEvent('click', Tablature.hideImport);
  72. $('save-import').addEvent('click', Tablature.import);
  73. },
  74. changeSpeed: function(increaseOrDecrease) {
  75. switch(increaseOrDecrease) {
  76. case 'increase':
  77. Tablature._setMovingSpeed( Tablature._movingSpeed * 2 );
  78. break;
  79. case 'decrease':
  80. Tablature._setMovingSpeed( Tablature._movingSpeed / 2 );
  81. break;
  82. ;
  83. }
  84. },
  85. clear: function() {
  86. for ( var staff = Tablature._numberOfStaves ; staff > 0 ; staff-- ) {
  87. Tablature._getStaff(staff-1).destroy();
  88. Tablature._numberOfStaves--;
  89. }
  90. },
  91. copyColumn: function() {
  92. Tablature._getCurrentColumn().each( function(e,i) {
  93. Tablature._copiedColumn[i] = e.get('text');
  94. });
  95. },
  96. draw: function(key) {
  97. Tablature._getCurrentNote().set('text', key);
  98. },
  99. drawBar: function() {
  100. Tablature._getCurrentColumn().each( function(p) {
  101. p.set('text', '|');
  102. });
  103. },
  104. eraseColumn: function() {
  105. Tablature._getCurrentColumn().each( function(p) {
  106. p.set('text', '-');
  107. });
  108. },
  109. export: function() {
  110. var tab = '';
  111. $('tab').getElements('div').each( function(staff) {
  112. staff.getElements('p').each( function(line) {
  113. tab += '|';
  114. line.getElements('span').each( function(note) {
  115. tab += note.get('text');
  116. })
  117. tab += '|';
  118. tab += "\n";
  119. });
  120. tab += "\n";
  121. });
  122. $('export-content').value = tab;
  123. Tablature._showExport();
  124. },
  125. hideExport: function() {
  126. $('export-tab').setStyle('display','none');
  127. },
  128. hideImport: function() {
  129. $('import-tab').setStyle('display','none');
  130. },
  131. import: function() {
  132. var tab = $('import-content').value;
  133. lines = tab.match(new RegExp("\\|.{"+Tablature.WIDTH+"}\\|", "g"));
  134. var staves = [];
  135. for ( var staff = 0 ; staff*Tablature.NUMBER_OF_LINES < lines.length ; staff += 1 ) {
  136. staves[staff] = [];
  137. for ( var line = 0 ; line < Tablature.NUMBER_OF_LINES ; line++ ) {
  138. staves[staff][line] = lines[staff*Tablature.NUMBER_OF_LINES+line].match(new RegExp(".", "g"));
  139. }
  140. }
  141. Tablature.clear();
  142. for ( var staff = 0 ; staff < staves.length ; staff++ ) {
  143. Tablature._addStaff();
  144. Tablature._currentStaffNumber = staff;
  145. for ( var line = 0 ; line < staves[staff].length ; line++ ) {
  146. Tablature._currentLineNumber = line;
  147. for ( var note = 1 ; note < staves[staff][line].length-1 ; note++ ) {
  148. Tablature._currentColumnNumber = note-1;
  149. Tablature.draw(staves[staff][line][note]);
  150. }
  151. }
  152. }
  153. Tablature._currentStaffNumber = 0;
  154. Tablature._currentColumnNumber = 0;
  155. Tablature._currentLineNumber = 0;
  156. Tablature._displayCursor();
  157. Tablature.hideImport();
  158. },
  159. move: function(direction) {
  160. Tablature._resetCursor();
  161. switch(direction) {
  162. case 'right':
  163. Tablature._currentColumnNumber = Math.min(
  164. Tablature.WIDTH - 1,
  165. Tablature._currentColumnNumber + Tablature._movingSpeed
  166. )
  167. break;
  168. case 'left':
  169. Tablature._currentColumnNumber = Math.max(
  170. 0,
  171. Tablature._currentColumnNumber - Tablature._movingSpeed
  172. )
  173. break;
  174. case 'down':
  175. Tablature._currentLineNumber = Math.min(
  176. Tablature.NUMBER_OF_LINES - 1,
  177. Tablature._currentLineNumber + 1
  178. )
  179. break;
  180. case 'up':
  181. Tablature._currentLineNumber = Math.max(
  182. 0,
  183. Tablature._currentLineNumber - 1
  184. )
  185. break;
  186. case 'next':
  187. Tablature._currentStaffNumber++;
  188. if ( Tablature._currentStaffNumber == Tablature._numberOfStaves ) {
  189. Tablature._addStaff();
  190. }
  191. break;
  192. case 'previous':
  193. if ( Tablature._currentStaffNumber == Tablature._numberOfStaves-1 ) {
  194. Tablature._deleteStaffIfEmpty();
  195. }
  196. Tablature._currentStaffNumber = Math.max(
  197. 0,
  198. Tablature._currentStaffNumber - 1
  199. )
  200. break;
  201. case 'start':
  202. Tablature._currentColumnNumber = 0;
  203. break;
  204. case 'end':
  205. Tablature._currentColumnNumber = Tablature.WIDTH - 1;
  206. break;
  207. ;
  208. }
  209. Tablature._displayCursor();
  210. },
  211. pasteColumn: function() {
  212. Tablature._getCurrentColumn().each( function(e,i) {
  213. e.set('text', Tablature._copiedColumn[i]);
  214. });
  215. },
  216. showImport: function() {
  217. $('import-content').value='';
  218. $('import-tab').setStyle('display','block');
  219. },
  220. _addStaff: function() {
  221. Tablature._numberOfStaves++;
  222. var newStaff = new Element('div', {
  223. 'class': 'staff-' + Tablature._numberOfStaves
  224. });
  225. for ( var line = 0; line < Tablature.NUMBER_OF_LINES; line++ ) {
  226. var newLine = new Element('p');
  227. newLine.adopt(Tablature.BORDER.clone())
  228. for ( var column = 0; column < Tablature.WIDTH; column++ ) {
  229. newLine.adopt(Tablature.LINE.clone());
  230. }
  231. newLine.adopt(Tablature.BORDER.clone())
  232. newStaff.adopt(newLine);
  233. }
  234. $('tab').adopt(newStaff);
  235. },
  236. _deleteStaffIfEmpty: function() {
  237. if ( Tablature._numberOfStaves > 1 ) {
  238. var isEmpty = Tablature._getCurrentLines().every( function(e, i) {
  239. return e.getElements('span').every( function(n, i) {
  240. return n.get('text') == '-';
  241. })
  242. })
  243. if ( isEmpty ) {
  244. Tablature._getCurrentStaff().destroy();
  245. Tablature._numberOfStaves--;
  246. }
  247. }
  248. },
  249. _displayCursor: function() {
  250. Tablature._getCurrentColumn().each( function(e, i) {
  251. e.addClass('active');
  252. if ( i == Tablature._currentLineNumber )
  253. e.addClass('current');
  254. });
  255. $('position').set('text', '{column}/{max} ({staff}/{staves})'.substitute({
  256. column: Tablature._currentColumnNumber + 1,
  257. max: Tablature.WIDTH,
  258. staff: Tablature._currentStaffNumber + 1,
  259. staves: Tablature._numberOfStaves
  260. }));
  261. },
  262. _getCurrentColumn: function() {
  263. var lines = [];
  264. Tablature._getCurrentLines().each( function(e, i) {
  265. lines[i] = e.getElements('span')[Tablature._currentColumnNumber];
  266. });
  267. return lines;
  268. },
  269. _getCurrentLines: function() {
  270. return Tablature._getCurrentStaff().getElements('p');
  271. },
  272. _getCurrentNote: function() {
  273. return Tablature._getCurrentLines()[Tablature._currentLineNumber]
  274. .getElements('span')[Tablature._currentColumnNumber];
  275. },
  276. _getCurrentStaff: function() {
  277. return Tablature._getStaff(Tablature._currentStaffNumber);
  278. },
  279. _getStaff: function(staffNumber) {
  280. return $('tab').getElements('div')[staffNumber];
  281. },
  282. _onClick: function(e) {
  283. if ( e.target.get('tag') == 'span' ) {
  284. Tablature._resetCursor();
  285. var currentCell = e.target;
  286. var currentLine = currentCell.getParent();
  287. var currentStaff = currentLine.getParent();
  288. var columnIndex = currentLine.getElements('span').indexOf(currentCell);
  289. var lineIndex = currentStaff.getElements('p').indexOf(currentLine);
  290. var staffIndex = $('tab').getElements('div').indexOf(currentStaff);
  291. Tablature._currentStaffNumber = staffIndex;
  292. Tablature._currentLineNumber = lineIndex;
  293. Tablature._currentColumnNumber = columnIndex;
  294. Tablature._displayCursor();
  295. }
  296. },
  297. _onMouseOver: function(e) {
  298. if ( e.target.get('tag') == 'span' ) {
  299. $('tab').getElements('.selected')
  300. .removeClass('selected');
  301. e.target.addClass('selected');
  302. }
  303. },
  304. _resetCursor: function() {
  305. Tablature._getCurrentStaff().getElements('.active')
  306. .removeClass('active')
  307. .removeClass('current');
  308. },
  309. _showExport: function() {
  310. $('export-tab').setStyle('display','block');
  311. },
  312. _setMovingSpeed: function(newSpeed) {
  313. Tablature._movingSpeed = Math.min(
  314. Math.ceil(newSpeed),
  315. Tablature.MAX_SPEED
  316. );
  317. $('moving-speed').set('text', Tablature._movingSpeed);
  318. }
  319. }
  320. var Command = {
  321. readInput: function(e) {
  322. //console.log( e.code + ': ' + e.key );
  323. var recognisedEvent = true;
  324. switch(e.key) {
  325. case '+':
  326. Tablature.changeSpeed('increase');
  327. break;
  328. case '-':
  329. Tablature.changeSpeed('decrease');
  330. break;
  331. case 'right':
  332. case 'left':
  333. case 'up':
  334. case 'down':
  335. Tablature.move(e.key);
  336. break;
  337. case 'h':
  338. case 'p':
  339. case 't':
  340. case 'b':
  341. case '/':
  342. case '\\':
  343. Tablature.draw(e.key);
  344. break;
  345. case 'c':
  346. Tablature.copyColumn();
  347. break;
  348. case 'v':
  349. Tablature.pasteColumn();
  350. break;
  351. case 'e':
  352. Tablature.export();
  353. break;
  354. case 'i':
  355. Tablature.showImport();
  356. break;
  357. case 'space':
  358. Tablature.move('next');
  359. break;
  360. case 'enter':
  361. Tablature.drawBar();
  362. break;
  363. case 'esc':
  364. Tablature.hideExport();
  365. Tablature.hideImport();
  366. break;
  367. default:
  368. switch(e.code) {
  369. case 33: // PgUp
  370. Tablature.move('previous');
  371. break;
  372. case 34: // PgDwn
  373. Tablature.move('next');
  374. break;
  375. case 36: // Start
  376. Tablature.move('start');
  377. break;
  378. case 35: // End
  379. Tablature.move('end');
  380. break;
  381. case 48: // 0
  382. case 49: // 1
  383. case 50: // 2
  384. case 51:
  385. case 52:
  386. case 53:
  387. case 54:
  388. case 55:
  389. case 56:
  390. case 57: // 9
  391. Tablature.draw(e.key);
  392. break;
  393. case 46: // Numpad delete
  394. if ( Tablature._getCurrentNote().get('text') == '|' ) {
  395. Tablature.eraseColumn();
  396. } else {
  397. Tablature.draw('-');
  398. }
  399. break;
  400. case 42: // Numpad *
  401. Tablature.draw('X');
  402. break;
  403. default:
  404. recognisedEvent = false;
  405. ;
  406. }
  407. break;
  408. ;
  409. }
  410. if ( recognisedEvent ) {
  411. e.preventDefault();
  412. }
  413. }
  414. }
  415. window.addEvent('domready', Tablature.initialise);
  416. window.addEvent('keydown', Command.readInput); // don't use keypress or event.keys will be wrong !
  417. //]]>
  418. </script>
  419. <style type="text/css">
  420. /*
  421. Syntax { display/position
  422. ; size/margin
  423. ; border
  424. ; colour
  425. ; text
  426. }
  427. In vim, use 'AlignCtrl l:' and 'Align { ; }'
  428. */
  429. /* tags */
  430. html, body { margin: 0; padding: 0
  431. ; font-family: Verdana,sans-serif; font-size: 11pt
  432. }
  433. div { margin: 20px 0 }
  434. p { margin: 0 }
  435. h1 { margin: 5px 0 0 0
  436. ; font-family: Georgia,fantasy; font-style: italic; font-size: 130%
  437. ; text-align: center
  438. }
  439. h2 { margin: 0
  440. ; font-family: Georgia,fantasy; font-style: italic; font-size: 120%
  441. ; text-align: center
  442. }
  443. h3 { margin: 10px 0 0
  444. ; border: 1px dotted #E3E3E3; border-width: 0 0 1px
  445. ; font-family: Georgia,fantasy; font-style: italic; font-size: 110%
  446. ; text-align: right
  447. }
  448. ul { margin: 0
  449. ; list-style-type: none
  450. }
  451. li { margin: 0; padding: 0
  452. ; border: 1px solid #E3E3E3; border-width: 1px 0 0 0
  453. }
  454. a { color: inherit; background-color: inherit
  455. ; border: 1px dotted black; border-width: 0 0 1px 0
  456. ; text-decoration: none }
  457. a:focus { border-width: 0 }
  458. /* ids */
  459. #tools { position: fixed; top: 0;
  460. ; height: 36px; width: 100%; margin: 0; padding: 0 5px
  461. ; border: 1px solid black; border-width: 0 0 1px 0
  462. ; background-color: #FFFFE3; color: inherit
  463. ; font-size: 70%
  464. }
  465. #copyright { position: fixed; bottom: 0;
  466. ; height: 26px; width: 100%; margin: 0; padding: 0 5px
  467. ; border: 1px solid black; border-width: 1px 0 0 0
  468. ; background-color: #FFFFE3; color: inherit
  469. ; font-size: 60%; text-align: center
  470. }
  471. #tab { margin: 46px 10px 36px 10px
  472. ; cursor: pointer
  473. }
  474. #help { position: fixed
  475. ; right: 0px; width: 200px; padding: 5px; margin: 0 10px
  476. ; border: 1px solid black;
  477. ; background-color: #FFFFE3; color: inherit
  478. ; font-size: 70%
  479. }
  480. #export-tab,
  481. #import-tab { position: absolute
  482. ; left:10px; right: 230px; margin:0; padding: 5px; height: 300px
  483. ; border: 1px solid black; background-color: #E3E3E3; color: inherit
  484. }
  485. #close-export,
  486. #close-import { float: right
  487. ; font-size: 70%
  488. }
  489. #export-content,
  490. #import-content { height:80% }
  491. /* classes */
  492. .active { background-color: #E3E3FF; color: inherit }
  493. .current { background-color: #8888FF; color: inherit }
  494. .selected { background-color: #E3FFE3; color: inherit }
  495. .generic-command { font-style: italic }
  496. /* advanced */
  497. #tools dl { margin: 0 }
  498. #tools dt { display: inline
  499. ; margin-left: 10px
  500. ; font-weight: bold
  501. }
  502. #tools dd { display: inline
  503. ; padding: 0 10px 0 5px; margin: 0 0 0 0
  504. ; border: 1px solid #E3E3E3; border-width: 0 1px 0 0
  505. }
  506. #help dl { margin: 0 }
  507. #help dt { float: left
  508. ; padding: 0 5px 0 0; margin: 0
  509. ; width: 70px
  510. ; border: 1px dotted #E3E3E3; border-width: 0 1px 0 0
  511. ; font-weight: bold; text-align: right; white-space: nowrap
  512. }
  513. #help dd { overflow:hidden
  514. ; padding: 0 0 0 5px; margin: 0
  515. }
  516. </style>
  517. </head>
  518. <body>
  519. <div id="tools">
  520. <h1>TablatureJS v0.1.0 (2010/12/20)</h1>
  521. <dl>
  522. <dt>Speed</dt>
  523. <dd id="moving-speed"></dd>
  524. <dt>Position</dt>
  525. <dd id="position"></dd>
  526. <dt>Actions</dt>
  527. <dd><a href="#" id="export">Export</a></dd>
  528. <dd><a href="#" id="import">Import</a></dd>
  529. </dl>
  530. </div>
  531. <div id="export-tab">
  532. <a href="#" id="close-export">[Close]</a>
  533. <textarea id="export-content" cols="80"></textarea>
  534. </div>
  535. <div id="import-tab">
  536. <a href="#" id="close-import">[Close]</a>
  537. <textarea id="import-content" cols="80"></textarea>
  538. <br />
  539. <button id="save-import">Save</button>
  540. </div>
  541. <div id="help">
  542. <h2>Quick Help</h2>
  543. <h3>Motion</h3>
  544. <dl>
  545. <dt class="generic-command">arrow</dt>
  546. <dd>move around</dd>
  547. <dt class="generic-command">mouse click</dt>
  548. <dd>move around</dd>
  549. <dt>page up</dt>
  550. <dd>move to previous</dd>
  551. <dt>page down</dt>
  552. <dd>move to next staff</dd>
  553. <dt>space</dt>
  554. <dd>move to next staff</dd>
  555. <dt>start</dt>
  556. <dd>move to first column</dd>
  557. <dt>end</dt>
  558. <dd>move to last column</dd>
  559. <dt>+</dt>
  560. <dd>increase speed</dd>
  561. <dt>-</dt>
  562. <dd>decrease speed</dd>
  563. </dl>
  564. <h3>Edition</h3>
  565. <dl>
  566. <dt class="generic-command">number</dt>
  567. <dd>input note</dd>
  568. <dt>h</dt>
  569. <dd>input hammer</dd>
  570. <dt>p</dt>
  571. <dd>input pulloff</dd>
  572. <dt>t</dt>
  573. <dd>input tapping</dd>
  574. <dt>b</dt>
  575. <dd>input bend</dd>
  576. <dt>/</dt>
  577. <dd>input slide up</dd>
  578. <dt>\</dt>
  579. <dd>input slide down</dd>
  580. <dt>*</dt>
  581. <dd>input mute</dd>
  582. <dt>enter</dt>
  583. <dd>add bar</dd>
  584. <dt>delete</dt>
  585. <dd>delete note</dd>
  586. <dt>c</dt>
  587. <dd>copy bar</dd>
  588. <dt>v</dt>
  589. <dd>paste bar</dd>
  590. </dl>
  591. <h3>Special</h3>
  592. <dl>
  593. <dt>e</dt>
  594. <dd>export</dd>
  595. <dt>i</dt>
  596. <dd>import</dd>
  597. </dl>
  598. </div>
  599. <pre id="tab"></pre>
  600. <p id="copyright">
  601. <em>TablatureJS</em> is a program to edit Tablatures in a web browser.<br />
  602. <em>TablatureJS</em> is available under GPLv3 license.
  603. You can redistribute it or modify it freely.
  604. See <a href="http://en.wikipedia.org/wiki/GNU_General_Public_License">
  605. this page</a> for further details.
  606. </p>
  607. </body>
  608. </html>