waw to midi

Programme en C++ Qt6 basé directement sur la transformée de Fourier rapide. Retrouve les notes de musique (et leur code midi) à partir d'un fichier audio (fichier.wav)
Ce fichier source doit être stéréo échantillonné à 48kb/s, ce qui peut être facilement obtenu avec le soft avidemux (par exemple), éventuellement après extraction de la piste audio d'une vidéo .mp4.

1 Vue d'ensemble



Les notes obtenues peuvent être rejouées, les durées et le rythme sont pris en compte

2 Scan en cours (Transformée de fourier d'un échantillon de signal)

3 Aperçu en vidéo


A voir directement sur Youtube en 1080p pour voir les détails !!!

4 Le code source 'wav to midi' en C++ Qt6: fichier mainwindow.cpp

CODE SOURCE en C++
  1. /* top
  2.   Calcul de la transformée de Fourier rapide d'un signal audio au format PCM enregistré dans un fichier .wav
  3.   Format WAVE, RIFF, fmt échantilloné à 48000Hz
  4.  
  5.   Format : Wave
  6.   File size : 2.39 MiB
  7.   Duration : 13 s 54 ms
  8.   Overall bit rate mode : Constant
  9.   Overall bit rate : 1 536 kb/s
  10.  
  11.   Audio
  12.   Format : PCM
  13.   Format settings : Little / Signed
  14.   Codec ID : 1
  15.   Duration : 13 s 54 ms
  16.   Bit rate mode : Constant
  17.   Bit rate : 1 536 kb/s
  18.   Channel(s) : 2 channels
  19.   Sampling rate : 48.0 kHz
  20.   Bit depth : 16 bits
  21.   Stream size : 2.39 MiB (100%)
  22.  
  23.   Programme écrit par Silicium628
  24.   ce logiciel est libre et open source
  25. */
  26. /*
  27. ***** RAPPEL**** (source: https://helpx.adobe.com/fr/audition/using/digitizing-audio.html) **
  28. Taux d’échantillonnage Niveau de qualité Plage de fréquences
  29.  
  30. 11,025 Hz Faible qualité radio AM (multimédia bas de gamme) 0- 5 512 Hz
  31. 22,050 Hz Comparable à la qualité radio FM (multimédia haut de gamme) 0-11 025 Hz
  32. 32 000 Hz Meilleur que la qualité radio FM (taux de diffusion standard) 0-16 000 Hz
  33. 44 100 Hz CD 0-22 050 Hz
  34. 48 000 Hz DVD standard 0-24 000 Hz
  35. 96 000 Hz DVD Blu-ray 0-48 000 Hz
  36. *********************************************************************************************/
  37. /*
  38. Le présent logiciel est paramétré pour traiter les fichiers audio ECHANTILLONES à 48000Hz (qualité DVD)
  39. ET PAS 44.1 !!
  40. Je le rendrai compatible avec les autres taux, mais pour l'instant il faut enregistrer
  41. au préalable l'audio à traiter avec un taux de 48kHz
  42. (par exemple avec Audacity, c'est facile voir en bas à gauche de sa fenêtre).
  43. */
  44.  
  45.  
  46. #include "mainwindow.h"
  47. #include "ui_mainwindow.h"
  48. #include "math.h"
  49. #include "complexe.cpp"
  50.  
  51. #include <QMessageBox>
  52. #include <QFileDialog>
  53. #include <QFile>
  54. //#include <QImage>
  55.  
  56. #include <QtMultimedia/QMediaPlayer>
  57. #include <QAudioOutput>
  58.  
  59. #include <QMouseEvent>
  60. #include <QDateTime>
  61. #include <QScrollBar>
  62.  
  63.  
  64. /* FFT_wav */
  65.  
  66. QString version = "34.4";
  67.  
  68. /* todo:
  69. - clic trop haut en dehors du cadre -> note MI 40 au lieu de rien
  70.  
  71. */
  72.  
  73. int write_mode =0;
  74.  
  75. QString couleur_ecran = "#141414";
  76. QString couleur_ligne = "#878787";
  77. QString couleur_trace1 = "#0EA004";
  78. QString couleur_trace2 = "#00FFFF";
  79. QString couleur_curseur = "#FFFF00";
  80. QString couleur_texte = "#FFFF00"; // JAUNE
  81. QString couleur_encadrement = "#FF0000"; // ROUGE
  82.  
  83. QPen pen_ligne(QColor(couleur_ligne), 1, Qt::SolidLine);
  84. QPen pen_trace1(QColor(couleur_trace1), 1, Qt::SolidLine);
  85. QPen pen_trace2(QColor(couleur_trace2), 1, Qt::SolidLine);
  86. QPen pen_curseur(QColor(couleur_curseur), 1, Qt::SolidLine);
  87. QPen pen_reticule(QColor(couleur_ligne), 1, Qt::SolidLine);
  88. QPen pen_encadrement(QColor(couleur_encadrement), 1, Qt::SolidLine);
  89.  
  90. char temp_entete[100]; // signal entete lu dans le fichier .wav
  91. char temp_data[2000000]; // signal audio lu dans le fichier .wav (max 2MB)
  92. int pas_echantillonage = 24;
  93.  
  94. Complexe ech[2048]; // nb_ech echantillons
  95. Complexe tab_X[2048]; // nb_ech valeurs traitées
  96. Complexe tab_W[2048];
  97. bool tableau_w_plein = false;
  98.  
  99. uint8_t table_FREQ_midi[2000][1]; // [t][num_raie]
  100. uint8_t table_amplitudes[2000][1];// [t][num_raie]
  101.  
  102. double facteur_compression=1.0;
  103.  
  104. double frequence1=400; // Hz
  105. double frequence2=400; // Hz
  106. double frequence3=100; // Hz
  107.  
  108. uint nb_etapes=10; // 10
  109. uint nb_ech = pow (2, nb_etapes); // nombre d'échantillons = 2 puissance(nb_etapes) ->2^10 = 1024
  110.  
  111. float table_modules_FFT[1024]; // = 2^10
  112.  
  113. float x_clic_ecran, y_clic_ecran;
  114.  
  115. int nb_tics;
  116. long T_i=0; // variable GLOBALE
  117. int n_player=1;
  118. double seuil;
  119. double gain =1.0;
  120. int num_note_depart;
  121. int num_note_jouee=0;
  122. int nb_acc=0;
  123. int num_note_max=0;
  124. double memo_scroll_x=0;
  125. QDateTime temps_0; // départ du jeu des notes
  126. bool hamming = true;
  127. bool bourrage_de_zeros = true;
  128. bool second_Frq = false;
  129. bool bz = true;
  130. bool modul = false;
  131.  
  132. // type de mesure noté Ta/Tb (4/4, 3/2 ...)
  133. int Ta = 4;
  134. int Tb = 4;
  135.  
  136. //QList<int> index_midi; // position x des notes midi sur le graphe FFT (à partir de midi=40)
  137. QList<QString> liste_couleurs;
  138. QList<ENR_FFT> liste_ENR_FFT; // liste de "notes" détectées (maximums de FFT)
  139. QList<NOTE> liste_NOTES;
  140. QList<QString> noms_notes;
  141. QList<QString> gamme_chromatique;
  142. QList<QString> gamme_chromatique_GB;
  143.  
  144.  
  145. QFile file_wav; // fichier à analyser
  146. QFile file_dat; // datas du TAB_FRQ
  147.  
  148. QDir currentDir;
  149. QString base_Dir;
  150. QString default_Dir = "/home/";
  151. QString string_currentDir = default_Dir; // à priori; sera mis à jour lors de la lecture du fichier 'params.ini'
  152. QString string_currentFile;
  153. QString nom_fichier_in="";
  154.  
  155. QDataStream binStream1;
  156.  
  157. float duree; // calculée dans la fonction 'decode_entete'
  158. float data_size; // calculée dans la fonction 'decode_entete'
  159.  
  160. bool wav_ok = false;
  161. bool dossier_de_travail_ok = false;
  162. bool data_nts_ok = false;
  163. bool rapide = false;
  164. bool etendre = true;
  165. bool visu_notes = true;
  166. bool visu_freq = true;
  167. bool visu_ech_tps;
  168. bool visu_mesures;
  169. bool visu_duree_notes = true;
  170. bool lecture_en_cours = false;
  171.  
  172. uint32_t offset_t;
  173. float zoom_x =1.0;
  174.  
  175.  
  176. MainWindow::MainWindow(QWidget *parent) :
  177. QMainWindow(parent)
  178. {
  179. setupUi(this);
  180. setWindowTitle("Transformée de Fourier Rapide FFT - version " + version);
  181.  
  182. //this->setGeometry(0,0, 1900, 1000);
  183. setWindowState(Qt::WindowMaximized);
  184.  
  185. tabWidget_Global->setGeometry(0,0, 1920, 1280);
  186. tabWidget_Global->setCurrentIndex(0);
  187.  
  188. //-----------------------------------------------------
  189. // SCENE 1 - celle du haut ('Transformée de Fourier' ET 'partie échantillonée du signal')
  190.  
  191. scene1 = new QGraphicsScene(this);
  192. scene1->setBackgroundBrush(QColor(couleur_ecran));
  193. graphicsView1->setScene(scene1);
  194. graphicsView1->setGeometry(0, 0, 1900, 655); //( 0, 0, 1900, 700)
  195. graphicsView1->verticalScrollBar()->setValue(0);
  196.  
  197. calque_lignes_F_zero = new QGraphicsItemGroup();
  198. scene1->addItem(calque_lignes_F_zero);
  199.  
  200. calque_reticule1 = new QGraphicsItemGroup();
  201. scene1->addItem(calque_reticule1);
  202. afficher_titre_calque("Transformée de Fourier", 0, 0, calque_reticule1);
  203.  
  204. calque_trace_FFT = new QGraphicsItemGroup();
  205. scene1->addItem(calque_trace_FFT);
  206.  
  207. calque_trace_signal1 = new QGraphicsItemGroup();
  208. scene1->addItem(calque_trace_signal1);
  209.  
  210. calque_curseur = new QGraphicsItemGroup();
  211. scene1->addItem(calque_curseur);
  212.  
  213.  
  214. //-----------------------------------------------------
  215. // SCENE 2 - celle du bas ('Fichier Audio .wav')
  216.  
  217. scene2 = new QGraphicsScene(this);
  218. QBrush QB1("#222222");
  219. scene2->setBackgroundBrush(QB1); // couleur_ecran
  220.  
  221. graphicsView2->setScene(scene2);
  222. graphicsView2->setGeometry(0, 660, 1900, 200); // (0, 660, 1900, 200)
  223.  
  224. calque_trace_signal2 = new QGraphicsItemGroup();
  225. scene2->addItem(calque_trace_signal2);
  226.  
  227. calque_reticule2 = new QGraphicsItemGroup();
  228. scene2->addItem(calque_reticule2);
  229. afficher_titre_calque("Fichier Audio .wav", 0, -80, calque_reticule2);
  230.  
  231. calque_encadrement1 = new QGraphicsItemGroup();
  232. scene2->addItem(calque_encadrement1);
  233.  
  234. calque_encadrement2 = new QGraphicsItemGroup();
  235. scene2->addItem(calque_encadrement2);
  236.  
  237. //-----------------------------------------------------
  238. // SCENE 3 - LISTE verticale NOTES sur l'onglet NOTES
  239. scene3 = new QGraphicsScene(this);
  240. scene3->setBackgroundBrush(QColor(couleur_ecran));
  241. graphicsView3->setScene(scene3);
  242.  
  243. calque_gradu_TAB_FRQ = new QGraphicsItemGroup();
  244. scene3->addItem(calque_gradu_TAB_FRQ);
  245.  
  246. //-----------------------------------------------------
  247. // SCENE 4 - ANALYSE sur l'onglet NOTES
  248.  
  249. scene4 = new QGraphicsScene(this);
  250. scene4->setBackgroundBrush(QColor(couleur_ecran));
  251. graphicsView4->setScene(scene4);
  252. // graphicsView4->setEnabled(false); // pour empêcher le scrolling (pb: l'horizontal aussi !)
  253. // graphicsView4->setGeometry(10, 30, 1000, 690); // (10,30,1000,690)
  254.  
  255.  
  256. calque_grille_mesures = new QGraphicsItemGroup();
  257. scene4->addItem(calque_grille_mesures);
  258.  
  259. calque_TAB_FRQ = new QGraphicsItemGroup();
  260. scene4->addItem(calque_TAB_FRQ);
  261. afficher_titre_calque("Table Fréquences & notes", 200, 0, calque_TAB_FRQ);
  262.  
  263. calque_notes = new QGraphicsItemGroup();
  264. scene4->addItem(calque_notes);
  265.  
  266. calque_notes_jouee = new QGraphicsItemGroup();
  267. scene4->addItem(calque_notes_jouee);
  268.  
  269. calque_echelle_temporelle =new QGraphicsItemGroup();
  270. scene4->addItem(calque_echelle_temporelle);
  271.  
  272. //-----------------------------------------------------
  273.  
  274. Timer1 = new QTimer(this);
  275. connect(Timer1, SIGNAL(timeout()), this, SLOT(Tic1()));
  276.  
  277. Timer2 = new QTimer(this);
  278. connect(Timer2, SIGNAL(timeout()), this, SLOT(Tic2()));
  279.  
  280.  
  281. noms_notes<<"La"<<"Si"<<"Do"<<"Ré"<<"Mi" <<"Fa"<<"Sol"<<"--"<<"--"; // <- A B C D E F G
  282. gamme_chromatique<<"Do"<<"Do#"<<"Ré"<<"Mib"<<"Mi"<<"Fa"<<"Fa#"<<"Sol"<<"Sol#"<<"La"<<"Sib"<<"Si";
  283. gamme_chromatique_GB<<"C"<<"C#"<<"D"<<"Eb"<<"E"<<"F"<<"F#"<<"G"<<"G#"<<"A"<<"A#"<<"B";
  284.  
  285.  
  286. liste_couleurs <<"#EF2929"<<"#FF5C00"<<"#FCAF3E"<<"#FFE300"<<"#BFFF00"<<"#07F64F"
  287. <<"#16D298"<<"#16D2C4"<<"#00AEFF"<<"#1667D2"<<"#7C00FF"<<"#FF67EF"<<"#EEEEEC";
  288.  
  289. player1 = new QMediaPlayer;
  290. audioOutput1 = new QAudioOutput(this);
  291. player1->setAudioOutput(audioOutput1);
  292.  
  293. player2 = new QMediaPlayer;
  294. audioOutput2 = new QAudioOutput(this);
  295. player2->setAudioOutput(audioOutput2);
  296.  
  297. player3 = new QMediaPlayer;
  298. audioOutput3 = new QAudioOutput(this);
  299. player3->setAudioOutput(audioOutput3);
  300.  
  301. player4 = new QMediaPlayer;
  302. audioOutput4 = new QAudioOutput(this);
  303. player4->setAudioOutput(audioOutput4);
  304.  
  305. load_fichier_ini();
  306.  
  307. calcul_tableau_W();
  308. tracer_graduations_signal();
  309. tracer_graduations_FFT();
  310.  
  311. init_TW_1();
  312. init_TAB_FRQ();
  313. init_TAB_lst_notes();
  314. init_TW_type_M();
  315. init_Autres();
  316.  
  317. seuil = doubleSpinBox_seuil->value();
  318.  
  319. spinBox_offset->setValue(-2124); // 2124; +/- 22 pour un décalage de +/-1/4 de ton
  320. spinBox_echx->setValue(499);
  321. write_mode=0;
  322. on_Bt_mode_R_clicked();
  323.  
  324. visu_mesures = false;
  325. on_Bt_toggle_visu_mesures_clicked();
  326.  
  327. visu_ech_tps = true;
  328. on_Bt_toggle_visu_ech_tps_clicked();
  329.  
  330. visu_notes = false;
  331. on_Bt_toggle_visu_notes_clicked();
  332.  
  333. on_tableWidget_type_M_cellClicked(2, 0);
  334.  
  335. spinBox_zoom_2->setValue(2);
  336. // Bt_jouer_tout->setStyleSheet("background-color: rgb(200, 200, 200);");
  337.  
  338. progressBar_1->setValue(0);
  339.  
  340. }
  341.  
  342.  
  343. void MainWindow::init_TAB_FRQ()
  344. {
  345. frame_notes->setGeometry(0,0,1920,720);
  346.  
  347. graphicsView3->setGeometry(0, 30, 100, 730);
  348.  
  349. graphicsView4->setGeometry(100, 30, 2000, 730);
  350. graphicsView4->setEnabled(false); // empêche le recadrage auto par le contenu, mais disable le scroll manuel !
  351.  
  352. rectangle1 = new QGraphicsRectItem(0, 0, 2000, 670);
  353.  
  354. rectangle1->setPen(QColor(couleur_ligne));
  355. calque_TAB_FRQ->addToGroup(rectangle1);
  356. tracer_graduation_TAB_NOTES();
  357. tracer_grille_MESURES();
  358. }
  359.  
  360.  
  361. void MainWindow::init_TAB_lst_notes()
  362. {
  363. tableWidget_lst_notes->setGeometry(1000, 30, 450, 201);
  364. QStringList liste_entetes1;
  365. liste_entetes1<<"numéro"<<"midi"<<"note"<<"n° barre"<< "temps"<< "durée" << " ";
  366. tableWidget_lst_notes->setHorizontalHeaderLabels (liste_entetes1);
  367. tableWidget_lst_notes->setEditTriggers(QAbstractItemView::NoEditTriggers);
  368. }
  369.  
  370.  
  371.  
  372. void MainWindow::init_Autres()
  373. {
  374. frame_1->setGeometry(1250,865,410,131);
  375. frame_1->setVisible(false);
  376. frame_2->setGeometry(10,865,970,75);
  377. frame_3->setGeometry(1000,865,665,121);
  378. frame_5->setGeometry(0, 760, 1920, 260);
  379. frame_6->setGeometry(10, 950, 901, 40);
  380.  
  381. Bt_efface->setGeometry(915,950,60,21);
  382.  
  383. lineEdit_fichier_FREQ->setGeometry(1250, 0, 700, 26);
  384. Bt_efface_2->setGeometry(1165, 0, 81, 26);
  385. progressBar_1->setGeometry(98, 4, 101, 18); //(1085, 3, 78, 18);
  386. lineEdit_fichier->setGeometry(380, 40, 601, 26);
  387. groupBox_2->setGeometry(380, 70, 241, 161);
  388. groupBox_3->setGeometry(630, 70, 351, 161);
  389.  
  390. // groupBox_4->setGeometry(5, 5, 5, 5); // (215, 40, 155, 191)
  391.  
  392. textEdit_ETAT->setGeometry(1480, 30, 400, 200);
  393.  
  394. int x0 = 1500;
  395. Bt_debut->setGeometry(x0+0, 760, 80, 22);
  396. Bt_prev->setGeometry(x0+90, 760, 80, 22);
  397. Bt_next->setGeometry(x0+180, 760, 80, 22);
  398. Bt_fin->setGeometry(x0+270, 760, 80, 22);
  399.  
  400. tracer_gradu_temporelle_signal_entree();
  401. tracer_graduations_signal();
  402. }
  403.  
  404.  
  405. void MainWindow::init_TW_type_M()
  406. {
  407. frame_4->setGeometry(210, 40, 120, 120);
  408.  
  409. tableWidget_type_M->setGeometry(5, 20, 40, 70);
  410. lineEdit_10->setGeometry(60,30,51,26);
  411. label_8->setGeometry(2,2,111,20);
  412.  
  413. QStringList liste_labels; // pour mettre directement dans la 1ere colonne (et pas en entêtes)
  414. liste_labels << "2/4" << "3/4" << "4/4";
  415. for(int n=0; n<3; n++) { tableWidget_type_M->setItem(0, n, new QTableWidgetItem (liste_labels[n])); }
  416. }
  417.  
  418.  
  419. void MainWindow::init_TW_1() // affi entete du fichier wav
  420. {
  421. tableWidget_1->setGeometry(700, 200, 600, 300);
  422. Bt_close_entete->setGeometry(1280, 200, 20, 20);
  423. tableWidget_1->setColumnCount(6);
  424. tableWidget_1->setColumnWidth(4, 120);
  425. tableWidget_1->setColumnWidth(5, 130);
  426.  
  427. tableWidget_1->setVisible(false);
  428. Bt_close_entete->setVisible(false);
  429.  
  430. QStringList liste_entetes;
  431. liste_entetes <<"FileTypeBlocID"
  432. <<"FileSize"
  433. <<"FileFormatID"
  434. <<"FormatBlocID"
  435. <<"BlocSize"
  436. <<"AudioFormat"
  437. <<"NbrCanaux"
  438. <<"Frequence"
  439. <<"ECH (BytePerSec)"
  440. <<"BytePerBloc"
  441. <<"BitsPerSample"
  442. <<"DataBlocID"
  443. <<"DataSize"
  444. <<"durée calculée";
  445.  
  446. tableWidget_1->setVerticalHeaderLabels(liste_entetes);
  447. }
  448.  
  449.  
  450. void MainWindow::load_fichier_ini()
  451. {
  452. QString line;
  453. int p1, p2, p3;
  454.  
  455. dossier_de_travail_ok = false; // à priori
  456. QFile file1(QDir::currentPath() + "/" + "params_FFT.ini"); // dans le dossier de l'exécutable (= QDir::currentPath() )
  457. if (file1.open(QIODevice::ReadOnly | QIODevice::Text))
  458. {
  459. QTextStream in(&file1);
  460. in.reset();
  461. while ( !in.atEnd() )
  462. {
  463. line = in.readLine();
  464. if (line.at(0) !='#')
  465. {
  466. if ((p1 = line.indexOf("<currentDir>")) != -1)
  467. {
  468. p2 = line.indexOf('>',p1);
  469. p3 = line.indexOf("</",p2);
  470. QString s1 = line.mid(p2+1, p3-p2-1);
  471. string_currentDir = s1;
  472. dossier_de_travail_ok = true;
  473. }
  474.  
  475. if ((p1 = line.indexOf("<currentFile>")) != -1)
  476. {
  477. p2 = line.indexOf('>',p1);
  478. p3 = line.indexOf("</",p2);
  479. QString s1 = line.mid(p2+1, p3-p2-1);
  480. string_currentFile = s1;
  481. }
  482. }
  483. }
  484. file1.close();
  485. }
  486. else
  487. {
  488. QString s1 = "fichier .ini non trouvé, je le crée (dans le dossier de l'executable)";
  489. QMessageBox msgBox; msgBox.setText(s1); msgBox.exec();
  490. base_Dir=QDir::currentPath() + "/";
  491. save_fichier_ini();
  492. dossier_de_travail_ok = false;
  493. }
  494.  
  495. lineEdit_current_dir->setText(string_currentDir);
  496. lineEdit_fichier->setText(string_currentDir);
  497. }
  498.  
  499.  
  500.  
  501. QString calcul_couleur(float x) // x = 0.0 à 1.0 ; return: rouge->jaune->vert
  502. {
  503. QString coul_str ="#000000";
  504. QString coul_R_str="#000000";
  505. QString coul_V_str="#000000";
  506.  
  507. int R, V; // rouge, vert
  508.  
  509. V= x * 255;
  510. R= 300 - (1.2 * V);
  511.  
  512. float coxh;
  513. // la formule suivante met le jaune en valeur (avec un cosinus hyperbolique)
  514. coxh = 3.2 - 1.5 * cosh(2.6*x - 1.5); // merci kmplot (testez la courbe f(x) = 3.2 −1.5 * cosh(2.6x − 1.5) )
  515.  
  516. R *= coxh/1.2;
  517. V *= coxh/1.2;
  518.  
  519. coul_R_str.setNum(R, 16); coul_R_str = "0" + coul_R_str; coul_R_str = coul_R_str.right(2);
  520. coul_V_str.setNum(V, 16); coul_V_str = "0" + coul_V_str; coul_V_str = coul_V_str.right(2);
  521. coul_str = coul_R_str + coul_V_str;
  522. coul_str = "#" + coul_str + "00";
  523. return coul_str; // de la forme "#AABB00" (rouge & vert en exa, (bleu à zéro, à traiter))
  524. }
  525.  
  526.  
  527.  
  528. int MainWindow::calcul_y_note(int midi) // en pixels sur la grille
  529. {
  530. int y =700 - ((midi-40) * 16); // voir 'tracer_graduation_TAB_NOTES()' pour l'espacement vertical
  531. return y;
  532. }
  533.  
  534.  
  535.  
  536. int MainWindow::calcul_hauteur_note(int mid) // de 0 à 11
  537. {
  538. int h1;
  539. h1 = mid-40;
  540. h1 -=5;
  541. h1+=12;
  542. while(h1>=12) {h1-=12;}
  543. if (h1==12) {h1=0;}
  544. return h1; // h1 = 0..11
  545. }
  546.  
  547.  
  548. QString MainWindow::nom_note(int mid)
  549. {
  550. QString s1;
  551.  
  552. int h1 = calcul_hauteur_note(mid);
  553. h1-=3;
  554. if(h1<0){h1+=12;}
  555. if(h1>11){h1-=12;}
  556.  
  557. if((h1<0) || ( h1>= gamme_chromatique.length())) {return "-";}
  558. s1 = gamme_chromatique[h1];
  559. return s1;
  560. }
  561.  
  562.  
  563. QString MainWindow::nom_note_GB(int mid)
  564. {
  565. QString s1;
  566.  
  567. int h1 = calcul_hauteur_note(mid);
  568. h1-=3;
  569. if(h1<0){h1+=12;}
  570. if(h1>11){h1-=12;}
  571.  
  572. if((h1<0) || ( h1>= gamme_chromatique_GB.length())) {return "-";}
  573. s1 = gamme_chromatique_GB[h1];
  574. return s1;
  575. }
  576.  
  577.  
  578. QString MainWindow::nom_octave_GB(int mid)
  579. {
  580. QString octave;
  581. if((mid>=40)&&(mid < 48)) {octave = "2";}
  582. if((mid>=48)&&(mid < 60)) {octave = "3";}
  583. if((mid>=60)&&(mid < 72)) {octave = "4";}
  584. if((mid>=72)&&(mid < 90)) {octave = "5";}
  585. return octave;
  586. }
  587.  
  588.  
  589.  
  590. float freq_mid(int midi_i) // calcule la fréquence (en Hertz) d'une note à partir de son numéro midi
  591. {
  592. // https://fr.wikipedia.org/wiki/MIDI_Tuning_Standard
  593. float F, A;
  594. A=((float)midi_i-69.0)/12.0;
  595. F= 440 * powf(2,A);
  596. return F;
  597. }
  598.  
  599.  
  600. double calcul_id_midi(double freq_i) // complément de la fonction précédente ( float freq_mid(int midi_i) )
  601. {
  602. double id;
  603. id = 69.0 + 12.0 * log2(freq_i / 440.0);
  604. return id;
  605. }
  606.  
  607.  
  608. int MainWindow::calcul_num_midi(double x) // en fonction de la position horizontale dans le tableau d'affichage de la FFT
  609. {
  610. // on va détecter la note la plus proche de la position donnée
  611. // rappel : x=92 +(m-40) * 40.9 (voir la fonction : 'tracer_graduations_FFT()')
  612.  
  613. double dx;
  614. double xm;
  615.  
  616. for (int m=40; m<83; m++)
  617. {
  618. xm= 92.0 +(m-40) * 40.9;
  619. dx = xm-x;
  620. if (dx<0){dx=-dx;}
  621. if (dx < (40.9/2) )
  622. {
  623. encadrement_note(m);
  624. return m;
  625. }
  626. }
  627. return 0;
  628. }
  629.  
  630.  
  631. void MainWindow::play_note(int midi) // sortie audio
  632. {
  633. QString s1, freq_txt;
  634.  
  635. calcul_hauteur_note(midi);
  636. s1.setNum(midi);
  637.  
  638. s1="notes/"+s1+".wav"; // fichiers audio comprenant une seule note chacun, voir dans le dossier "notes" sur le HDD
  639.  
  640. if (n_player == 1) {player1->setSource(QUrl::fromLocalFile(s1)); player1->play();}
  641. if (n_player == 2) {player2->setSource(QUrl::fromLocalFile(s1)); player2->play();}
  642. if (n_player == 3) {player3->setSource(QUrl::fromLocalFile(s1)); player3->play();}
  643. if (n_player == 4) {player4->setSource(QUrl::fromLocalFile(s1)); player4->play();}
  644. if (n_player == 5) {player5->setSource(QUrl::fromLocalFile(s1)); player5->play();}
  645. n_player++;
  646. if (n_player >= 5) {n_player = 1;}
  647. }
  648.  
  649.  
  650.  
  651.  
  652. void MainWindow::effacer_calque(QGraphicsScene *scene_i, QGraphicsItemGroup *calque_i)
  653. {
  654. foreach( QGraphicsItem *item, scene_i->items( calque_i->boundingRect() ) )
  655. {if( item->group() == calque_i ) { delete item; }}
  656. }
  657.  
  658.  
  659. MainWindow::~MainWindow()
  660. {
  661.  
  662. }
  663.  
  664.  
  665.  
  666. void MainWindow::Etiquette(int x, int y, QString s, QString coul_txt, QString coul_fond, QString coul_bord,QGraphicsItemGroup *calque_i )
  667. {
  668. // fond noir sous le texte
  669. rect1 = new QGraphicsRectItem(x, y+4, 40, 18);
  670. rect1->setPen(QColor(coul_bord)); // bordure
  671. rect1->setBrush(QColor(coul_fond)); // fond
  672. calque_i->addToGroup(rect1);
  673.  
  674. //texte
  675. GraphicsTextItem = new QGraphicsTextItem(s);
  676. GraphicsTextItem->setPos(x, y);
  677. GraphicsTextItem->setDefaultTextColor(coul_txt);
  678. calque_i->addToGroup(GraphicsTextItem);
  679. }
  680.  
  681.  
  682.  
  683. void MainWindow::tracer_graduations_FFT() // sur onglet 'Source wav'
  684. {
  685. double x=0;
  686. QString s1;
  687. int y_bas =450; // 350
  688.  
  689. // cadre
  690. rectangle1 = new QGraphicsRectItem(0, 0, 1900, y_bas);
  691. QPen pen1("#12FF00");
  692. rectangle1->setPen(pen1);
  693.  
  694. calque_reticule1->addToGroup(rectangle1);
  695.  
  696. s1 = "midi :"; // numéro midi
  697. GraphicsTextItem = new QGraphicsTextItem(s1);
  698. GraphicsTextItem->setDefaultTextColor("#FFFFFF");
  699. GraphicsTextItem->setPos(30, 20);
  700. // if(x<1900)
  701. {
  702. calque_reticule1->addToGroup(GraphicsTextItem);
  703. }
  704.  
  705. // positions des notes midi
  706. x= 96;
  707. for(int m=40; m<=83; m++)
  708. {
  709. ligne1 = new QGraphicsLineItem(x, 70, x, y_bas);
  710. ligne1->setPen(pen_reticule);
  711. calque_reticule1->addToGroup(ligne1);
  712.  
  713. s1.setNum(m); // numéro midi
  714. GraphicsTextItem = new QGraphicsTextItem(s1);
  715. GraphicsTextItem->setDefaultTextColor("#D3D7CF");
  716. GraphicsTextItem->setPos(x-15, 20);
  717. if(x<1900) {calque_reticule1->addToGroup(GraphicsTextItem); }
  718.  
  719. int h1 = calcul_hauteur_note(m);
  720. h1-=3;
  721. if(h1<0){h1+=12;}
  722. if(h1>11){h1-=12;}
  723. if((h1<0) || ( h1>= gamme_chromatique.length())) {return;}
  724. s1 = " " + gamme_chromatique[h1]; // nom de la note
  725. GraphicsTextItem = new QGraphicsTextItem(s1);
  726. GraphicsTextItem->setDefaultTextColor(liste_couleurs[h1]);
  727. GraphicsTextItem->setPos(x-18, 40);
  728. if(x<1900) {calque_reticule1->addToGroup(GraphicsTextItem); }
  729.  
  730. x+=40.9; // espacement des graduation
  731. }
  732. }
  733.  
  734.  
  735.  
  736. float MainWindow::calcul_x_barre(int n_barre)
  737. {
  738. // calcul de l'abscisse (en pixel) d'une barre de mesure
  739.  
  740. float x0 = 100; // à voir !
  741. float pas_grille = doubleSpinBox_dt->value()/2.0 * zoom_x;
  742. float x = x0 + float(n_barre) * pas_grille;
  743. return x;
  744. }
  745.  
  746.  
  747.  
  748.  
  749. void MainWindow::tracer_grille_MESURES()
  750. {
  751. //grille temporelle (mesures et temps forts/faibles) sur le TAB NOTES (barres verticales)
  752. QString s1;
  753. QString bleu_clair = "#00AAFF";
  754. QString jaune = "#FFFF00";
  755. QString gris_clair = "#CCCCCC";
  756. QString gris_fonce = "#777777";
  757. QString gris_tres_fonce = "#444444";
  758. QString couleur_i;
  759. QPen pen_i;
  760. float x_i1;
  761.  
  762. int num_mesure;
  763.  
  764. effacer_calque(scene4, calque_grille_mesures);
  765.  
  766. if ( visu_mesures)
  767. {
  768. for(int n=0; n<=120*16; n++) //42
  769. {
  770. x_i1 = calcul_x_barre(n);
  771.  
  772. couleur_i = gris_tres_fonce; // à priori
  773. if ( n%(Ta/2) == 0) { couleur_i = gris_fonce; }
  774. if ( n%(4) == 0) { couleur_i = gris_clair; }
  775.  
  776. if ( n%(4*Ta) == 0) // 1er temps fort de la mmesure
  777. {
  778. // numérotation des mesures, en bas, chiffres jaunes
  779. num_mesure = n /Ta/4;
  780. s1.setNum(num_mesure);
  781. Etiquette(x_i1-10, 650, s1, "#FFFF00", "#000000", "#0000FF", calque_grille_mesures);
  782. }
  783. //if ( n%(4*m)== 0) {couleur_i = jaune;}
  784.  
  785. pen_i.setColor(couleur_i);
  786. ligne1 = new QGraphicsLineItem(x_i1, 0.0, x_i1, 700.0);//650
  787. ligne1->setPen(pen_i);
  788. calque_grille_mesures->addToGroup(ligne1);
  789.  
  790. if (n==0)
  791. {
  792. /* A REVOIR
  793.  
  794.   // représentation de la durée d'une NOIRE sous la forme d'un petit rectangle horizontal
  795.   // afin de bien visualiser le type de mesures à la clef : 2/4 .. 3/4 .. 4/4 .. etc
  796.   GraphicsTextItem = new QGraphicsTextItem("noire");
  797.   GraphicsTextItem->setDefaultTextColor("#AAAAAA");
  798.   GraphicsTextItem->setPos(x_i1+1.0, 595);
  799.   calque_grille_mesures->addToGroup(GraphicsTextItem);
  800.  
  801.   rect2 = new QGraphicsRectItem(x_i1+1.0, 620, (4.0 * pas_grille) -2, 5);
  802.  
  803.   QBrush br2; br2.setStyle(Qt::SolidPattern); br2.setColor("#222222");rect2->setBrush(br2);
  804.   pen_i.setColor("#FFFFFF");
  805.   rect2->setPen(pen_i);
  806.   calque_grille_mesures->addToGroup(rect2);
  807.   s1 += " <- n° mesure";
  808.   GraphicsTextItem = new QGraphicsTextItem(s1);
  809.   GraphicsTextItem->setDefaultTextColor("#FFFF00"); // jaune
  810.   GraphicsTextItem->setPos(x_i1-10.0, 650);
  811.   calque_grille_mesures->addToGroup(GraphicsTextItem);
  812.   */
  813. }
  814. }
  815. }
  816. }
  817.  
  818.  
  819. void MainWindow::afficher_titre_calque(QString titre, int x, int y, QGraphicsItemGroup *calque_i)
  820. {
  821. GraphicsTextItem = new QGraphicsTextItem(titre);
  822. GraphicsTextItem->setDefaultTextColor("#FFFFFF");
  823. GraphicsTextItem->setPos(x, y);
  824. calque_i->addToGroup(GraphicsTextItem);
  825. }
  826.  
  827.  
  828.  
  829. void MainWindow::tracer_graduation_TAB_NOTES() // midi ; en colonne à gauche + noms des notes
  830. {
  831. // positions des notes midi
  832. QString s1;
  833. int y= 640; //640
  834. for(int m=40; m<=82; m++)
  835. {
  836. //ligne1 = new QGraphicsLineItem(100, 0, 100, 350);
  837. //ligne1->setPen(pen_reticule);
  838. //calque_reticule1->addToGroup(ligne1);
  839.  
  840. s1.setNum(m); // numéro midi
  841. GraphicsTextItem = new QGraphicsTextItem(s1);
  842. GraphicsTextItem->setDefaultTextColor("#D3D7CF");
  843. GraphicsTextItem->setPos(0, y);
  844. if(y> -50) {calque_gradu_TAB_FRQ->addToGroup(GraphicsTextItem); }
  845.  
  846. int h1 = calcul_hauteur_note(m);
  847. h1-=3;
  848. if(h1<0){h1+=12;}
  849. if(h1>11){h1-=12;}
  850. if((h1<0) || ( h1>= gamme_chromatique.length())) {return;}
  851. s1 = " " + gamme_chromatique[h1]; // nom de la note
  852. GraphicsTextItem = new QGraphicsTextItem(s1);
  853. GraphicsTextItem->setDefaultTextColor(liste_couleurs[h1]);
  854. // GraphicsTextItem->setHtml("<div style='background-color:#666666;'>" + s1 + "</div>");
  855.  
  856. if (m==69) // La 440
  857. {
  858. rect3 = new QGraphicsRectItem(30, y+6, 40, 15);
  859. QBrush br2;
  860. QPen pen_i;
  861. pen_i.setColor("#AAAAAA");
  862. rect3->setPen(pen_i);
  863. calque_gradu_TAB_FRQ->addToGroup(rect3);
  864.  
  865. }
  866.  
  867. GraphicsTextItem->setPos(30, y);
  868. if(y > -50) {calque_gradu_TAB_FRQ->addToGroup(GraphicsTextItem); }
  869.  
  870. y-=16; // espacement des graduations
  871. }
  872. }
  873.  
  874.  
  875.  
  876. void MainWindow::tracer_graduations_signal() // sur le 1er onglet (Source.wav)
  877. {
  878. /*
  879.   midi57 = 110Hz
  880.   1/110Hz = 9ms -> delta x = 142-46 = 96px
  881.   echelle x = 96/9 = 10.6 px/ms
  882.   soit:
  883.   10ms -> 106px
  884. */
  885. double x;
  886. double nb_grad_max;
  887. double intervalle; // séparant les graduations
  888. QPen pen1;
  889. // int num_x;
  890. //QString sti;
  891. // uint decal = 3; // leger decallage vertical pour ne pas masquer la trace
  892.  
  893. /*
  894.   rectangle1 = new QGraphicsRectItem(5, 452, 1900, 200);
  895.   pen1.setColor("#0073FF");
  896.   rectangle1->setPen(pen1);
  897.   calque_reticule1->addToGroup(rectangle1);
  898.  
  899.   ligne1 = new QGraphicsLineItem(10, 475, 1900, 475); // ligne horizontale
  900.   pen1.setColor("#0073FF");
  901.   ligne1->setPen(pen1);
  902.   calque_reticule1->addToGroup(ligne1);
  903. */
  904. afficher_titre_calque("Partie échantillonée du signal", 0, 452, calque_reticule1);
  905.  
  906. // lignes verticales
  907.  
  908. intervalle = 106;
  909. nb_grad_max = 18;
  910.  
  911. for (int i=0; i<=nb_grad_max; i++)
  912. {
  913. x = intervalle * i;
  914.  
  915. ligne1 = new QGraphicsLineItem(x, 452, x, 780);
  916. ligne1->setPen(pen_reticule);
  917. }
  918.  
  919. /*
  920. // lignes horizontales
  921.   intervalle = 55;
  922.   nb_grad_max = 3;
  923.   for (i=0; i<=nb_grad_max; i++)
  924.   {
  925.   y = 300 - intervalle * i;
  926.  
  927.   ligne1 = new QGraphicsLineItem(0, y, 1350, y);
  928.   ligne1->setPen(pen_reticule);
  929.   calque_reticule1->addToGroup(ligne1);
  930.   }
  931.   texte_mid = new QGraphicsTextItem("Silicium628");
  932.   texte_mid->setDefaultTextColor(couleur_signature);
  933.   texte_mid->setPos(5,5);
  934.   calque_reticule1->addToGroup(texte_mid);
  935.  */
  936.  
  937. scene1->addItem(calque_reticule1);
  938. }
  939.  
  940.  
  941.  
  942. void MainWindow::tracer_gradu_temporelle_signal_entree()
  943. {
  944. // GRADUATION TEMPORELLE sur le signal d'entrée, en secondes
  945.  
  946. QString s1;
  947. int x=0;
  948. int dy = 75;
  949. float pas =8;
  950.  
  951. for(int n=0; n<1200; n++)
  952. {
  953.  
  954. if (n%10 == 0) { dy = 75; }
  955. else if (n%5 == 0) {dy = 20; }
  956. else {dy = 10;}
  957.  
  958. x = n *pas;
  959. ligne1 = new QGraphicsLineItem(x, -dy, x, dy);
  960. QPen P1("#AAAAAA");
  961. ligne1->setPen(P1);
  962. calque_reticule2->addToGroup(ligne1);
  963.  
  964. if (n%10 == 0)
  965. {
  966. s1.setNum(n/10);
  967. s1+="s";
  968. GraphicsTextItem = new QGraphicsTextItem(s1);
  969. GraphicsTextItem->setDefaultTextColor(couleur_texte);
  970. GraphicsTextItem->setPos(x,55);
  971. if(x<6000) {calque_reticule2->addToGroup(GraphicsTextItem); }//3000
  972. }
  973. }
  974. }
  975.  
  976.  
  977.  
  978. void MainWindow::tracer_signal_complet() // totalité du fichier wav (dans le cadre du bas du 1er onglet)
  979. {
  980. uint8_t octet_n;
  981. double R;
  982. double offset_y = 0.0;
  983. double echelle_y =2.0;
  984. double echelle =0.074;
  985.  
  986. int x, y, memo_x, memo_y;
  987. double min= 1000000.0;
  988. double max=-1000000.0;
  989.  
  990. int pas = 10 * pas_echantillonage; // 240;
  991. // le signal wav est échantillonné à l'origine à 96000 Bps (séréo 2*fois 48000 Bps)
  992. // en ne prenant qu'un octet sur 24 on obtient 4000 Bps.
  993. QString s1;
  994.  
  995. effacer_calque(scene2, calque_trace_signal2 );
  996. segment_trace = new QGraphicsLineItem(0, offset_y, 512, offset_y);
  997. QPen P1("#0000FF");
  998. segment_trace->setPen(P1); //couleur_ligne
  999. calque_trace_signal2->addToGroup(segment_trace);
  1000.  
  1001. x=0;
  1002. y=offset_y;
  1003. long n_max = 80000; // (2 000 000/25 = 80 000) voir le fonction 'garnis_temp_data()'
  1004.  
  1005. long n;
  1006. long i=0;
  1007. int j=0;
  1008.  
  1009. for(n=0; n<n_max; n+=10)
  1010. {
  1011. memo_x = x;
  1012. memo_y = y;
  1013. x = echelle * n;
  1014.  
  1015. octet_n = temp_data[i]; // canal 1
  1016. R = octet_n - 128; // pour oter la composante continue propre au codage par des octets non signés
  1017. R *= echelle_y;
  1018. y=offset_y + R;
  1019.  
  1020. // recherche du mini-maxi:
  1021. if (y < min) {min = y;}
  1022. if (y > max) {max = y;}
  1023.  
  1024. // if (x<3000)
  1025. {
  1026. segment_trace = new QGraphicsLineItem(memo_x ,memo_y, x, y);
  1027. QPen P1("#0055FF");
  1028. segment_trace->setPen(P1);
  1029. calque_trace_signal2->addToGroup(segment_trace);
  1030. }
  1031.  
  1032. i+= pas; // le nb de pas étant pair, on retombe toujours sur le même canal (droite ou gauche)
  1033. j++;
  1034. }
  1035. //scene1->addItem(calque_trace_signal);
  1036. s1.setNum(min);
  1037. //lineEdit_4->setText(s1);
  1038. s1.setNum(max);
  1039. // lineEdit_5->setText(s1);
  1040. }
  1041.  
  1042.  
  1043.  
  1044. void MainWindow::encadrement_signal(int x, int dx)
  1045. {
  1046. ligne1 = new QGraphicsLineItem(x, -80, x, 80);
  1047. ligne1->setPen(pen_encadrement);
  1048. calque_encadrement2->addToGroup(ligne1);
  1049.  
  1050. ligne1 = new QGraphicsLineItem(x+dx, -80, x+dx, 80);
  1051. ligne1->setPen(pen_encadrement);
  1052. calque_encadrement2->addToGroup(ligne1);
  1053.  
  1054. ligne1 = new QGraphicsLineItem(x, -80, x+dx, -80);
  1055. ligne1->setPen(pen_encadrement);
  1056. calque_encadrement2->addToGroup(ligne1);
  1057.  
  1058. ligne1 = new QGraphicsLineItem(x, 80, x+dx, 80);
  1059. ligne1->setPen(pen_encadrement);
  1060. calque_encadrement2->addToGroup(ligne1);
  1061. }
  1062.  
  1063.  
  1064.  
  1065. void MainWindow::encadrement_note(int n_midi) // par un rectangle
  1066. {
  1067. double x, dx, y, dy;
  1068.  
  1069. x=92 - 13 + ((double)n_midi-40.0) * 40.9;
  1070. dx=35;
  1071. y=16;
  1072. dy=50;
  1073.  
  1074. rectangle1 = new QGraphicsRectItem(x, y, dx, dy);
  1075. rectangle1->setPen(pen_encadrement);
  1076. calque_trace_FFT->addToGroup(rectangle1);
  1077. }
  1078.  
  1079.  
  1080.  
  1081. void MainWindow::tracer_signal_a_convertir() //partie à analyser s=f(t) (signal incident, pas le FFT); dans le cadre du haut
  1082. {
  1083. double offset_y = 575.0;
  1084. double echelle =5.0;
  1085. uint8_t octet_n;
  1086. double R;
  1087. double x, y, memo_x, memo_y;
  1088. double min= 1000000.0;
  1089. double max=-1000000.0;
  1090. QString s1;
  1091.  
  1092. effacer_calque(scene1,calque_trace_signal1 );
  1093. segment_trace = new QGraphicsLineItem(0, offset_y, 512, offset_y);
  1094. segment_trace->setPen(QColor(couleur_ligne));
  1095. calque_trace_signal1->addToGroup(segment_trace);
  1096.  
  1097. long n;
  1098. long i=0;
  1099. x=0;
  1100. y=offset_y;
  1101. int pas = 64;
  1102. for(n=0; n<nb_ech/2; n++)
  1103. {
  1104. memo_x = x;
  1105. memo_y = y;
  1106. x = echelle * n;
  1107.  
  1108. octet_n = temp_data[i]; // canal 1
  1109. R = octet_n - 128; // pour oter la composante continue propre au codage par des octets non signés
  1110. // R /= 10.0;
  1111. y=offset_y + R;
  1112.  
  1113. if (y < min) {min = y;}
  1114. if (y > max) {max = y;}
  1115.  
  1116. if (x<1800)
  1117. {
  1118. segment_trace = new QGraphicsLineItem(memo_x ,memo_y, x, y);
  1119. segment_trace->setPen(pen_trace1);
  1120. calque_trace_signal1->addToGroup(segment_trace);
  1121. }
  1122.  
  1123. i++; // pour sauter le canal B (le signal dans le fichier .wav est stéréo)
  1124. i+= pas;
  1125. }
  1126. //scene1->addItem(calque_trace_signal);
  1127. s1.setNum(min);
  1128. //lineEdit_4->setText(s1);
  1129. s1.setNum(max);
  1130. // lineEdit_5->setText(s1);
  1131. }
  1132.  
  1133.  
  1134.  
  1135.  
  1136. void MainWindow::tracer_notes_FFT() // sur onglet NOTES
  1137. {
  1138. double offset_x= spinBox_offset->value(); // ref -2146 ; +/- 22 pour un décalage de +/-1/4 de ton
  1139. double echelle_x =spinBox_echx->value(); // 498
  1140. double offset_y = 350.0;
  1141.  
  1142. uint n;
  1143. double module_FFT;
  1144. double x, y;
  1145. double memo_x[5]={0,0,0,0,0};
  1146. double memo_y[5]={0,0,0,0,0};
  1147. double x0, y0; // fréquence centrale trouvée comme résultat (points d'inflexions de la courbe)
  1148.  
  1149. double z=1.6;
  1150. //int x1=0;
  1151. //int x2=0;
  1152. int num_raie=0;
  1153.  
  1154. QPen pen1("#12FF00");
  1155.  
  1156. if(!rapide)
  1157. {
  1158. effacer_calque(scene1,calque_trace_FFT );
  1159. effacer_calque(scene1,calque_lignes_F_zero );
  1160. }
  1161.  
  1162. x=0;
  1163. y = offset_y;
  1164. ENR_FFT enr_i;
  1165. for(n=0; n<nb_ech; n++)
  1166. {
  1167. //qDebug() << "n" << n;
  1168.  
  1169. memo_x[0] = x;
  1170. memo_y[0] = y;
  1171. // x = offset_x + echelle_x * n; // echelle linéaire -> pas top
  1172. x = offset_x + echelle_x * log2((double)(n+1)); // échelle logarithmique afin que les tons soient équi-espacés
  1173.  
  1174. // ci-dessous 'a' est la partie réelle du complexe, et 'b' la partie imaginaire
  1175. // on calcule le module :
  1176. module_FFT = z * sqrt( tab_X[n].a * tab_X[n].a + tab_X[n].b * tab_X[n].b ); // z * racine(a²+b²)
  1177.  
  1178. y = module_FFT*10.0; // amplitude
  1179. y = offset_y - y; // offset et inversion du sens d'affichage because à l'écran les y croissent de haut en bas
  1180.  
  1181.  
  1182. // décale la pile memo_x
  1183. // puis mise en mémoire (empile) le dernier point
  1184. memo_x[4] = memo_x[3]; memo_y[4] = memo_y[3];
  1185. memo_x[3] = memo_x[2]; memo_y[3] = memo_y[2];
  1186. memo_x[2] = memo_x[1]; memo_y[2] = memo_y[1];
  1187. memo_x[1] = memo_x[0]; memo_y[1] = memo_y[0];
  1188. memo_x[0] = x;
  1189. memo_y[0] = y;
  1190.  
  1191. if((x>20) && (x<1900))
  1192. {
  1193. //y *=1.0;
  1194. if (x > -100)
  1195. {
  1196. if (!rapide)
  1197. {
  1198. segment_trace = new QGraphicsLineItem(memo_x[1] ,memo_y[1], x, y);
  1199. segment_trace->setPen(pen_trace2);
  1200. calque_trace_FFT->addToGroup(segment_trace);
  1201. }
  1202.  
  1203. }
  1204.  
  1205. // DETECTION DES NOTES
  1206.  
  1207. //----------------------------------------------------------------------------------
  1208. // détection direct des points hauts (points d'inflexion de la courbe)
  1209. // on pourrait calculer la dérivée de la courbe, et détecter les valeurs pour lesquelles elle s'annule
  1210. // problème : peut ne pas détecter si le sommet est un pic (discontinuité)
  1211. //----------------------------------------------------------------------------------
  1212.  
  1213. // Autre méthode :
  1214. // détection de 2 doublets de points de part et d'autre, montants puis descendant
  1215. // le sommet se situe donc entre les 2 doublets
  1216.  
  1217. // la DETECTION s'effectue ICI
  1218.  
  1219. // ATTENTION : la ligne qui suit détermine la stratégie utilisée et son paramétrage influe grandement
  1220. // sur la qualité du résultat.
  1221. // on doit pouvoir l'améliorer mais attention : toujours expérimenter sur des données réelles (air de musique)
  1222. // avant de valider la moindre "améloration".
  1223.  
  1224. //if ( (memo_y[3] - memo_y[2]) >0.5 && (memo_y[1] - memo_y[2]) >0.5 )
  1225. if ( (memo_y[3] - memo_y[2]) > 1.1 && (memo_y[1] - memo_y[2]) > 1.1 )
  1226. {
  1227. x0 = memo_x[2]; // point d'inflexion probable
  1228. y0 = memo_y[2];
  1229.  
  1230. if( !rapide) // pas d'affichage en mode rapide
  1231. {
  1232. ligne1 = new QGraphicsLineItem(x0, 60, x0, 350);
  1233. ligne1->setPen(pen1); // BLEU
  1234. calque_lignes_F_zero->addToGroup(ligne1);
  1235. ligne1 = new QGraphicsLineItem(x0, T_i-1, x0, T_i+1); // T_i : variable GLOBALE
  1236. ligne1->setPen(pen1);
  1237. }
  1238.  
  1239. int m0 = 0;
  1240. m0 = calcul_num_midi(x0);
  1241.  
  1242. enr_i.t=T_i; // T_i : variable GLOBALE
  1243. enr_i.num=num_raie;
  1244. enr_i.midi=m0;
  1245. enr_i.amplitude=y0;
  1246.  
  1247. // tracer sur tableau fréquences
  1248. if(num_raie<10) // 6
  1249. {
  1250. liste_ENR_FFT << enr_i; // memorisation ; donc 5 notes max pour un temps (T_i) donné
  1251. // les notes ayant même T_i seront considérées comme simultanées (accord)
  1252. tracer_1enr_sur_TAB_NOTES(enr_i);
  1253. }
  1254. num_raie++;
  1255. }
  1256. }
  1257. }
  1258. T_i++; // variable GLOBALE
  1259.  
  1260. // T_i est ici incrémenté à chaque appel de la fonction
  1261. // sachant que chaque appel de cette fonction analyse 1024 échantillons du signal.
  1262. // et que chaque échantillon représente une durée = 0.5ms du signal d'origine
  1263. // donc T_i est (virtuellement) incrémenté toutes les 1024*0.5ms = 512ms;
  1264. // pourquoi 'virtuellement' ? parce que chaque échantillon "REPRESENTE" une durée de 0.5 ms
  1265. // mais ne "DURE PAS" 0.5ms; L'analyse s'effectue à très haute vitesse sur un signal pré-échantilloné.
  1266. // de quel chapeau sort ce 0.5ms? Voir la fontion 'void MainWindow::remplir_tableau_echantillons_signal()'
  1267.  
  1268. num_raie=0;
  1269. //affi_notes();
  1270.  
  1271. }
  1272.  
  1273.  
  1274. void MainWindow::tracer_echelle_temps_TAB_NOTES() // en secondes sur l'onglet NOTES
  1275. {
  1276. QString s1;
  1277. float x, x0, dx;
  1278. int offset_x = 80;
  1279. int y0 = 620;
  1280. float nbs;
  1281.  
  1282. effacer_calque(scene4, calque_echelle_temporelle);
  1283.  
  1284. if (visu_ech_tps == true) {y0 = 0;} // grandes lignes
  1285. for(int n=0; n<=120; n++)
  1286. {
  1287. x0 = 10.0 * doubleSpinBox_T0->value();
  1288. dx = 1000.0 * pas_echantillonage/256.0; // =93.75
  1289.  
  1290. x = x0 + dx * zoom_x * (float)n;
  1291.  
  1292. ligne1 = new QGraphicsLineItem(offset_x + x, y0-5, offset_x + x, 650);
  1293. QPen pen1;
  1294. pen1.setColor("#00FF00"); //
  1295. ligne1->setPen(pen1);
  1296. calque_echelle_temporelle->addToGroup(ligne1);
  1297.  
  1298. nbs = (float) n;
  1299. s1.setNum(nbs, 10, 0); // base 10, 0 décimale
  1300. s1 += "s";
  1301.  
  1302. Etiquette(offset_x + x, 630, s1, "#FFFFFF", "#000000", "#00FF00", calque_echelle_temporelle);
  1303. }
  1304. }
  1305.  
  1306.  
  1307.  
  1308. void MainWindow::tracer_1enr_sur_TAB_NOTES(ENR_FFT enr_i) // c.a.d. ayant la durée élémentaire T_i = 256 ms
  1309. {
  1310. int T2;
  1311. //uint8_t num_raie;
  1312. uint8_t m0;
  1313. double yH, yL;
  1314. double y0, y2, dy, dy2;
  1315. uint16_t v; // v comme 'vertical'
  1316. double offset_y = 350.0;
  1317. QString couleur1;
  1318.  
  1319. T2 = zoom_x * enr_i.t;
  1320.  
  1321. m0 = enr_i.midi;
  1322. y0 = enr_i.amplitude;
  1323.  
  1324. if (checkBox_flitrer->isChecked() && (m0 != spinBox_filtre->value())) {return;}
  1325.  
  1326. v= 700 - (16 * (m0-40) );
  1327.  
  1328. y2 = -y0 + offset_y;
  1329.  
  1330. dy = y2/30.0; // 40
  1331. //dy = y2/10;
  1332.  
  1333. //dy=dy*dy; // pour un meilleur affichage ; A VOIR !!!!
  1334. //dy /=5.0;
  1335.  
  1336. dy *= gain;
  1337.  
  1338. if ( dy > 200) { dy = 200;} // bridage amplitude max
  1339.  
  1340. if(v > 730) {return;}
  1341.  
  1342. if (dy > seuil)
  1343. {
  1344. dy2 = dy;
  1345. if (checkBox_norm->isChecked()) {dy2=5; } // bride la hauteur des tirets
  1346. float x = 80.0 + T2;
  1347. yH = v+dy2/2;
  1348. yL = v-dy2/2;
  1349. // rabotage pour éviter le scrolling de l'affichage:
  1350. if(yH > 730) {yH = 730;}
  1351. if(yL <0) {yH = 0;}
  1352.  
  1353. //ligne1 = new QGraphicsLineItem(x, yL, x, yH);
  1354.  
  1355. rectangle1 = new QGraphicsRectItem(x, v-dy2/2, zoom_x-2, dy2);
  1356. int h1 = calcul_hauteur_note(m0);
  1357. h1-=3;
  1358. if(h1<0){h1+=12;}
  1359. if(h1>11){h1-=12;}
  1360.  
  1361. if (checkBox_norm->isChecked()) // utilise une couleur en fonction de l'amplitude du signal
  1362. {
  1363. float dy3 = dy/ 20;
  1364. if (dy3 > 0.8) {dy3 = 0.8;}
  1365. couleur1 = calcul_couleur(dy3);
  1366. }
  1367. else
  1368. {
  1369. couleur1 = liste_couleurs[h1]; // utilise une couleur en fonction de la fréquence ('hauteur') de la note
  1370. }
  1371.  
  1372. QPen pen1;
  1373. pen1.setColor(couleur1);
  1374.  
  1375. rectangle1->setPen(pen1);
  1376. rectangle1->setBrush(QColor(couleur1));
  1377.  
  1378. QBrush br1;
  1379. br1.setStyle(Qt::SolidPattern);
  1380. br1.setColor(couleur1);
  1381. rectangle1->setBrush(br1);
  1382.  
  1383. calque_TAB_FRQ->addToGroup(rectangle1); // lent !
  1384.  
  1385. graphicsView1->verticalScrollBar()->setValue(0);
  1386. }
  1387. }
  1388.  
  1389.  
  1390.  
  1391. void MainWindow::retracer_TAB_FRQ()
  1392. {
  1393. ENR_FFT enr_i;
  1394. uint16_t n_max = liste_ENR_FFT.length();
  1395. if (n_max == 0) return;
  1396. //effacer_calque(scene1,calque_trace_FFT );
  1397. tracer_graduation_TAB_NOTES();
  1398.  
  1399. calque_TAB_FRQ->setPos(0, 0);
  1400. for(uint16_t n=0; n<n_max-1; n++)
  1401. {
  1402. enr_i = liste_ENR_FFT[n];
  1403. tracer_1enr_sur_TAB_NOTES(enr_i);
  1404. }
  1405.  
  1406. float pas_grille = doubleSpinBox_dt->value()/2.0 * zoom_x;
  1407. double offset_x = 10 * doubleSpinBox_x0->value() + spinBox_d_barres->value() * pas_grille;
  1408. calque_TAB_FRQ->setPos(offset_x, 0);
  1409. }
  1410.  
  1411.  
  1412.  
  1413. void RAZ_tableau_echantillons()
  1414. {
  1415. uint n;
  1416. for(n=0; n < nb_ech; n++)
  1417. {
  1418. ech[n].a = 0; // partie reelle
  1419. ech[n].b = 0; // partie imaginaire
  1420. }
  1421. }
  1422.  
  1423.  
  1424.  
  1425.  
  1426. void MainWindow::remplir_tableau_echantillons_sinus()
  1427. {
  1428. // création du signal à analyser
  1429. uint n, n_max;
  1430. double R;
  1431. double frq_echantillonnage=48000; // Hz
  1432. double Te; // période d'échantillonage
  1433.  
  1434. Te = 1.0 / frq_echantillonnage;
  1435. Te *=15.0;
  1436.  
  1437. if (bz==true) {n_max = nb_ech /4; } else {n_max = nb_ech; }
  1438.  
  1439. for(n=0; n < n_max; n++) // nb d'échantillons
  1440. {
  1441. R= cos(2.0 * M_PI * frequence1 * n * Te );
  1442.  
  1443. if (modul) {R *= 1 + 0.8 * cos(2 * M_PI * frequence3 * n * Te);} // modulation d'amplitude
  1444.  
  1445. if (second_Frq) {R+=cos(2 * M_PI * frequence2 * n * Te); }
  1446. if (hamming) { R = R * (1- cos (2* M_PI * n / n_max ));}
  1447.  
  1448. R/=10;
  1449. ech[n].a = R; // partie reelle
  1450. ech[n].b = 0; // partie imaginaire
  1451. }
  1452. }
  1453.  
  1454.  
  1455.  
  1456. uint bit_reversal(uint num, uint nb_bits)
  1457. {
  1458. uint r = 0, i, s;
  1459. if ( num > (1<< nb_bits)) { return 0; }
  1460.  
  1461. for (i=0; i<nb_bits; i++)
  1462. {
  1463. s = (num & (1 << i));
  1464. if(s) { r |= (1 << ((nb_bits - 1) - i)); }
  1465. }
  1466. return r;
  1467. }
  1468.  
  1469.  
  1470.  
  1471. void MainWindow::bit_reverse_tableau_X()
  1472. {
  1473. // recopie les échantillons en les classant dans l'ordre 'bit reverse'
  1474. uint n,r;
  1475.  
  1476. for(n=0; n < nb_ech; n++) // nb d'échantillons
  1477. {
  1478. r=bit_reversal(n,nb_etapes);
  1479. tab_X[n] = ech[r];
  1480. }
  1481. }
  1482.  
  1483. void MainWindow::calcul_tableau_W()
  1484. {
  1485. if (tableau_w_plein == true) {return;}
  1486. // calcul et memorisation dans un tableau des twiddle factors (facteurs de rotation)
  1487. uint n;
  1488. double x;
  1489. for(n=0; n<(nb_ech/2-1); n++)
  1490. {
  1491. x=2.0*M_PI * n / nb_ech;
  1492.  
  1493. tab_W[n].a = cos(x); // partie reelle
  1494. tab_W[n].b = -sin(x); // partie imaginaire
  1495. }
  1496. tableau_w_plein = true;
  1497. }
  1498.  
  1499. void MainWindow::calcul_FFT()
  1500. {
  1501. Complexe produit; // voir la classe "Complexe" : complexe.h et complexe.ccp
  1502.  
  1503. uint etape, e1, e2, li, w, ci;
  1504. uint li_max=nb_ech;
  1505. e2=1;
  1506.  
  1507. for (etape=1; etape<=nb_etapes; etape++)
  1508. {
  1509. e1=e2; //(e1 évite d'effectuer des divisions e2/2 plus bas)
  1510. e2=e2+e2; // plus rapide que *=2
  1511.  
  1512. for (li=0; li<li_max; li+=1)
  1513. {
  1514. ci=li & (e2-1); // ET bit à bit
  1515. if (ci>(e1-1))
  1516. {
  1517. w=li_max/e2*(li & (e1 -1)); // ET bit à bit calcul du numéro du facteur de rotation W
  1518. produit = tab_W[w] * tab_X[li]; // le twiddle factor est lu en memoire; le produit est une mutiplication de nb complexes. Voir "complexe.cpp"
  1519. tab_X[li]=tab_X[li-e1] - produit; // concerne la ligne basse du croisillon; soustraction complexe; Voir "complexe.cpp"
  1520. tab_X[li-e1]=tab_X[li-e1] + produit; // concerne la ligne haute du croisillon; addition complexe; Voir "complexe.cpp"
  1521. }
  1522. }
  1523. }
  1524. }
  1525.  
  1526.  
  1527.  
  1528. void MainWindow::on_spinBox_frq_valueChanged(int arg1) // SELECTEUR DE FREQUENCE 1
  1529. {
  1530. effacer_calque(scene1,calque_trace_FFT );
  1531. frequence1 = arg1;
  1532. RAZ_tableau_echantillons();
  1533. remplir_tableau_echantillons_sinus();
  1534. tracer_signal_a_convertir();
  1535. calcul_tableau_W();
  1536. bit_reverse_tableau_X();
  1537. calcul_FFT(); // pour 1 cluster
  1538. // tracer_graduations();
  1539. tracer_notes_FFT();
  1540. }
  1541.  
  1542.  
  1543. void MainWindow::on_spinBox_frq_2_valueChanged(int arg1) // SELECTEUR DE FREQUENCE 2
  1544. {
  1545. effacer_calque(scene1,calque_trace_FFT );
  1546. frequence2 = arg1;
  1547. RAZ_tableau_echantillons();
  1548. remplir_tableau_echantillons_sinus();
  1549. tracer_signal_a_convertir();
  1550. calcul_tableau_W();
  1551. bit_reverse_tableau_X();
  1552. calcul_FFT();
  1553. // tracer_graduations();
  1554. tracer_notes_FFT();
  1555. }
  1556.  
  1557.  
  1558. void MainWindow::on_spinBox_frq_3_valueChanged(int arg1)
  1559. {
  1560. effacer_calque(scene1,calque_trace_FFT );
  1561. frequence3 = arg1;
  1562. RAZ_tableau_echantillons();
  1563. remplir_tableau_echantillons_sinus();
  1564. tracer_signal_a_convertir();
  1565. calcul_tableau_W();
  1566. bit_reverse_tableau_X();
  1567. calcul_FFT();
  1568. // tracer_graduations();
  1569. tracer_notes_FFT();
  1570. }
  1571.  
  1572.  
  1573. void MainWindow::on_checkBox1_toggled(bool checked) // HAMMING
  1574. {
  1575. effacer_calque(scene1,calque_trace_FFT );
  1576. if (checked) {hamming = true;} else {hamming = false;}
  1577. RAZ_tableau_echantillons();
  1578. remplir_tableau_echantillons_sinus();
  1579. tracer_signal_a_convertir();
  1580. calcul_tableau_W();
  1581. bit_reverse_tableau_X();
  1582. calcul_FFT();
  1583. // tracer_graduations();
  1584. tracer_notes_FFT();
  1585.  
  1586. }
  1587.  
  1588.  
  1589. void MainWindow::on_checkBox2_toggled(bool checked) // SECONDE FREQUENCE
  1590. {
  1591. effacer_calque(scene1,calque_trace_FFT );
  1592. if (checked) {second_Frq = true;} else {second_Frq = false;}
  1593. RAZ_tableau_echantillons();
  1594. remplir_tableau_echantillons_sinus();
  1595. tracer_signal_a_convertir();
  1596. calcul_tableau_W();
  1597. bit_reverse_tableau_X();
  1598. calcul_FFT();
  1599. // tracer_graduations();
  1600. tracer_notes_FFT();
  1601. }
  1602.  
  1603.  
  1604. void MainWindow::on_checkBox3_toggled(bool checked)
  1605. {
  1606. effacer_calque(scene1,calque_trace_FFT );
  1607. if (checked) {bz = true;} else {bz = false;}
  1608. RAZ_tableau_echantillons();
  1609. remplir_tableau_echantillons_sinus();
  1610. tracer_signal_a_convertir();
  1611. calcul_tableau_W();
  1612. bit_reverse_tableau_X();
  1613. calcul_FFT();
  1614. // tracer_graduations();
  1615. tracer_notes_FFT();
  1616. }
  1617.  
  1618.  
  1619. void MainWindow::on_checkBox4_clicked(bool checked)
  1620. {
  1621. effacer_calque(scene1,calque_trace_FFT );
  1622. if (checked) {modul = true;} else {modul = false;}
  1623. RAZ_tableau_echantillons();
  1624. remplir_tableau_echantillons_sinus();
  1625. tracer_signal_a_convertir();
  1626. calcul_tableau_W();
  1627. bit_reverse_tableau_X();
  1628. calcul_FFT();
  1629. // tracer_graduations();
  1630. tracer_notes_FFT();
  1631. }
  1632.  
  1633.  
  1634. void MainWindow::Tic1()
  1635. {
  1636.  
  1637. nb_tics++;
  1638. if(nb_tics > 4000)
  1639. {
  1640. Timer1->stop();
  1641. nb_tics=0;
  1642. }
  1643. else
  1644. {
  1645. spinBox_4->setValue( spinBox_4->value() +1);
  1646. Timer1->setInterval(2); // à voir
  1647. }
  1648. }
  1649.  
  1650.  
  1651. void MainWindow::Tic2()
  1652. {
  1653. int d_barre;
  1654. float dt, vts;
  1655. int itrv;
  1656.  
  1657. vts = doubleSpinBox_vitesse->value();
  1658. d_barre = joue_1_note_de_la_liste(); // nb de barres temporelles séparant la note avec celle qui suit
  1659.  
  1660. dt = 20.0 * (float)d_barre;
  1661. dt *= (100.0 / vts);
  1662. itrv = (int) dt;
  1663.  
  1664. Timer2->setInterval(itrv);
  1665. }
  1666.  
  1667.  
  1668. void clear_temp_data()
  1669. {
  1670. for(int i=0; i<2000000; i++)
  1671. {
  1672. temp_data[i]=0;
  1673. }
  1674.  
  1675. }
  1676.  
  1677.  
  1678. void MainWindow::on_Bt_load_wav_clicked()
  1679. {
  1680. open_fichier_wav(); // associe le binStream1 au fichier wav
  1681. decode_entete();
  1682.  
  1683. MainWindow::setCursor(Qt::WaitCursor);
  1684. liste_ENR_FFT.clear();
  1685. effacer_calque(scene1,calque_trace_signal1 );
  1686.  
  1687. effacer_calque(scene1, calque_trace_FFT);
  1688. clear_temp_data();
  1689. garnis_temp_data(0); // donne accès à la totalité (2MB) du fichier wav (dans le 'temp_data')
  1690. tracer_signal_complet();
  1691. MainWindow::setCursor(Qt::ArrowCursor);
  1692. tracer_gradu_temporelle_signal_entree();
  1693.  
  1694. frame_3->setVisible(true);
  1695. Bt_scan_auto->setVisible(true);
  1696. checkBox_rapide->setVisible(true);
  1697. }
  1698.  
  1699.  
  1700.  
  1701. /*
  1702.   char RIFF[4]; (4 bytes)
  1703.   unsigned long ChunkSize; (4 bytes)
  1704.   char WAVE[4]; (4 bytes)
  1705.   char fmt[4]; (4 bytes)
  1706.   unsigned long Subchunk1Size; (4 bytes)
  1707.   unsigned short AudioFormat; (2 octets)
  1708.   unsigned short NumOfChan; (2 octets)
  1709.   unsigned long SamplesPerSec; (4 bytes)
  1710.   unsigned long bytesPerSec; (4 bytes)
  1711.   unsigned short blockAlign; (2 octets)
  1712.   unsigned short bitsPerSample; (2 octets)
  1713.   char Subchunk2ID[4]; (4 bytes)
  1714.   unsigned long Subchunk2Size; (4 bytes)
  1715.  
  1716.   TOTAL 44 octets
  1717. */
  1718.  
  1719.  
  1720. QString separ_milliers(uint n) // séparation des miliers par des espaces
  1721. {
  1722. QString s1, s1a, s1b, s1c;
  1723. s1.setNum(n);
  1724. int L= s1.length(); s1a = s1.right(3); s1b = s1.mid(L-6, 3); s1c = s1.mid(L-9, 3);
  1725. return (s1c+" "+s1b+" "+s1a);
  1726. }
  1727.  
  1728.  
  1729.  
  1730. void MainWindow::save_fichier_ini()
  1731. {
  1732. QFile file1(QDir::currentPath() + "/" + "params_FFT.ini"); // dans le dossier de l'exécutable
  1733. if (file1.open(QIODevice::WriteOnly | QIODevice::Text))
  1734. {
  1735. //int p1= string_currentFile.lastIndexOf('/');
  1736. //string_currentDir = string_currentFile.left(p1);
  1737.  
  1738. QTextStream out(&file1);
  1739.  
  1740. out << "# Ce fichier est crée automatiquement par le programme";
  1741. out << '\n';
  1742. out << "#";
  1743. out << '\n';
  1744. out << "# chemins:";
  1745. out << '\n';
  1746. out << "<currentDir>" << string_currentDir << "</currentDir>";
  1747. out << '\n';
  1748. out << "<currentFile>" << string_currentFile << "</currentFile>";
  1749. }
  1750. file1.close();
  1751. }
  1752.  
  1753.  
  1754.  
  1755. void MainWindow::open_fichier_wav()
  1756. {
  1757. // Le fichier .wav comprend un signal audio stéréo échantilloné à 48 000 octets/seconde pour chaque canal
  1758. // ce qui fait 96000 octets/s pour l'ensemble du signal stéréo
  1759.  
  1760. string_currentFile = QFileDialog::getOpenFileName(this, tr("Ouvrir Fichier wav..."), string_currentDir,
  1761. tr("Fichiers wav (*.wav);;All Files (*)"));
  1762. if (string_currentFile != "")
  1763. {
  1764. save_fichier_ini();
  1765. }
  1766. lineEdit_1->setText(string_currentFile);
  1767.  
  1768. int p1= string_currentFile.lastIndexOf('/');
  1769. string_currentDir = string_currentFile.left(p1);
  1770. lineEdit_current_dir->setText(string_currentDir);
  1771.  
  1772. save_fichier_ini();
  1773.  
  1774. file_wav.setFileName(string_currentFile);
  1775. if (!file_wav.open(QIODevice::ReadOnly))
  1776. {
  1777. wav_ok = false;
  1778. Bt_scan_auto->setStyleSheet("background-color: rgb(200, 200, 200);");
  1779. return ;
  1780. }
  1781. else
  1782. {
  1783. binStream1.setDevice(&file_wav); // accès à la totalité du fichier wav
  1784. wav_ok = true;
  1785. Bt_scan_auto->setStyleSheet("background-color: rgb(0, 255, 0);"); // vert
  1786.  
  1787. }
  1788. // le fichier reste ouvert pour toute la session
  1789. }
  1790.  
  1791.  
  1792.  
  1793.  
  1794. void MainWindow::decode_entete()
  1795. {
  1796. // ============ [Bloc de déclaration d'un fichier au format WAVE] ============
  1797.  
  1798. if (! wav_ok) {return;}
  1799. QString s3, s4, s5, fileSize1;
  1800. uint8_t x, nb_canaux;
  1801. float tot1, tot2, tot3, tot4;
  1802.  
  1803.  
  1804. binStream1.device()->seek(0); // retour de la lecture au début du fichier
  1805. binStream1.readRawData (temp_entete, 100); // lecture entete du fichier
  1806. //FileTypeBlocID
  1807. x=(uint8_t)temp_entete[0]; if ((x>64) && (x<127)) { s3 = char(x); }
  1808. x=(uint8_t)temp_entete[1]; if ((x>64) && (x<127)) { s3 += char(x); }
  1809. x=(uint8_t)temp_entete[2]; if ((x>64) && (x<127)) { s3 += char(x); }
  1810. x=(uint8_t)temp_entete[3]; if ((x>64) && (x<127)) { s3 += char(x); }
  1811. tableWidget_1->setItem(0, 0, new QTableWidgetItem (s3) ); //FileTypeBlocID
  1812.  
  1813. // FileSize
  1814. x=(uint8_t)temp_entete[4]; s3.setNum(x); tableWidget_1->setItem(1, 0, new QTableWidgetItem (s3) );
  1815. x=(uint8_t)temp_entete[5]; s3.setNum(x); tableWidget_1->setItem(1, 1, new QTableWidgetItem (s3) );
  1816. x=(uint8_t)temp_entete[6]; s3.setNum(x); tableWidget_1->setItem(1, 2, new QTableWidgetItem (s3) );
  1817. x=(uint8_t)temp_entete[7]; s3.setNum(x); tableWidget_1->setItem(1, 3, new QTableWidgetItem (s3) );
  1818.  
  1819. tot1 = temp_entete[4] + (2<<7) * temp_entete[5] + (2<<15) * temp_entete[6] + (2<23)* temp_entete[7];
  1820. fileSize1 = separ_milliers(tot1);
  1821. tableWidget_1->setItem(1, 4, new QTableWidgetItem ("= " + fileSize1) );
  1822.  
  1823. // FileFormatID
  1824. x=(uint8_t)temp_entete[8]; if ((x>64) && (x<127)) { s3 = char(x); }
  1825. x=(uint8_t)temp_entete[9]; if ((x>64) && (x<127)) { s3 += char(x); }
  1826. x=(uint8_t)temp_entete[10]; if ((x>64) && (x<127)) { s3 += char(x); }
  1827. x=(uint8_t)temp_entete[11]; if ((x>64) && (x<127)) { s3 += char(x); }
  1828. tableWidget_1->setItem(2, 0, new QTableWidgetItem (s3) );
  1829.  
  1830. // ============ [Bloc décrivant le format audio] ==============
  1831.  
  1832. // FormatBlocID
  1833. x=(uint8_t)temp_entete[12]; if ((x>64) && (x<127)) { s3 = char(x); }
  1834. x=(uint8_t)temp_entete[13]; if ((x>64) && (x<127)) { s3 += char(x); }
  1835. x=(uint8_t)temp_entete[14]; if ((x>64) && (x<127)) { s3 += char(x); }
  1836. x=(uint8_t)temp_entete[15]; if ((x>64) && (x<127)) { s3 += char(x); }
  1837. tableWidget_1->setItem(3, 0, new QTableWidgetItem (s3) );
  1838.  
  1839. //BlocSize
  1840. x=(uint8_t)temp_entete[16]; s3.setNum(x); tableWidget_1->setItem(4, 0, new QTableWidgetItem (s3) );
  1841. x=(uint8_t)temp_entete[17]; s3.setNum(x); tableWidget_1->setItem(4, 1, new QTableWidgetItem (s3) );
  1842. x=(uint8_t)temp_entete[18]; s3.setNum(x); tableWidget_1->setItem(4, 2, new QTableWidgetItem (s3) );
  1843. x=(uint8_t)temp_entete[19]; s3.setNum(x); tableWidget_1->setItem(4, 3, new QTableWidgetItem (s3) );
  1844.  
  1845. tot2 = (uint8_t)temp_entete[16] + (2<<7) * (uint8_t)temp_entete[17] + (2<<15) * (uint8_t)temp_entete[18] + (2<23)* (uint8_t)temp_entete[19];
  1846. tableWidget_1->setItem(4, 4, new QTableWidgetItem ("= " + separ_milliers(tot2)) );
  1847.  
  1848. //AudioFormat
  1849. x=(uint8_t)temp_entete[20]; s3.setNum(x); tableWidget_1->setItem(5, 0, new QTableWidgetItem (s3) );
  1850. x=(uint8_t)temp_entete[21]; s3.setNum(x); tableWidget_1->setItem(5, 1, new QTableWidgetItem (s3) );
  1851.  
  1852. if ((uint8_t)temp_entete[20]==1){tableWidget_1->setItem(5, 4, new QTableWidgetItem ("PCM") );}
  1853.  
  1854. //NbrCanaux
  1855. nb_canaux=(uint8_t)temp_entete[22]; s3.setNum(nb_canaux); tableWidget_1->setItem(6, 0, new QTableWidgetItem (s3) );
  1856. x=(uint8_t)temp_entete[23]; s3.setNum(x); tableWidget_1->setItem(6, 1, new QTableWidgetItem (s3) );
  1857.  
  1858. //Fréquence d'échantillonage en Hz
  1859. x=(uint8_t)temp_entete[24]; s3.setNum(x); tableWidget_1->setItem(7, 0, new QTableWidgetItem (s3) );
  1860. x=(uint8_t)temp_entete[25]; s3.setNum(x); tableWidget_1->setItem(7, 1, new QTableWidgetItem (s3) );
  1861. x=(uint8_t)temp_entete[26]; s3.setNum(x); tableWidget_1->setItem(7, 2, new QTableWidgetItem (s3) );
  1862. x=(uint8_t)temp_entete[27]; s3.setNum(x); tableWidget_1->setItem(7, 3, new QTableWidgetItem (s3) );
  1863.  
  1864. tot3 = (uint8_t)temp_entete[24] + (2<<7) * (uint8_t)temp_entete[25] + (2<<15) * (uint8_t)temp_entete[26] + (2<23)* (uint8_t)temp_entete[27];
  1865. tableWidget_1->setItem(7, 4, new QTableWidgetItem ("= " + separ_milliers(tot3)) );
  1866.  
  1867. //BytePerSec
  1868. x=temp_entete[28]; s3.setNum(x); tableWidget_1->setItem(8, 0, new QTableWidgetItem (s3) );
  1869. x=temp_entete[29]; s3.setNum(x); tableWidget_1->setItem(8, 1, new QTableWidgetItem (s3) );
  1870. x=temp_entete[30]; s3.setNum(x); tableWidget_1->setItem(8, 2, new QTableWidgetItem (s3) );
  1871. x=temp_entete[31]; s3.setNum(x); tableWidget_1->setItem(8, 3, new QTableWidgetItem (s3) );
  1872.  
  1873. tot4 = (uint8_t)temp_entete[28] + (2<<7) * (uint8_t)temp_entete[29] + (2<<15) * (uint8_t)temp_entete[30] + (2<23)* (uint8_t)temp_entete[31];
  1874. s3.setNum(tot4);
  1875. tableWidget_1->setItem(8, 4, new QTableWidgetItem (s3));
  1876. //tableWidget_1->setItem(8, 4, new QTableWidgetItem ("= " + separ_milliers(tot4)) );
  1877.  
  1878. //BytePerBloc
  1879. x=(uint8_t)temp_entete[32]; s3.setNum(x); tableWidget_1->setItem(9, 0, new QTableWidgetItem (s3) );
  1880. x=(uint8_t)temp_entete[33]; s3.setNum(x); tableWidget_1->setItem(9, 1, new QTableWidgetItem (s3) );
  1881.  
  1882. //BitsPerSample
  1883. x=(uint8_t)temp_entete[34]; s3.setNum(x); tableWidget_1->setItem(10, 0, new QTableWidgetItem (s3) );
  1884. x=(uint8_t)temp_entete[35]; s3.setNum(x); tableWidget_1->setItem(10, 1, new QTableWidgetItem (s3) );
  1885.  
  1886. x=(uint8_t)temp_entete[36]; if ((x>64) && (x<127)) { s3 = char(x); }
  1887. x=(uint8_t)temp_entete[37]; if ((x>64) && (x<127)) { s3 += char(x); }
  1888. x=(uint8_t)temp_entete[38]; if ((x>64) && (x<127)) { s3 += char(x); }
  1889. x=(uint8_t)temp_entete[39]; if ((x>64) && (x<127)) { s3 += char(x); }
  1890. tableWidget_1->setItem(11, 0, new QTableWidgetItem (s3) );
  1891.  
  1892. // DataSize
  1893. x=(uint8_t)temp_entete[40]; s3.setNum(x); tableWidget_1->setItem(12, 0, new QTableWidgetItem (s3) );
  1894. x=(uint8_t)temp_entete[41]; s3.setNum(x); tableWidget_1->setItem(12, 1, new QTableWidgetItem (s3) );
  1895. x=(uint8_t)temp_entete[42]; s3.setNum(x); tableWidget_1->setItem(12, 2, new QTableWidgetItem (s3) );
  1896. x=(uint8_t)temp_entete[43]; s3.setNum(x); tableWidget_1->setItem(12, 3, new QTableWidgetItem (s3) );
  1897.  
  1898. int tot5a = 1 * (uint8_t) temp_entete[40]; //because le temp_entête de type 'char' code avec entiers signés
  1899. int tot5b = (1<<8) * (uint8_t)temp_entete[41]; // remarque: (1<<8) = 2^8 = 256 // ne pas écrire (2<<8) !!
  1900. int tot5c = (1<<16) * (uint8_t)temp_entete[42];
  1901. int tot5d = (1<<24) * (uint8_t)temp_entete[43];
  1902.  
  1903. data_size = tot5a + tot5b + tot5c + tot5d;
  1904.  
  1905. // 21248 + 458752 = 480000
  1906. // pour le .wav LA 440 (48000, durée 10s) ->14x(2^16) + 166 * (2^8) = 960000
  1907. // 960 000 kb (stéréo) / 96 000 kb/s (stéréo)= 10s
  1908.  
  1909. tableWidget_1->setItem(12, 4, new QTableWidgetItem ("= " + separ_milliers(data_size)) ); // DataSize
  1910.  
  1911. // durée calculée
  1912. duree = data_size / tot4;
  1913. s3.setNum(duree, 'f', 3);// double n, char format = 'g', int precision = 6
  1914. tableWidget_1->setItem(13, 4, new QTableWidgetItem (s3 + " s") );
  1915.  
  1916. s4.setNum(tot4);
  1917. s4 = "ech : " + s3;
  1918. s4 += " Bps / 2 voies (stéréo) = ";
  1919.  
  1920. s5.setNum(tot4/2000);
  1921. s5 +=" kBps";
  1922.  
  1923. tableWidget_1->setItem(8, 5, new QTableWidgetItem (s5) );
  1924. lineEdit_6->setText("File size = " + fileSize1 + " bytes ; " + s4 + s5 + " ; durée calculée = " +s3 + "s");
  1925.  
  1926. if ((nb_canaux == 2) && (tot4 != 96000))
  1927. {
  1928. QMessageBox msgBox;
  1929. QString s1;
  1930. s1 = "Attention: Le taux d'échentillonage n'est pas 48 kb/s";
  1931. msgBox.setText(s1);
  1932. msgBox.exec();
  1933. }
  1934. if (nb_canaux != 2)
  1935. {
  1936. QMessageBox msgBox;
  1937. QString s1;
  1938. s1 = "Attention: Signal mono (doit être STEREO !)";
  1939. msgBox.setText(s1);
  1940. msgBox.exec();
  1941. }
  1942. }
  1943.  
  1944.  
  1945.  
  1946.  
  1947.  
  1948. // voir la page : https://fr.wikipedia.org/wiki/Waveform_Audio_File_Format
  1949. void MainWindow::garnis_temp_data(qint32 offset_i)
  1950. {
  1951. if (! wav_ok) {return;}
  1952.  
  1953. binStream1.device()->seek(0); // retour de la lecture au début du fichier
  1954. binStream1.skipRawData(44+offset_i); // saut bien plus loin dans le fichier
  1955. binStream1.readRawData (temp_data, 2000000); //lecture des données audio
  1956.  
  1957. //file_wav.close();
  1958. }
  1959.  
  1960.  
  1961. void MainWindow::calcul_compression()
  1962. {
  1963. double R;
  1964. double R_max=0;
  1965.  
  1966. for(uint n =0; n<nb_ech/4; n++)
  1967. {
  1968. R=ech[n].a;
  1969. if (R>R_max) {R_max=R;}
  1970. }
  1971. }
  1972.  
  1973.  
  1974. void MainWindow::remplir_tableau_echantillons_signal() // lecture du signal à analyser dans le 'temp_data' -> ech[n]
  1975. {
  1976.  
  1977. /*
  1978. Le fichier .wav doit avoir les caractéristiques suivantes :
  1979. - RIFF PCM WAVE fmt
  1980. - stéréo deux voies
  1981. - 96000 octets/s c'est à dire acqui avec 48000 octets/s x 2 voies
  1982. La FTT sera effectuée en 10 passes, sur un nb_ech = 2^10 = 1024 échantillons
  1983. */
  1984.  
  1985. uint n, n_max, i, offset_x;
  1986. double R;
  1987.  
  1988. offset_x = 40; // ou plus, si lecture plus loin dans le temps, à voir
  1989.  
  1990. uint8_t octet_n; // octet_B;
  1991. /*
  1992.   pour un codage 8 bits/sample = 2 * 1 octet/sample (stéréo)
  1993.   [Octet du Sample1 Canal1 ] (octet_A, octet_B)
  1994.   [Octet du Sample1 Canal2 ]
  1995.   ...
  1996. */
  1997. i=0;
  1998. n=0;
  1999. // on ne prend pas en compte tous les échantillons dispo dans le .wav (inutile ici)
  2000. // mais 1 sur 40 (la fréquence de la note la plus aigue (midi94) est = 932Hz)
  2001. // et seul le fondamental est pertinant pour reconnaitre la note, les harmoniques (timbre) sont ignorées
  2002. // il faut donc échantilloner à 932*2 = 1864 Hz au minimum
  2003. // Le fichier .wav d'origine est échantilloné à 48kHz
  2004. // 48000 / 1864 = 25.75
  2005. // On va prendre 1 échantillon sur 24 , ce qui donne un échantillonage à 48000/24 = 2000Hz
  2006. // attention : tout changement de cette valeur (pas = 24) change l'échelle de représentation de la FFT
  2007. // et fout le bocson dans tout le programme !!!
  2008. // chaque échantillon représente donc une durée = 1/2000 seconde = 0.5ms = 500us
  2009. // voir la suite des explications vers la fin de la fonction 'void MainWindow::tracer_notes_FFT()'
  2010.  
  2011. n_max = nb_ech /2; // = 1024/2 = 512
  2012. // 512*0.5ms = 256 ms
  2013.  
  2014. while (n < n_max)
  2015. {
  2016. octet_n = temp_data[offset_x + i]; // canal A
  2017. // i++; // pour sauter (et ignorer) le canal B (le signal dans le fichier .wav est stéréo)
  2018. i+= pas_echantillonage;
  2019.  
  2020. // x= 256 * octet_A + octet_B;
  2021. R = octet_n - 128; // pour oter la composante continue propre au codage par des octets non signés
  2022. R /= 10.0;
  2023. R *= doubleSpinBox_1->value();
  2024.  
  2025. if (hamming) { R = R * (1- cos (2* M_PI * n / nb_ech/2 ));}
  2026.  
  2027. if (bourrage_de_zeros)
  2028. {
  2029. if (n<=nb_ech/4) // /4 -> signal
  2030. {
  2031. ech[n].a = R; // partie reelle
  2032. ech[n].b = 0; // partie imaginaire
  2033. }
  2034. else // -> Bourage de zéros
  2035. {
  2036. ech[n].a = 0; // partie reelle
  2037. ech[n].b = 0; // partie imaginaire
  2038. }
  2039. }
  2040. else
  2041. {
  2042. ech[n].a = R; // partie reelle
  2043. ech[n].b = 0; // partie imaginaire
  2044. }
  2045.  
  2046. n++; // n atteindra la valeur max = 512 ech représentant une durée totale de 256 ms
  2047. }
  2048.  
  2049. //calcul_compression();
  2050. }
  2051.  
  2052. /*
  2053. void MainWindow::on_toolButton_2_clicked() // recup signal
  2054. {
  2055.   RAZ_tableau_echantillons();
  2056.   remplir_tableau_echantillons_signal();
  2057.   tracer_signal_a_convertir();
  2058. }
  2059. */
  2060.  
  2061. void MainWindow::calcul_ofsset()
  2062. {
  2063. if(!wav_ok) return;
  2064. offset_t = spinBox_1->value() + 10 * spinBox_2->value() + 100 * spinBox_3->value() + 1000 * spinBox_4->value()
  2065. + 10000 * spinBox_5->value() + 100000 * spinBox_6->value();
  2066. QString s1;
  2067. s1 = separ_milliers(offset_t) ;
  2068. lineEdit_3->setText(s1);
  2069. effacer_calque(scene2, calque_encadrement2);
  2070. encadrement_signal(offset_t/1200, 25);
  2071. }
  2072.  
  2073.  
  2074. void MainWindow::traitement_signal() // lance les Transformées de Fourier du signal
  2075. {
  2076. if (! wav_ok) {return;}
  2077.  
  2078. garnis_temp_data(offset_t);
  2079. remplir_tableau_echantillons_signal();
  2080.  
  2081. calcul_tableau_W();
  2082. //RAZ_tableau_echantillons();
  2083.  
  2084. if(!rapide) { tracer_signal_a_convertir();}
  2085. bit_reverse_tableau_X();
  2086.  
  2087. calcul_FFT(); // 1 FFT s'effectue sur 1 cluster de 1024 échantillons.
  2088. //Le résultat représente un spectre élémentaire correspondant au cluster, c.a.d à une durée = 1024 x 0.5ms = 512 ms
  2089. // ce résultat est retourné dans le tableau 'Complexe tab_X[2048]'
  2090.  
  2091. //if (radioButton_notes->isChecked()) { tracer_notes_FFT(); }
  2092. //else { tracer_modules_FFT(); }
  2093.  
  2094. tracer_notes_FFT();
  2095. }
  2096.  
  2097.  
  2098.  
  2099. void MainWindow::analyse_tout() // FFT de tous les clusters, c.a.d. sur la totalité du signal
  2100. {
  2101.  
  2102. progressBar_1->setVisible(true);
  2103. /*
  2104.   if (wav_ok == false)
  2105.   {
  2106.   QMessageBox msgBox;
  2107.   msgBox.setText("file 'wav' not open");
  2108.   int ret = msgBox.exec();
  2109.   return;
  2110.   }
  2111. */
  2112. /*
  2113.   if (data_nts_ok == false)
  2114.   {
  2115.   QMessageBox msgBox;
  2116.   msgBox.setText("file 'nts' not open");
  2117.   int ret = msgBox.exec();
  2118.   return;
  2119.   }
  2120. */
  2121.  
  2122. QString s1;
  2123. offset_t=0;
  2124. T_i=0; // variable GLOBALE
  2125.  
  2126. uint16_t i_max = data_size / 1024; // = environ 6000
  2127.  
  2128. if (checkBox_debut_seul->isChecked()) {i_max=2000;} // pour gagner du temps lors de la phase de test
  2129.  
  2130.  
  2131. // data_size est affiché par le visualisateur d'entête
  2132. // et aussi dans le LineEdit en bas de l'onglet FFT
  2133. // data_size = de l'ordre de 7MB, ce qui nous donne un i_max d'environ 6900
  2134.  
  2135. effacer_calque(scene4, calque_TAB_FRQ);
  2136. liste_ENR_FFT.clear();
  2137. //clear_temp_data();
  2138. //garnis_temp_data(0);
  2139.  
  2140. // effacer_calque(scene4, calque_gradu_TAB_FRQ);
  2141. // effacer_calque(scene4, calque_notes);
  2142. // effacer_calque(scene4, calque_notes_jouee);
  2143. // effacer_calque(scene4, calque_grille_mesures);
  2144. // effacer_calque(scene4, calque_echelle_temporelle);
  2145.  
  2146. for(uint16_t i=0 ; i<i_max ; i++) // cette boucle sera donc parcourue environ 6000 fois...
  2147. {
  2148. //qDebug() << "i=" << i;
  2149.  
  2150. if ((i % 200) == 0)
  2151. {
  2152. uint16_t pc = 100 * i / i_max;
  2153. pc+=2;
  2154. progressBar_1->setValue(pc);
  2155. // la ligne suivante permet l'affichage de la progression
  2156. QCoreApplication::processEvents(QEventLoop::AllEvents, 1);
  2157. }
  2158. //s1.setNum(i); lineEdit_compteur->setText(s1);
  2159.  
  2160. traitement_signal(); // traitement d'un cluster de 1024 échantillons
  2161. offset_t += 1024; // on passera au cluster de 1024 échantillons suivant c.a.d à un temps + 0.5ms
  2162.  
  2163. }
  2164. progressBar_1->setVisible(false);
  2165.  
  2166. tracer_echelle_temps_TAB_NOTES();
  2167. }
  2168.  
  2169.  
  2170.  
  2171.  
  2172. void MainWindow::on_spinBox_1_valueChanged(int arg1)
  2173. {
  2174. if (arg1==10) { spinBox_1->setValue(0); spinBox_2->stepUp();}
  2175. calcul_ofsset();
  2176. traitement_signal();
  2177. }
  2178.  
  2179.  
  2180. void MainWindow::on_spinBox_2_valueChanged(int arg1)
  2181. {
  2182. if (arg1==-1) {spinBox_2->setValue(9); spinBox_3->stepDown();}
  2183. if (arg1==10) { spinBox_2->setValue(0); spinBox_3->stepUp();}
  2184. calcul_ofsset();
  2185. traitement_signal();
  2186. }
  2187.  
  2188.  
  2189. void MainWindow::on_spinBox_3_valueChanged(int arg1)
  2190. {
  2191. if (arg1==-1) {spinBox_3->setValue(9); spinBox_4->stepDown();}
  2192. if (arg1==10) { spinBox_3->setValue(0); spinBox_4->stepUp();}
  2193. calcul_ofsset();
  2194. traitement_signal();
  2195. }
  2196.  
  2197.  
  2198. void MainWindow::on_spinBox_4_valueChanged(int arg1)
  2199. {
  2200. if (arg1==-1) {spinBox_4->setValue(9); spinBox_5->stepDown();}
  2201. if (arg1==10) { spinBox_4->setValue(0); spinBox_5->stepUp();}
  2202. calcul_ofsset();
  2203. traitement_signal();
  2204. }
  2205.  
  2206.  
  2207. void MainWindow::on_spinBox_5_valueChanged(int arg1)
  2208. {
  2209. if (arg1==-1) {spinBox_5->setValue(9); spinBox_6->stepDown();}
  2210. if (arg1==10) { spinBox_5->setValue(0); spinBox_6->stepUp();}
  2211. calcul_ofsset();
  2212. traitement_signal();
  2213. }
  2214.  
  2215.  
  2216. void MainWindow::on_spinBox_6_valueChanged()
  2217. {
  2218. //if (arg1==-1) {spinBox_6->setValue(9);} //spinBox_6->stepDown();}
  2219. calcul_ofsset();
  2220. traitement_signal();
  2221. }
  2222.  
  2223.  
  2224. void MainWindow::on_doubleSpinBox_1_valueChanged()
  2225. {
  2226. calcul_ofsset();
  2227. traitement_signal();
  2228. }
  2229.  
  2230.  
  2231. void MainWindow::on_pushButton_8_clicked()
  2232. {
  2233. QMessageBox msgBox;
  2234. QString s1;
  2235. s1 = "Le fichier audio à analyser doit être au format unsigned 8 bits PCM";
  2236. s1 += " (généré par exemple avec Audacity)";
  2237. s1 += "\n";
  2238. s1 += "Attention: ce n'est pas le format PCM par défaut, il faut aller dans les sous-menus :";
  2239. s1 += "\n";
  2240. s1 += "Fichier/Exporter/Exporter en WAV / encodage : Unsigned 8-bit PCM";
  2241. s1 += "\n";
  2242. s1 += "Ce n'est pas 'top WiFi', mais largement suffisant pour en faire la FFT et retrouver les notes.";
  2243. s1 += "\n";
  2244. s1 += "Ce qui est le but ici.";
  2245. s1 += "\n";
  2246. s1 += "D'autre part il est vivement conseillé de compresser la dynamique de l'audio (ce qui est simple avec Audacity)";
  2247. s1 += "\n";
  2248. s1 += "ce qui facilite grandement la détection des notes.";
  2249.  
  2250. msgBox.setText(s1);
  2251. msgBox.exec();
  2252. }
  2253.  
  2254.  
  2255. void MainWindow::on_Bt_RAZ_clicked()
  2256. {
  2257. spinBox_1->setValue(0);
  2258. spinBox_2->setValue(0);
  2259. spinBox_3->setValue(0);
  2260. spinBox_4->setValue(0);
  2261. spinBox_5->setValue(0);
  2262. spinBox_6->setValue(0);
  2263. offset_t=0;
  2264. }
  2265.  
  2266.  
  2267. void MainWindow::on_spinBox_7_valueChanged(int arg1)
  2268. {
  2269. // ligne verticale
  2270. effacer_calque(scene1,calque_curseur);
  2271. int x = arg1;
  2272. ligne1 = new QGraphicsLineItem(x, 10, x, 500);
  2273. ligne1->setPen(pen_curseur);
  2274. calque_curseur->addToGroup(ligne1);
  2275.  
  2276. }
  2277.  
  2278.  
  2279.  
  2280.  
  2281. void MainWindow::on_pushButton_2_clicked()
  2282. {
  2283. Timer1->stop();
  2284. nb_tics=0;
  2285. }
  2286.  
  2287.  
  2288. void MainWindow::on_Btn_52_clicked()
  2289. {
  2290. //spinBox_n_midi->setValue(52);
  2291.  
  2292. file_wav.setFileName(nom_fichier_in);
  2293. if (!file_wav.open(QIODevice::ReadOnly))
  2294. {
  2295. wav_ok = false;
  2296. return ;
  2297. }
  2298.  
  2299. wav_ok = true;
  2300.  
  2301. on_Bt_RAZ_clicked();
  2302.  
  2303. binStream1.setDevice(&file_wav);
  2304. calcul_ofsset();
  2305. traitement_signal();
  2306. }
  2307.  
  2308.  
  2309. void MainWindow::on_Btn_94_clicked()
  2310. {
  2311.  
  2312. file_wav.setFileName(nom_fichier_in);
  2313. if (!file_wav.open(QIODevice::ReadOnly))
  2314. {
  2315. wav_ok = false;
  2316. return ;
  2317. }
  2318.  
  2319. wav_ok = true;
  2320.  
  2321. on_Bt_RAZ_clicked();
  2322.  
  2323. binStream1.setDevice(&file_wav);
  2324. calcul_ofsset();
  2325. traitement_signal();
  2326. }
  2327.  
  2328.  
  2329. void MainWindow::on_Bt_efface_clicked()
  2330. {
  2331. QMessageBox msgBox;
  2332. msgBox.setText("Erase Frequences");
  2333. msgBox.setInformativeText("Effacer toutes les FFT ?");
  2334. msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
  2335. msgBox.setDefaultButton(QMessageBox::Cancel);
  2336. int ret = msgBox.exec();
  2337.  
  2338. if (ret == QMessageBox::Ok )
  2339. {
  2340. effacer_calque(scene1,calque_trace_signal1 );
  2341. effacer_calque(scene1,calque_trace_FFT );
  2342. effacer_calque(scene1,calque_lignes_F_zero );
  2343. effacer_calque(scene1,calque_encadrement1 );
  2344. effacer_calque(scene2,calque_encadrement2 );
  2345.  
  2346. effacer_calque(scene4,calque_TAB_FRQ );
  2347. on_Bt_RAZ_clicked();
  2348. T_i=0; // T_i : variable GLOBALE
  2349. }
  2350.  
  2351. }
  2352.  
  2353.  
  2354.  
  2355. void MainWindow::on_pushButton_3_clicked()
  2356. {
  2357.  
  2358. tableWidget_1->setVisible(true);
  2359. Bt_close_entete->setVisible(true);
  2360. }
  2361.  
  2362.  
  2363. void MainWindow::on_Bt_close_entete_clicked()
  2364. {
  2365. tableWidget_1->setVisible(false);
  2366. Bt_close_entete->setVisible(false);
  2367. }
  2368.  
  2369.  
  2370. void MainWindow::on_Bt_close_frame1_clicked()
  2371. {
  2372. frame_1->setVisible(false);
  2373. frame_3->setVisible(true);
  2374. }
  2375.  
  2376.  
  2377. void MainWindow::on_pushButton_4_clicked()
  2378. {
  2379. frame_3->setVisible(false);
  2380. frame_1->setVisible(true);
  2381. }
  2382.  
  2383.  
  2384.  
  2385. void MainWindow::on_pushButton_6_clicked()
  2386. {
  2387. frame_notes->setVisible(false);
  2388. }
  2389.  
  2390.  
  2391.  
  2392. void MainWindow::on_pushButton_5_clicked()
  2393. {
  2394. spinBox_offset->setValue(-2124); // 2154 ; ref -2210 ; +/- 22 pour un décalage de +/-1/4 de ton
  2395. spinBox_echx->setValue(499); // 498
  2396. }
  2397.  
  2398.  
  2399.  
  2400. void MainWindow::save_fichier_FRQ()
  2401. {
  2402. // enregisterment incrémentiel sur le disque (nom de fichier = 1..2...3...)
  2403. ENR_FFT enr_i;
  2404. QString s1;
  2405.  
  2406. long n_max = liste_ENR_FFT.length();
  2407. if (n_max == 0)
  2408. {
  2409. QMessageBox msgBox; msgBox.setText("liste vide !"); msgBox.exec();
  2410. return;
  2411. }
  2412.  
  2413.  
  2414. int numero=0;
  2415. QString s2;
  2416.  
  2417. Timer1->stop();
  2418.  
  2419. bool existe =1;
  2420. while(existe)
  2421. {
  2422. numero++;
  2423. s2.setNum(numero);
  2424. existe = QFile::exists(string_currentDir + "/" + "TAB_FREQ_" + s2 + ".tfrq");
  2425. }
  2426. s2.setNum(numero);
  2427.  
  2428. QFile file1(string_currentDir + "/" + "TAB_FREQ_" + s2 + ".tfrq");
  2429. if (file1.open(QIODevice::WriteOnly | QIODevice::Text))
  2430. {
  2431. QByteArray byteArray1;
  2432. QDataStream stream1(&byteArray1, QIODevice::WriteOnly);
  2433. stream1.setDevice(&file1);
  2434. stream1.setVersion(QDataStream::Qt_6_8);
  2435.  
  2436. // entête 64 octets------------------
  2437. uint8_t d_barre = spinBox_d_barres->value(); // 1 octet
  2438. double dx = doubleSpinBox_dt->value(); // 8 octets
  2439. double x0 = doubleSpinBox_x0->value(); // 8 octets
  2440. stream1 << d_barre << dx << x0; //1+8+8 = 17 octets au début du fichier
  2441. for (int i=0; i<(64-17); i++) {stream1 << 'x';} // complète à 64 octets
  2442. // ----------------------------------
  2443.  
  2444. for(int n=0; n<n_max; n++)
  2445. {
  2446. enr_i = liste_ENR_FFT[n];
  2447. stream1 << enr_i.amplitude << enr_i.midi << enr_i.num << enr_i.t; // sérialisation des data
  2448. }
  2449. }
  2450. file1.close();
  2451.  
  2452. QMessageBox msgBox;
  2453. s1="Fichier enregistré: " + string_currentDir + "/" + "TAB_FREQ_" + s2 + ".tfrq"; msgBox.setText(s1); msgBox.exec();
  2454. }
  2455.  
  2456.  
  2457. void MainWindow::choix_dossier_de_travail()
  2458. {
  2459.  
  2460. QString actuel = string_currentDir;
  2461. string_currentDir = QFileDialog::getExistingDirectory
  2462. (this, tr("Open Directory"), actuel, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  2463.  
  2464. if (string_currentDir != "")
  2465. {
  2466. dossier_de_travail_ok = true;
  2467. save_fichier_ini();
  2468. lineEdit_current_dir->setText(string_currentDir);
  2469. }
  2470. else { dossier_de_travail_ok = false; } // -> si on clique sur le bouton 'cancel'
  2471.  
  2472. }
  2473.  
  2474.  
  2475. void MainWindow::on_Bt_choix_current_dir_clicked()
  2476. {
  2477. choix_dossier_de_travail();
  2478. }
  2479.  
  2480.  
  2481. void MainWindow::load_fichier_FRQ()
  2482. {
  2483.  
  2484. QString filename1;
  2485. QString s1;
  2486.  
  2487. if(dossier_de_travail_ok == false)
  2488. {
  2489. choix_dossier_de_travail();
  2490. if (dossier_de_travail_ok == false)
  2491. {
  2492. QMessageBox msgBox;
  2493. s1="Le dossier de travail n'est pas spécifié";
  2494. msgBox.setText(s1); msgBox.exec();
  2495. return ;
  2496. }
  2497. }
  2498.  
  2499. filename1 = QFileDialog::getOpenFileName(this,
  2500. tr("Ouvrir Fichier tfrq"), string_currentDir + "/", tr("Fichiers tfrq (*.tfrq)"));
  2501.  
  2502.  
  2503. lineEdit_fichier_FREQ->setText(filename1);
  2504.  
  2505. file_dat.setFileName(filename1);
  2506. if (!file_dat.open(QIODevice::ReadOnly))
  2507. {
  2508. data_nts_ok = false;
  2509. return ;
  2510. }
  2511. else
  2512. {
  2513. binStream1.setDevice(&file_dat); // accès à la totalité du fichier dat
  2514. binStream1.setVersion(QDataStream::Qt_6_8);
  2515. data_nts_ok = true;
  2516. liste_ENR_FFT.clear();
  2517. }
  2518.  
  2519. //int z = sizeof(ENR_FFT); // ATTENTION ! ne PAS utiliser cette valeur qui tient en compte l'alignement en RAM
  2520. long n_max = file_dat.bytesAvailable() / 14; // 14 bits par enr; voir la def de 'ENR_FFT' dans le .h
  2521.  
  2522. // lecture entête -----------------
  2523.  
  2524. uint8_t d_barre; // 1 octet
  2525. double dt;
  2526. double x0;
  2527. binStream1 >> d_barre >> dt >> x0; // 1+8+8 = 17 octets au début du fichiers
  2528. uint8_t xx;
  2529. for (int i=0; i<(64-17); i++) {binStream1 >> xx;} // lit en tout à 64 octets libre pour l'avenir
  2530. //---------------------------------
  2531.  
  2532. doubleSpinBox_dt->setValue(dt);
  2533. doubleSpinBox_x0->setValue(x0);
  2534.  
  2535. ENR_FFT enr_i;
  2536. for(int n=0; n<n_max; n++)
  2537. {
  2538. binStream1 >> enr_i.amplitude >> enr_i.midi >> enr_i.num >> enr_i.t;
  2539. liste_ENR_FFT << enr_i;
  2540. }
  2541. file_dat.close();
  2542. retracer_TAB_FRQ();
  2543. spinBox_d_barres->setValue(d_barre);
  2544. }
  2545.  
  2546.  
  2547. void MainWindow::save_fichier_NOTES()
  2548. {
  2549. // enregisterment incrémentiel sur le disque (nom de fichier = 1..2...3...)
  2550. NOTE note_i;
  2551. QString s1;
  2552.  
  2553. double x0 = doubleSpinBox_x0->value();
  2554. double dx = doubleSpinBox_dt->value();
  2555.  
  2556. uint16_t n_max = liste_NOTES.length();
  2557. if (n_max == 0)
  2558. {
  2559. QMessageBox msgBox; msgBox.setText("liste vide !"); msgBox.exec();
  2560. return;
  2561. }
  2562.  
  2563. int numero=0;
  2564. QString s2;
  2565.  
  2566. Timer1->stop();
  2567.  
  2568. bool existe =1;
  2569. while(existe)
  2570. {
  2571. numero++;
  2572. s2.setNum(numero);
  2573. existe = QFile::exists(string_currentDir + "/" + "NOTES_" + s2 + ".nts");
  2574. }
  2575. s2.setNum(numero);
  2576.  
  2577. QFile file1(string_currentDir + "/" + "NOTES_" + s2 + ".nts");
  2578. if (file1.open(QIODevice::WriteOnly | QIODevice::Text))
  2579. {
  2580. QByteArray byteArray1;
  2581. QDataStream stream1(&byteArray1, QIODevice::WriteOnly);
  2582. stream1.setDevice(&file1);
  2583. stream1.setVersion(QDataStream::Qt_6_8);
  2584.  
  2585. // entête 64 octets --------------
  2586. double vts = doubleSpinBox_vitesse->value(); // 8 octets
  2587. stream1 << x0 << dx << vts; //8+8+8 = 24 octets au début du fichier
  2588. for (int i=0; i<(64-24); i++) {stream1 << 'x';} // complète à 64 octets
  2589. //--------------------------------
  2590.  
  2591. for(uint16_t n=0; n<n_max; n++)
  2592. {
  2593. note_i = liste_NOTES[n];
  2594. // sérialisation des data
  2595. stream1 << note_i.numero << note_i.midi << note_i.n_barre << note_i.n_temps << note_i.duree;
  2596. }
  2597. }
  2598. file1.close();
  2599.  
  2600. QMessageBox msgBox;
  2601. s1="Fichier enregistré: " + string_currentDir + "/" + "NOTES_" + s2 + ".nts"; msgBox.setText(s1); msgBox.exec();
  2602. }
  2603.  
  2604.  
  2605.  
  2606. void MainWindow::load_fichier_NOTES()
  2607. {
  2608. QString filename1;
  2609. QString s1;
  2610.  
  2611. if(dossier_de_travail_ok == false)
  2612. {
  2613. choix_dossier_de_travail();
  2614. if (dossier_de_travail_ok == false)
  2615. {
  2616. QMessageBox msgBox;
  2617. s1="Le dossier de travail n'est pas spécifié";
  2618. msgBox.setText(s1); msgBox.exec();
  2619. return ;
  2620. }
  2621. }
  2622.  
  2623. filename1 = QFileDialog::getOpenFileName(this,
  2624. tr("Ouvrir Fichier nts"), string_currentDir+"/", tr("Fichiers nts (*.nts)"));
  2625.  
  2626.  
  2627. lineEdit_fichier->setText(filename1);
  2628.  
  2629. file_dat.setFileName(filename1);
  2630. if (!file_dat.open(QIODevice::ReadOnly))
  2631. {
  2632. data_nts_ok = false;
  2633. return ;
  2634. }
  2635. else
  2636. {
  2637. binStream1.setDevice(&file_dat); // accès à la totalité du fichier dat
  2638. binStream1.setVersion(QDataStream::Qt_6_8);
  2639. data_nts_ok = true;
  2640. }
  2641.  
  2642. //int z = sizeof(NOTE); // ATTENTION ! ne PAS utiliser cette valeur qui tient en compte l'alignement en RAM
  2643. uint16_t n_max = file_dat.bytesAvailable() / 7; // 7 bits par enr; voir la def de 'NOTE' dans le .h
  2644.  
  2645. double x0;
  2646. double dx;
  2647. double vts;
  2648.  
  2649. // lecture entête -----------------
  2650. binStream1 >> x0 >> dx >> vts; // 8+8+8=24 octets au début du fichiers
  2651.  
  2652. uint8_t xx;
  2653. for (int i=0; i<(64-24); i++) {binStream1 >> xx;} // lit en tout à 64 octets
  2654. //---------------------------------
  2655.  
  2656. doubleSpinBox_x0->setValue(x0);
  2657. doubleSpinBox_dt->setValue(dx);
  2658. doubleSpinBox_vitesse->setValue(vts);
  2659.  
  2660. NOTE note_i;
  2661. for(int n=0; n<n_max; n++)
  2662. {
  2663. binStream1 >> note_i.numero >> note_i.midi >> note_i.n_barre >> note_i.n_temps >> note_i.duree;
  2664. note_i.midi += spinBox_transposition->value();
  2665. liste_NOTES << note_i;
  2666. }
  2667.  
  2668. file_dat.close();
  2669.  
  2670. Bt_jouer_tout->setStyleSheet("background-color: rgb(0, 255, 0);"); // vert
  2671.  
  2672. }
  2673.  
  2674.  
  2675. void decalle_notes(int d)
  2676. {
  2677. int nb;
  2678. uint16_t i_max = liste_NOTES.length();
  2679. for( int i =0; i<i_max; i++)
  2680. {
  2681. nb = liste_NOTES[i].n_barre;
  2682. nb += d;
  2683. liste_NOTES[i].n_barre = nb;
  2684. }
  2685.  
  2686. }
  2687.  
  2688.  
  2689. void MainWindow::on_Bt_save_clicked()
  2690. {
  2691. save_fichier_FRQ();
  2692. }
  2693.  
  2694.  
  2695. void MainWindow::on_Bt_load_FREQ_clicked()
  2696. {
  2697. load_fichier_FRQ();
  2698. tracer_echelle_temps_TAB_NOTES();
  2699. }
  2700.  
  2701. void MainWindow::on_checkBox_rapide_stateChanged(int arg1)
  2702. {
  2703. rapide=arg1;
  2704. init_TAB_FRQ();
  2705. }
  2706.  
  2707.  
  2708.  
  2709. void MainWindow::on_doubleSpinBox_seuil_valueChanged(double arg1)
  2710. {
  2711. seuil = arg1;
  2712. effacer_calque(scene4, calque_TAB_FRQ);
  2713. retracer_TAB_FRQ();
  2714. }
  2715.  
  2716.  
  2717. void MainWindow::on_checkBox_norm_clicked()
  2718. {
  2719. if (checkBox_norm->isChecked())
  2720. {
  2721. textEdit_ETAT->setText("Mode Normalisé : \n Les couleurs représentent l'amplitude du signal");
  2722. }
  2723. else
  2724. {
  2725. textEdit_ETAT->setText(
  2726. "Mode Fréquences : \n"
  2727. "Les couleurs représentent la valeur (fréquence) de la note (Do, RE, MI...) \n"
  2728. "La taille de chaque tiret représente (abusivement sur l'axe fréquenciel) l'amplitude du signal \n"
  2729. "cette taille ne signifie donc pas un étalement en fréquence du signal, c'est juste une astuce de représentation."
  2730. );
  2731. }
  2732. effacer_calque(scene4, calque_TAB_FRQ);
  2733. retracer_TAB_FRQ();
  2734. }
  2735.  
  2736.  
  2737.  
  2738. void MainWindow::surbrille_note(uint16_t n)
  2739. {
  2740. double x_note;
  2741.  
  2742. NOTE note_i;
  2743. uint16_t n_max = liste_NOTES.length();
  2744. if ( n>= n_max) {return;}
  2745.  
  2746. note_i = liste_NOTES[n];
  2747. x_note = calcul_x_barre(note_i.n_barre);
  2748.  
  2749. if (checkBox_scrolling->isEnabled())
  2750. {
  2751. double scroll_x = graphicsView4->horizontalScrollBar()->value();
  2752. double diff_x = (2.0*x_note - scroll_x);
  2753. if (diff_x > (memo_scroll_x + 1800))
  2754. {
  2755. graphicsView4->horizontalScrollBar()->setValue(diff_x - 2000);
  2756. memo_scroll_x = diff_x;
  2757. }
  2758. }
  2759.  
  2760. int y;
  2761.  
  2762. int midi_i;
  2763. QString blanc = "#FFFFFF";
  2764.  
  2765. midi_i = note_i.midi;
  2766. y = calcul_y_note(midi_i) ;
  2767.  
  2768. //if (effacer) {effacer_calque(scene4, calque_notes_jouee);}
  2769.  
  2770. QPen pen1;
  2771. pen1.setColor(blanc);
  2772. pen1.setWidth(2);
  2773. ellipse1 = new QGraphicsEllipseItem(x_note-15, y-15, 30, 30) ;
  2774. ellipse1->setPen(pen1);
  2775. //ellipse1->setBrush(blanc);
  2776.  
  2777. calque_notes_jouee->addToGroup(ellipse1);
  2778.  
  2779.  
  2780. }
  2781.  
  2782.  
  2783. void MainWindow::complete_case(int row, int column, QString s1, QString c1, QString c2, bool bold1, QTableWidget *QTI)
  2784. {
  2785. QTableWidgetItem *Item1 = new QTableWidgetItem();
  2786. Item1->QTableWidgetItem::setForeground(QColor(c1));
  2787. Item1->QTableWidgetItem::setBackground(QColor(c2));
  2788.  
  2789. QFont font1;
  2790. font1.setBold(bold1);
  2791. Item1->setFont(font1);
  2792. Item1->setTextAlignment(Qt::AlignCenter);
  2793.  
  2794. Item1->setText(s1);
  2795. QTI->setItem(row,column,Item1);
  2796. }
  2797.  
  2798.  
  2799. void MainWindow::affiche_liste_notes() // en TEXTE dans le petit tableau
  2800. {
  2801. NOTE note_i;
  2802. QString s1;
  2803.  
  2804. tableWidget_lst_notes->clear();
  2805. tableWidget_lst_notes->setRowCount(0);
  2806. init_TAB_lst_notes();
  2807.  
  2808. uint16_t n_max = liste_NOTES.length();
  2809. if (n_max == 0) {return;}
  2810.  
  2811. for(int n=0; n<n_max; n++) //n_max
  2812. {
  2813. note_i=liste_NOTES[n];
  2814.  
  2815. int numero = note_i.numero;
  2816. int midi = note_i.midi;
  2817. int n_barre =note_i.n_barre;
  2818. int n_temps =note_i.n_temps;
  2819. int duree = note_i.duree;
  2820.  
  2821. int num_ligne = tableWidget_lst_notes->rowCount();
  2822. tableWidget_lst_notes->setRowCount(num_ligne+1); // ajout une ligne au tableau
  2823.  
  2824. s1.setNum(numero);
  2825. complete_case(n, 0, s1, "#000000", "#FFFFFF", false, tableWidget_lst_notes);
  2826.  
  2827. s1.setNum(midi);
  2828. int h1 = calcul_hauteur_note(midi); h1-=3; if(h1<0){h1+=12;} if(h1>11){h1-=12;}
  2829. if ((h1<0) || (h1>(liste_couleurs.length()-1))) {h1 = 0;}
  2830.  
  2831. QString couleur1 = liste_couleurs[h1];
  2832. complete_case(n, 1, s1, "#000000", couleur1, true, tableWidget_lst_notes);
  2833.  
  2834. s1 = nom_note(midi);
  2835. complete_case(n, 2, s1, "#000000", "#FFFFFF", false, tableWidget_lst_notes);
  2836.  
  2837. s1.setNum(n_barre);
  2838. complete_case(n, 3, s1, "#000000", "#FFFFFF", false, tableWidget_lst_notes);
  2839.  
  2840. s1.setNum(n_temps); // ok
  2841. complete_case(n, 4, s1, "#000000", "#FFFFFF", true, tableWidget_lst_notes);
  2842.  
  2843. s1.setNum(duree); //ok
  2844. complete_case(n, 5, s1, "#000000", "#FFFFFF", true, tableWidget_lst_notes);
  2845.  
  2846. /*
  2847.   if (duree == 16) {s1 = "R";} // Ronde
  2848.   if (duree == 12) {s1 = "B.";}
  2849.   if (duree == 8) {s1 = "B";} // blanche
  2850.   if (duree == 4) {s1 = "N";} // noire
  2851.   if (duree == 2) {s1 = "c";} // croche
  2852.   if (duree == 1) {s1 = "db_c";} // double croche
  2853.   if (duree == 0) {s1 = "-";}
  2854.   //if (midi == 100) {s1 = "--";}
  2855.  
  2856.   complete_case(n, 6, s1, "#000000", "#FFFFFF", true, tableWidget_lst_notes);
  2857. */
  2858.  
  2859. }
  2860.  
  2861. }
  2862.  
  2863.  
  2864. void MainWindow::calcule_durees_notes()
  2865. {
  2866. int db;
  2867. uint16_t i_max = liste_NOTES.length();
  2868. if (i_max == 0) {return;}
  2869.  
  2870. int n_barre_1;
  2871. int n_barre_2;
  2872.  
  2873. for(int n=0; n<i_max-1; n++) // 'i_max-1' because plus bas on indexe liste_NOTES[n+1] !!!
  2874. {
  2875. n_barre_1 = liste_NOTES[n].n_barre;
  2876. n_barre_2 = liste_NOTES[n+1].n_barre;
  2877. db = n_barre_2 - n_barre_1;
  2878.  
  2879. if (db<0) {db=0;}
  2880. if (db>48){db=48;}
  2881. liste_NOTES[n].duree = db;
  2882. }
  2883. }
  2884.  
  2885.  
  2886.  
  2887. void MainWindow::trace_liste_notes() //dessine des cercles)colorés (couleur midi) sur la grille
  2888. {
  2889. QString s1;
  2890. int db, midi_i;
  2891. float x, dx, dbx, y; //, dy;
  2892. int numero;
  2893. uint16_t n_max = liste_NOTES.length();
  2894. int n_barre_1;
  2895. //int n_barre_2;
  2896. for(int n=0; n<n_max; n++)
  2897. {
  2898. n_barre_1 = liste_NOTES[n].n_barre;
  2899.  
  2900. db = liste_NOTES[n].duree;
  2901. dx = doubleSpinBox_dt->value();
  2902. dbx = (float)db * dx * zoom_x / 2.0 ;
  2903.  
  2904. //if (visu_duree_notes == false) {dbx = 20;} // dessinera 1 note toute ronde
  2905.  
  2906. // x = x0 + (float)n_barre_1 * doubleSpinBox_dt->value()/2.0 * zoom_x;
  2907.  
  2908. x = calcul_x_barre(n_barre_1);
  2909.  
  2910. midi_i = liste_NOTES[n].midi;
  2911.  
  2912. if ((midi_i >=40) && (midi_i <=83) )
  2913. {
  2914. y = calcul_y_note(midi_i);
  2915.  
  2916. int h1 = calcul_hauteur_note(midi_i); h1-=3; if(h1<0){h1+=12;} if(h1>11){h1-=12;}
  2917. QString couleur1 = liste_couleurs[h1];
  2918. QString blanc = "#FFFFFF";
  2919.  
  2920. // rectangle (queue de la note représentant sa durée)
  2921. rect1 = new QGraphicsRectItem(x, y-2, dbx, 4);
  2922. QBrush br1;
  2923. br1.setStyle(Qt::SolidPattern);
  2924. br1.setColor(couleur1);
  2925. rect1->setBrush(br1);
  2926. //rect1->setPen(pen_i);
  2927. calque_notes->addToGroup(rect1);
  2928.  
  2929. ellipse1 = new QGraphicsEllipseItem(x-10, y-10, 20, 20);
  2930. ellipse1->setPen(QColor(blanc));
  2931. ellipse1->setBrush(QColor(couleur1));
  2932. calque_notes->addToGroup(ellipse1);
  2933.  
  2934.  
  2935. // inscrit le numéro de la note au centre de la note
  2936. numero = liste_NOTES[n].numero;
  2937. s1.setNum(numero);
  2938. GraphicsTextItem = new QGraphicsTextItem(s1);
  2939. GraphicsTextItem->setFont(QFont("Arial", 8));
  2940. GraphicsTextItem->setDefaultTextColor("#000000");
  2941. int x2 = x-12; if(numero<10){x2+=4;}
  2942. GraphicsTextItem->setPos(x2, y-10);
  2943. calque_notes->addToGroup(GraphicsTextItem);
  2944. }
  2945. /*
  2946.   if (midi_i == 100) // barre de mesure
  2947.   {
  2948.   ellipse1 = new QGraphicsEllipseItem(x-5, 20, 10, 10);
  2949.  
  2950.   QColor vert = "#00FF00";
  2951.   ellipse1->setBrush(vert);
  2952.   calque_notes->addToGroup(ellipse1);
  2953.   }
  2954. */
  2955. }
  2956. }
  2957.  
  2958.  
  2959. void MainWindow::numerotation_liste_notes()
  2960. {
  2961. uint16_t i_max = liste_NOTES.length();
  2962.  
  2963. for(uint16_t n=0; n<i_max; n++)
  2964. {
  2965. liste_NOTES[n].numero = n;
  2966. }
  2967. }
  2968.  
  2969.  
  2970. void MainWindow::suppression_notes_invalides()
  2971. {
  2972. int midi;
  2973. int nb = 0;
  2974. uint16_t n_max = liste_NOTES.length();
  2975. if (n_max == 0) {return;}
  2976. bool boucler=true;
  2977. do
  2978. {
  2979. nb=0;
  2980. for(uint16_t n=0; n<n_max; n++)
  2981. {
  2982. midi = liste_NOTES[n].midi;
  2983. if ((midi <40) || (midi>82))
  2984. {
  2985. supprime_note(n);
  2986. if (n_max == 0) {return;}
  2987. n_max --;
  2988. nb++;
  2989. }
  2990. }
  2991. if (nb==0) {boucler=false;}
  2992. }
  2993. while (boucler == true);
  2994. }
  2995.  
  2996.  
  2997. void MainWindow::suppression_mesures()
  2998. {
  2999. //int midi;
  3000. uint16_t n_max = liste_NOTES.length();
  3001. int nb = 0;
  3002.  
  3003. bool boucler=true;
  3004. do
  3005. {
  3006. nb=0;
  3007. for(int n=0; n<n_max; n++)
  3008. {
  3009. //midi = liste_NOTES[n].midi;
  3010. /*
  3011.   if (midi == 100) // midi=100 codera pour les barres de mesures
  3012.   {
  3013.   supprime_note(n);
  3014.   n_max --;
  3015.   nb++;
  3016.   }
  3017. */
  3018. }
  3019. if (nb==0) {boucler=false;}
  3020. }
  3021. while (boucler == true);
  3022.  
  3023. }
  3024.  
  3025.  
  3026.  
  3027. void MainWindow::tri_liste_notes_par_num_barre()
  3028. {
  3029.  
  3030. // tri par bulles
  3031.  
  3032. int ba1, ba2; // barres
  3033. NOTE note_i;
  3034. uint16_t i_max = liste_NOTES.length();
  3035. if (i_max==0){return;}
  3036.  
  3037. for(int p=0; p<i_max; p++)
  3038. {
  3039. for(int n=0; n<i_max-1; n++)
  3040. {
  3041. ba1=liste_NOTES[n].n_barre;
  3042. ba2=liste_NOTES[n+1].n_barre;
  3043. if(ba1 > ba2)
  3044. {
  3045. //permutter les notes
  3046. note_i = liste_NOTES[n];
  3047. liste_NOTES[n] = liste_NOTES[n+1];
  3048. liste_NOTES[n+1] = note_i;
  3049. }
  3050. }
  3051. }
  3052. }
  3053.  
  3054.  
  3055.  
  3056. void MainWindow::ajout_note(int midi, int B, int T)
  3057. {
  3058. NOTE note_i;
  3059. note_i.midi = midi;
  3060. note_i.n_barre = B; // valeur discrete, entière : numéro de la barre de la grille temporelle
  3061. note_i.n_temps = T; // numero au sein de la mesure
  3062. liste_NOTES << note_i;
  3063. }
  3064.  
  3065.  
  3066.  
  3067.  
  3068. void MainWindow::supprime_note(uint16_t n)
  3069. {
  3070. int L = liste_NOTES.length();
  3071. if (L==0) {return;}
  3072.  
  3073. if ((n>=0) && (n<L))
  3074. {
  3075. liste_NOTES.remove(n);
  3076. effacer_calque(scene4,calque_notes);
  3077. tri_liste_notes_par_num_barre(); //les notes seront triées par temps croissant
  3078.  
  3079. numerotation_liste_notes(); //les notes seront numérotées par temps croissant
  3080.  
  3081. trace_liste_notes();
  3082. }
  3083. }
  3084.  
  3085.  
  3086.  
  3087. int MainWindow::test_if_note_in_liste(uint16_t n_barre, int midi)
  3088. {
  3089. // retourne la position dans la liste, sinon zéro;
  3090. uint16_t barre_i;
  3091. int midi_i;
  3092. int i_max = liste_NOTES.length();
  3093. for(int n=0; n<i_max; n++)
  3094. {
  3095. barre_i = liste_NOTES[n].n_barre;
  3096. midi_i = liste_NOTES[n].midi;
  3097.  
  3098. if ((barre_i == n_barre) && (midi_i == midi))
  3099. {
  3100. return n;
  3101. }
  3102. }
  3103. return -1;
  3104. }
  3105.  
  3106.  
  3107. void MainWindow::affi_txt_en_couleur(int midi_i, QLineEdit *lineEdit_i)
  3108. {
  3109. int h1 = calcul_hauteur_note(midi_i); h1-=3; if(h1<0){h1+=12;} if(h1>11){h1-=12;}
  3110. if ((h1<0) || (h1>(liste_couleurs.length()-1))) {h1 = 0;}
  3111. QString c1 = liste_couleurs[h1];
  3112. QString c2 = "#000000";
  3113. lineEdit_i->setStyleSheet("color: " + c1 + "; background-color: " + c2 + "; font: 700 14pt 'Ubuntu';");
  3114. }
  3115.  
  3116.  
  3117.  
  3118. void MainWindow::encadre_midi(int n_midi)
  3119. {
  3120. if (n_midi>82) {return;}
  3121.  
  3122. effacer_calque(scene3, calque_gradu_TAB_FRQ);
  3123. tracer_graduation_TAB_NOTES();
  3124. double x, dx, y, dy;
  3125.  
  3126. int dm = n_midi -40;
  3127. y = 645 - (dm * 16);
  3128.  
  3129. dy=16;
  3130. x=0;
  3131. dx=85;
  3132.  
  3133. rectangle1 = new QGraphicsRectItem(x, y, dx, dy);
  3134. QPen pen1;
  3135. pen1.setColor("#FFFFFF");
  3136. pen1.setWidth(2);
  3137. rectangle1->setPen(pen1);
  3138. calque_gradu_TAB_FRQ->addToGroup(rectangle1);
  3139. }
  3140.  
  3141.  
  3142. void MainWindow::mousePressEvent(QMouseEvent *event)
  3143. {
  3144. if (tabWidget_Global->currentIndex() != 1) {return;}
  3145.  
  3146. QString s1;
  3147. float x0, y0; // position cliquée, libre
  3148.  
  3149. int n_barre=0; // numero de la barre verticale de la grille temporelle (depuis le départ)
  3150. int n_temps=0; // numero de la barre verticale de la grille temporelle (au sein de la mesure)
  3151. int n2;
  3152.  
  3153. float x_barre=0;
  3154. float x_min, x_max;
  3155. float y_min, y_max;
  3156.  
  3157. int midi=0; // midi
  3158.  
  3159. float scroll_x = graphicsView4->horizontalScrollBar()->value();
  3160. float scroll_y = graphicsView4->verticalScrollBar()->value();
  3161.  
  3162. graphicsView4->verticalScrollBar()->setValue(0);
  3163.  
  3164. s1.setNum(scroll_x); lineEdit_8->setText(s1);
  3165. s1.setNum(scroll_y); lineEdit_9->setText(s1);
  3166.  
  3167. x_min = graphicsView4->x();
  3168. x_max = x_min + graphicsView4->width();
  3169.  
  3170. y_min = graphicsView4->y()+60;
  3171. y_max = y_min + graphicsView4->height() + 32; // +32 sinon rate le mi grave (midi 40)
  3172.  
  3173. x_clic_ecran = event->position().x();
  3174. y_clic_ecran = event->position().y();
  3175.  
  3176. x0 = x_clic_ecran-102 + scroll_x; // position cliquée
  3177. y0 = y_clic_ecran-78 + scroll_y;
  3178.  
  3179.  
  3180. if (0) // 1 pour test (petite croix)
  3181. {
  3182. int d=10; // taille
  3183. QPen pen1; pen1.setColor("#FFFF00");
  3184. ligne1 = new QGraphicsLineItem(x0-d, y0-d, x0+d, y0+d);
  3185. ligne1->setPen(pen1);
  3186. calque_notes->addToGroup(ligne1);
  3187. ligne1 = new QGraphicsLineItem(x0-d, y0+d, x0+d, y0-d);
  3188. ligne1->setPen(pen1);
  3189. calque_notes->addToGroup(ligne1);
  3190. }
  3191. // ----------------------
  3192.  
  3193. if (x_clic_ecran > x_min && x_clic_ecran < x_max && y_clic_ecran > y_min && y_clic_ecran < y_max)
  3194. {
  3195. s1.setNum(x0); lineEdit_4->setText(s1);
  3196. s1.setNum(y0); lineEdit_5->setText(s1); // =481 foire !
  3197.