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