選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

417 行
8.7KB

  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.Window 2.2
  19. import QtQuick.Controls 1.2
  20. import QtQuick.Dialogs 1.2
  21. import QtQml 2.2
  22. import art.freakaria.ton 1.0
  23. Window {
  24. id: root
  25. visible: true
  26. width:900;height:400
  27. Rectangle {
  28. anchors.fill:parent
  29. color:Qt.hsla(.5,0,1,.5)
  30. }
  31. Item {
  32. id:buffer
  33. property var spectrumR0: []
  34. property var spectrumR1: []
  35. property var spectrumF0: [110, 1, 220, 0.5, 330, 0.25, 440, 0.125, 550, 0.1, 660, 0.1, 770, 0.1, 880, 0.1]
  36. property var spectrumF1: []
  37. property var gridTunedStep:9
  38. property var gridPitch:440
  39. property var gridLowest:27
  40. property var gridHighest:8000
  41. property var grid:[0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100]
  42. onGridChanged: {
  43. keyboard.calculate_spectrum()
  44. }
  45. onSpectrumR0Changed:{spectrumR1 = spectrumR0 }
  46. onSpectrumF0Changed:{
  47. dissonanceCalculator.prepare_spectrum()
  48. }
  49. }
  50. Item {
  51. width: 300//Math.min(parent.width, parent.height)
  52. height:300//Math.min(parent.width, parent.height)
  53. SpiralView {
  54. id:spiral
  55. anchors.fill:parent
  56. paintAxes:true
  57. paintGrid:true
  58. fBase:27.5 // sub kontra A
  59. octaves:8
  60. gridTunedStep:buffer.gridTunedStep
  61. gridPitch:buffer.gridPitch
  62. gridLowest:buffer.gridLowest
  63. gridHighest:buffer.gridHighest
  64. grid:buffer.grid
  65. peaks:buffer.spectrumF0
  66. }
  67. }
  68. Item {
  69. x:300;y:300
  70. width:600; height:100
  71. Keyboard {
  72. id:keyboard
  73. transpose:-2
  74. inSpectrum:buffer.spectrumR0
  75. onInSpectrumChanged: { calculate_spectrum() }
  76. }
  77. SpinBox {
  78. id:keyTranspose
  79. minimumValue: -5
  80. maximumValue: 8
  81. value:-2
  82. onValueChanged: {
  83. keyboard.transpose = value
  84. keyboard.calculate_spectrum()
  85. }
  86. anchors.right:parent.right
  87. }
  88. }
  89. Item {
  90. x:0;y:300
  91. width:300;height:100
  92. Rectangle {
  93. anchors.fill:parent
  94. color:"#fff"
  95. Column {
  96. Row {
  97. id:spiralDisplayOptions
  98. spacing:5
  99. CheckBox {
  100. text:qsTr("Raster")
  101. onCheckedChanged: { spiral.paintGrid=checked }
  102. checked:true
  103. }
  104. CheckBox {
  105. text:qsTr("Spirale")
  106. onCheckedChanged: { spiral.paintAxes=checked }
  107. checked:true
  108. }
  109. }
  110. Row {
  111. id:harmonicGenerator
  112. spacing:5
  113. SpinBox {
  114. id:nPartials
  115. onValueChanged: parent.update_spectrum()
  116. minimumValue: 1
  117. maximumValue: 81
  118. }
  119. CheckBox {
  120. id:filterEven
  121. text:qsTr("nur ungerade Teiltöne")
  122. onCheckedChanged:parent.update_spectrum()
  123. }
  124. SpinBox {
  125. id:inharmonicity
  126. onValueChanged: parent.update_spectrum()
  127. minimumValue:-999
  128. maximumValue:999
  129. value:0
  130. }
  131. function update_spectrum() {
  132. var y=[]
  133. var log2=Math.log(2)
  134. for(var i=1;i<=nPartials.value;i++) {
  135. if(filterEven.checked && ((i%2)==0)) continue;
  136. y.push(Math.pow(2+(inharmonicity.value/1000),Math.log(i)/log2))
  137. //y.push(i)
  138. y.push(1/i)
  139. }
  140. buffer.spectrumR0 = y
  141. }
  142. }
  143. Row {
  144. id:gridGenerator
  145. spacing:5
  146. Text { text:qsTr("Raster: von") }
  147. TextInput {
  148. text:"27"
  149. onEditingFinished:{buffer.gridLowest = text }
  150. validator: IntValidator{bottom:0; top:10000}
  151. selectByMouse:true
  152. }
  153. Text { text:qsTr("bis") }
  154. TextInput {
  155. text:"8000"
  156. onEditingFinished:{buffer.gridHighest= text }
  157. validator: IntValidator{bottom:0; top:20000}
  158. selectByMouse:true
  159. }
  160. Text { text:qsTr("Stimmton") }
  161. TextInput {
  162. text:"440"
  163. onEditingFinished:{buffer.gridPitch = text }
  164. validator: IntValidator{bottom:0; top:10000}
  165. selectByMouse:true
  166. }
  167. }
  168. }
  169. Row {
  170. id:mainMenu
  171. spacing:1
  172. anchors.bottom:parent.bottom
  173. Button {
  174. text:qsTr("AUDIO")
  175. onClicked: { audioWindow.visible=true }
  176. }
  177. Button {
  178. text:qsTr("CDC-5")
  179. onClicked: { cdc5Window.visible=true }
  180. }
  181. Button {
  182. text:qsTr("Skalen")
  183. onClicked: { scaleWindow.visible=true }
  184. }
  185. Button {
  186. text:qsTr("DB")
  187. onClicked: { databaseWindow.visible=true }
  188. width:50
  189. }
  190. }
  191. }
  192. }
  193. Cartesian {
  194. id: cartesian
  195. x:300; y:0
  196. height: 283; width: 600
  197. fillColor:"#fff"
  198. leftHz:55
  199. rightHz:8000
  200. logx:logToggle.checked
  201. paintGrid:cartesianGridToggle.checked
  202. paintFFT:audioWindow.visible
  203. gridTunedStep:buffer.gridTunedStep
  204. gridPitch:buffer.gridPitch
  205. gridLowest:buffer.gridLowest
  206. gridHighest:buffer.gridHighest
  207. grid:buffer.grid
  208. peaks:buffer.spectrumF0
  209. fftData: audio.audio.spectrum
  210. sampleRate:audio.audio.sampleRate
  211. pointerFreq:spiral.pointerFreq
  212. pointerAmp:spiral.pointerAmp
  213. Rectangle {
  214. width:4;height:4;radius:2;
  215. color:"red";
  216. x: parent.pointerPos.x
  217. y: parent.pointerPos.y
  218. }
  219. MouseArea {
  220. anchors.fill: parent
  221. hoverEnabled: true
  222. function getFreqAmp(x,y){
  223. var result = {"freq":0.0,"amp":0.0}
  224. result.freq=(parent.rightHz-parent.leftHz)/parent.width * x + parent.leftHz
  225. result.amp=Math.pow(10,y/parent.height*parent.dbFloor/20)
  226. return result;
  227. }
  228. onPositionChanged: {
  229. var pos = getFreqAmp(mouseX,mouseY);
  230. spiral.pointerFreq = pos.freq
  231. spiral.pointerAmp = pos.amp
  232. }
  233. }
  234. }
  235. Item {
  236. id:cartesianOptions
  237. width:600;height:20
  238. x:300;y:283
  239. Row {
  240. spacing:5
  241. CheckBox{
  242. id:logToggle
  243. text:qsTr("logarithmische Achse")
  244. }
  245. CheckBox {
  246. id:cartesianGridToggle
  247. text:qsTr("Raster")
  248. checked:true
  249. }
  250. }
  251. Item {
  252. anchors.right:parent.right
  253. width:120; height:17
  254. Row {
  255. spacing:5
  256. Text {text:qsTr("zeige")}
  257. TextInput {
  258. text:"55"
  259. onEditingFinished:{cartesian.leftHz = text }
  260. validator: IntValidator{bottom:0; top:10000}
  261. selectByMouse:true
  262. focus:true
  263. }
  264. Text { text:qsTr("bis") }
  265. TextInput {
  266. text:"8000"
  267. onEditingFinished:{cartesian.rightHz = text }
  268. validator: IntValidator{bottom:81; top:20000}
  269. selectByMouse:true
  270. focus:true
  271. }
  272. Text { text:qsTr("Hz") }
  273. }
  274. }
  275. }
  276. Window {
  277. id:scaleWindow
  278. title:qsTr("Skalen")
  279. visible:true
  280. width:170;height:400
  281. ScaleBrowser {
  282. id:scales
  283. anchors.fill:parent
  284. }
  285. }
  286. Window {
  287. id:audioWindow
  288. title:qsTr("Audio Analyse")
  289. visible:false
  290. width:700;height:200
  291. // onVisibleChanged: {}
  292. AudioSegment {
  293. id:audio
  294. anchors.fill:parent
  295. }
  296. }
  297. Window {
  298. id:databaseWindow
  299. title:qsTr("Datenbank")
  300. visible:false
  301. width:200;height:300
  302. SpectrumBrowser {
  303. id:spectra
  304. anchors.fill:parent
  305. }
  306. }
  307. Window {
  308. id:cdc5Window
  309. title:qsTr("Dissonanz Berechnungen")
  310. visible:false
  311. width:600;height:300
  312. property var grundton:440
  313. onGrundtonChanged: { dissonanceCalculator.prepare_spectrum() }
  314. Row {
  315. anchors.bottom:parent.bottom
  316. height:17
  317. spacing:5
  318. Text {
  319. text:qsTr("Grundton "+buffer.spectrumF0[0]+"Hz | ")
  320. }
  321. Text {
  322. text:qsTr("Maximal darstellbare Rauhigkeit")
  323. }
  324. TextInput {
  325. text:"0.5"
  326. onEditingFinished:{dissonanceCurve.maxDissonance = text }
  327. validator: DoubleValidator{bottom:0.000001; top:20;decimals:5}
  328. selectByMouse:true
  329. focus:true
  330. }
  331. }
  332. Dissonance {
  333. id:dissonanceCalculator
  334. function prepare_spectrum() {
  335. if (cdc5Window.visible) {
  336. var f=[];
  337. var a=[];
  338. for(var i=0;i<buffer.spectrumR1.length;i++){
  339. if (i%2) a.push(buffer.spectrumR1[i])
  340. else f.push(buffer.spectrumF0[0]*buffer.spectrumR1[i])
  341. }
  342. freqs=f;
  343. amps=a;
  344. buffer.gridHighest = buffer.gridHighest
  345. }
  346. }
  347. }
  348. Cartesian {
  349. id:dissonanceCurve
  350. height:parent.height-17;width:parent.width
  351. fillColor:"#333"
  352. leftHz:buffer.spectrumF0[0]*1
  353. rightHz:buffer.spectrumF0[0]*2.1
  354. paintDissonance:true
  355. paintGrid:true
  356. logx:true
  357. paintAxes:false
  358. paintFFT:false
  359. paintPeaks:false
  360. dissonance:dissonanceCalculator.dissonanceCurve
  361. gridTunedStep:buffer.gridTunedStep
  362. gridPitch:buffer.gridPitch
  363. gridLowest:buffer.gridLowest
  364. gridHighest:buffer.gridHighest
  365. grid:buffer.grid
  366. }
  367. }
  368. }