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.

258 lines
6.1KB

  1. // tonalisa - software to look at overtone-structures
  2. // Copyright (C) 2016 Dominik Schmidt-Philipp
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. //
  17. import QtQuick 2.3
  18. import QtQuick.Controls 1.2
  19. import QtQuick.LocalStorage 2.0
  20. Item {
  21. id: root
  22. width: parent.width; height:parent.height
  23. property alias model: scaleModel
  24. property alias list: scaleList
  25. property var db;
  26. Rectangle {
  27. anchors.fill: parent
  28. }
  29. Button {
  30. id: newScale
  31. text: "new"
  32. x:0;y:0
  33. onClicked: {
  34. scaleList.model.append({
  35. "name":"equal",
  36. "tunedStep":9,
  37. "pitch":440.0,
  38. "highest":0,
  39. "lowest":0,
  40. "cents":"[0,100,200,300,400,500,600,700,800,900,1000,1100]"
  41. });
  42. scaleList.currentIndex = scaleModel.count-1
  43. }
  44. }
  45. Button {
  46. id: updateScale
  47. text: "update"
  48. x:80;y:0
  49. onClicked: {
  50. scaleList.model.get(scaleList.currentIndex).name = sEname.text;
  51. scaleList.model.get(scaleList.currentIndex).tunedStep = sEtunedStep.text;
  52. scaleList.model.get(scaleList.currentIndex).pitch = sEpitch.text;
  53. scaleList.model.get(scaleList.currentIndex).lowest = sElowest.text;
  54. scaleList.model.get(scaleList.currentIndex).highest = sEhighest.text;
  55. scaleList.model.get(scaleList.currentIndex).cents = JSON.stringify(scaleEditor.centBuffer);
  56. }
  57. }
  58. Button {
  59. id: deleteScale
  60. text: "delete"
  61. anchors.right:parent.right;
  62. onClicked: {
  63. scaleList.model.remove(scaleList.currentIndex)
  64. }
  65. }
  66. Item {
  67. id: scaleEditor
  68. x:2;y:30
  69. width:parent.width/2-4
  70. height:parent.height-40
  71. property var index:0
  72. property var centBuffer:[]
  73. TextField {
  74. height:18
  75. x:10;y:0
  76. id: sEname
  77. }
  78. Text {x:120;y:0;text:"name" }
  79. TextField {
  80. height:18
  81. x:10;y:20
  82. id: sEpitch
  83. }
  84. Text {x:120;y:20;text:"ReferencePitch (Hz)" }
  85. TextField {
  86. height:18
  87. x:10;y:40
  88. id: sEtunedStep
  89. }
  90. Text {x:120;y:40;text:"index of tuned Step" }
  91. TextField {
  92. height:18
  93. x:10;y:60
  94. id: sEhighest
  95. }
  96. Text {x:120;y:60;text:"upper limit (Hz)" }
  97. TextField {
  98. height:18
  99. x:10;y:80
  100. id: sElowest
  101. }
  102. Text {x:120;y:80;text:"lower limit (Hz)" }
  103. ListView {
  104. id:sEcents
  105. x: 10;y:100
  106. height:200
  107. model:[10,20,30]
  108. delegate: Item {
  109. height:16
  110. TextField {
  111. height:16;width:40;
  112. text:modelData
  113. onTextChanged: {
  114. scaleEditor.centBuffer[index]=text
  115. }
  116. }
  117. Text { x:45; text: "cents" }
  118. }
  119. }
  120. }
  121. function initDatabase() {
  122. db = LocalStorage.openDatabaseSync(
  123. "ExtendedFrequencyToolDB",
  124. "0.2",
  125. "Scales and Spectra",
  126. 100000)
  127. db.transaction( function(tx) {
  128. console.log("... create 'scales' table")
  129. tx.executeSql(
  130. // all entries for scales are in cents, which are saved as REALs
  131. 'CREATE TABLE IF NOT EXISTS scales('
  132. +'id INTEGER,'
  133. +'name TEXT,'
  134. +'tunedStep INTEGER,'
  135. +'pitch REAL,' // Hz
  136. +'highest REAL,'
  137. +'lowest REAL,'
  138. +'cents TEXT)'
  139. )
  140. });
  141. }
  142. function storeData() {
  143. if(!db) { return; }
  144. db.transaction( function(tx) {
  145. for (var i=0;i<scaleModel.count;i++) {
  146. var item = scaleModel.get(i);
  147. var result = tx.executeSql('SELECT * FROM scales WHERE id = "'+i+'"');
  148. if(result.rows.length === 1) { // use update
  149. console.log("update")
  150. result = tx.executeSql('UPDATE scales SET name=?, tunedStep=?, pitch=?, highest=?, lowest=?, cents=? WHERE id="'+i+'"',[
  151. item.name,
  152. item.tunedStep,
  153. item.pitch,
  154. item.highest,
  155. item.lowest,
  156. item.cents
  157. ]);
  158. } else { // use insert
  159. console.log("insert")
  160. result = tx.executeSql('INSERT INTO scales VALUES (?,?,?,?,?,?,?)',[
  161. i,
  162. item.name,
  163. item.tunedStep,
  164. item.pitch,
  165. item.highest,
  166. item.lowest,
  167. item.cents
  168. ])
  169. }
  170. }
  171. });
  172. }
  173. function readData() {
  174. if(!db){return;}
  175. db.transaction( function(tx){
  176. console.log("... read data from 'scale' table")
  177. var result = tx.executeSql('SELECT * FROM scales');
  178. if ( result.rows.length > 0 ) {
  179. for ( var i=0;i<result.rows.length;i++ ) {
  180. scaleList.model.append(result.rows.item(i))
  181. }
  182. } else {
  183. console.log("no scales in database")
  184. }
  185. });
  186. }
  187. Component.onCompleted: {
  188. initDatabase();
  189. readData();
  190. }
  191. Component.onDestruction: {
  192. storeData()
  193. }
  194. ListModel {
  195. id:scaleModel
  196. }
  197. ListView {
  198. id:scaleList
  199. anchors.fill:parent
  200. anchors.margins: 2
  201. anchors.leftMargin:parent.width/2+2
  202. anchors.topMargin:20
  203. clip:true
  204. model:scaleModel
  205. delegate:scaleDelegate
  206. spacing:1
  207. focus:true
  208. onCurrentItemChanged: {
  209. var item = scaleModel.get(currentIndex);
  210. // populate editor
  211. sEname.text = item.name
  212. sEpitch.text = item.pitch
  213. sEtunedStep.text = item.tunedStep
  214. sElowest.text = item.lowest
  215. sEhighest.text = item.highest
  216. sEcents.model=JSON.parse(item.cents)
  217. spiral.gridTunedStep = item.tunedStep
  218. spiral.gridLowest = item.lowest
  219. spiral.gridHighest = item.highest
  220. spiral.gridPitch = item.pitch
  221. spiral.grid = JSON.parse(item.cents)
  222. karthesisch.gridTunedStep = item.tunedStep
  223. karthesisch.gridLowest = item.lowest
  224. karthesisch.gridHighest = item.highest
  225. karthesisch.gridPitch = item.pitch
  226. karthesisch.grid = JSON.parse(item.cents)
  227. dissonanceCurve.gridTunedStep = item.tunedStep
  228. dissonanceCurve.gridLowest = item.lowest
  229. dissonanceCurve.gridHighest = item.highest
  230. dissonanceCurve.gridPitch = item.pitch
  231. dissonanceCurve.grid = JSON.parse(item.cents)
  232. buffer.grid = JSON.parse(item.cents)
  233. }
  234. }
  235. Component {
  236. id: scaleDelegate
  237. ScaleListElement {
  238. text:name
  239. }
  240. }
  241. }