| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,123 @@ |
| 1 |
+/* |
|
| 2 |
+ * Author: Pawel Jablonski |
|
| 3 |
+ * E-mail: pj@xirx.net |
|
| 4 |
+ * WWW: xirx.net |
|
| 5 |
+ * GIT: git.xirx.net |
|
| 6 |
+ * |
|
| 7 |
+ * License: You can use this code however you like |
|
| 8 |
+ * but leave information about the original author. |
|
| 9 |
+ * Code is free for non-commercial and commercial use. |
|
| 10 |
+ */ |
|
| 11 |
+ |
|
| 12 |
+#ifndef SPEAKER_H |
|
| 13 |
+#define SPEAKER_H |
|
| 14 |
+ |
|
| 15 |
+#include <QObject> |
|
| 16 |
+#include <QList> |
|
| 17 |
+#include <QAudioFormat> |
|
| 18 |
+#include <QAudioOutput> |
|
| 19 |
+#include <QByteArray> |
|
| 20 |
+#include <QScopedPointer> |
|
| 21 |
+ |
|
| 22 |
+//! This class contains speaker functions |
|
| 23 |
+class Speaker : public QObject |
|
| 24 |
+{
|
|
| 25 |
+ Q_OBJECT |
|
| 26 |
+ |
|
| 27 |
+ public: |
|
| 28 |
+ static const int SAMPLE_RATE = 44100; //!< Sampple rate in Hz |
|
| 29 |
+ |
|
| 30 |
+ static const int BUFFER_SIZE = 32; //!< Size of the buffer |
|
| 31 |
+ |
|
| 32 |
+ static const int NOTE_QUANTITY = 89; //!< Note quantity available to play |
|
| 33 |
+ |
|
| 34 |
+ static const int TIME_MIN = 1; //!< Minimum time to play for a note in ms multiplied by TIME_MUL |
|
| 35 |
+ static const int TIME_MAX = 250; //!< Maximum time to play for a note in ms multiplied by TIME_MUL |
|
| 36 |
+ static constexpr double TIME_MUL = 10.0; //!< Time multiplicator for a note |
|
| 37 |
+ |
|
| 38 |
+ static const int FILL_MIN = 1; //!< Minimum fill of the square wave in percents divided by FILL_DIV |
|
| 39 |
+ static const int FILL_MAX = 15; //!< Maximum fill of the square wave in percents divided by FILL_DIV |
|
| 40 |
+ static const int FILL_MASK = 0x0f; //!< Mask for the fill value |
|
| 41 |
+ static constexpr double FILL_DIV = 16.0; //!< Square wave fill divider |
|
| 42 |
+ |
|
| 43 |
+ static const int VOLUME_MASK = 0x0f; //!< Mask for the volume value |
|
| 44 |
+ static constexpr double VOLUME_MAX = 15.0; //!< Maximum volume level |
|
| 45 |
+ |
|
| 46 |
+ static constexpr double VALUE_MUL = 127.0; //!< Output level multiplicator used to conversion |
|
| 47 |
+ static constexpr double VALUE_VOLUME = 0.3; //!< Output volume level multiplicator |
|
| 48 |
+ |
|
| 49 |
+ //! Fields used by speaker to describe note |
|
| 50 |
+ struct Note |
|
| 51 |
+ {
|
|
| 52 |
+ unsigned char note; //!< Number of the note |
|
| 53 |
+ unsigned char time; //!< Time to play |
|
| 54 |
+ unsigned char fill; //!< Square wave fill |
|
| 55 |
+ unsigned char volume; //!< Volume level |
|
| 56 |
+ }; |
|
| 57 |
+ |
|
| 58 |
+ Speaker(QObject *parent = nullptr); |
|
| 59 |
+ ~Speaker() override; |
|
| 60 |
+ |
|
| 61 |
+ Speaker(const Speaker &) = delete; |
|
| 62 |
+ Speaker &operator=(const Speaker &) = delete; |
|
| 63 |
+ Speaker(Speaker &&) = delete; |
|
| 64 |
+ Speaker &operator=(Speaker &&) = delete; |
|
| 65 |
+ |
|
| 66 |
+ void reset(); |
|
| 67 |
+ |
|
| 68 |
+ void setVolume(unsigned int volume); |
|
| 69 |
+ |
|
| 70 |
+ void clear(); |
|
| 71 |
+ void addNote(const Speaker::Note ¬e); |
|
| 72 |
+ |
|
| 73 |
+ unsigned char getBufferFree(); |
|
| 74 |
+ |
|
| 75 |
+ private: |
|
| 76 |
+ //! List of possible notes to play |
|
| 77 |
+ enum NoteCode |
|
| 78 |
+ {
|
|
| 79 |
+ NOTE_SILENT, |
|
| 80 |
+ NOTE_A0, NOTE_AS0, NOTE_B0, |
|
| 81 |
+ NOTE_C1, NOTE_CS1, NOTE_D1, NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1, NOTE_B1, |
|
| 82 |
+ NOTE_C2, NOTE_CS2, NOTE_D2, NOTE_DS2, NOTE_E2, NOTE_F2, NOTE_FS2, NOTE_G2, NOTE_GS2, NOTE_A2, NOTE_AS2, NOTE_B2, |
|
| 83 |
+ NOTE_C3, NOTE_CS3, NOTE_D3, NOTE_DS3, NOTE_E3, NOTE_F3, NOTE_FS3, NOTE_G3, NOTE_GS3, NOTE_A3, NOTE_AS3, NOTE_B3, |
|
| 84 |
+ NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4, |
|
| 85 |
+ NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5, |
|
| 86 |
+ NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6, |
|
| 87 |
+ NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7, |
|
| 88 |
+ NOTE_C8 |
|
| 89 |
+ }; |
|
| 90 |
+ |
|
| 91 |
+ //! List of frequencies for notes |
|
| 92 |
+ QVector<int> noteFrequency = QVector<int>({
|
|
| 93 |
+ 20, // Silent |
|
| 94 |
+ 27, 29, 31, // A0 - B0 |
|
| 95 |
+ 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, // C1 - B1 |
|
| 96 |
+ 65, 69, 73, 78, 82, 87, 93, 98, 104, 110, 117, 123, // C2 - B2 |
|
| 97 |
+ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, // C3 - B3 |
|
| 98 |
+ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, // C4 - B4 |
|
| 99 |
+ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, // C5 - B5 |
|
| 100 |
+ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, // C6 - B6 |
|
| 101 |
+ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, // C7 - B7 |
|
| 102 |
+ 4186 // C8 |
|
| 103 |
+ }); |
|
| 104 |
+ |
|
| 105 |
+ bool playing; //!< Playing status |
|
| 106 |
+ QList<struct Note> buffer; //!< Buffer of notes |
|
| 107 |
+ |
|
| 108 |
+ QAudioFormat audioFormat; //!< Audio stream parameter information |
|
| 109 |
+ QScopedPointer<QAudioOutput> audioOutput; //!< Interface to an audio output device |
|
| 110 |
+ QIODevice *ioDevice; //!< IO device retuned by QAudioOutput |
|
| 111 |
+ |
|
| 112 |
+ QByteArray bufferOut; //!< Raw buffer with prepared data ready to send to IO device |
|
| 113 |
+ |
|
| 114 |
+ void playNextNote(); |
|
| 115 |
+ |
|
| 116 |
+ signals: |
|
| 117 |
+ void updateStatusSignal(int bufferUsed); |
|
| 118 |
+ |
|
| 119 |
+ private slots: |
|
| 120 |
+ void audioNotifySlot(); |
|
| 121 |
+}; |
|
| 122 |
+ |
|
| 123 |
+#endif |