1 #include "qsoundout.h"
2 #include "QAudioFormat"
3 
QSoundOut(QObject * parent)4 QSoundOut::QSoundOut(QObject *parent) :
5     QObject(parent)
6 {
7     rcnt = 0;
8     rrd = 0;
9     rwr = 0;
10     fptr = 0;
11     m_audio = nullptr;
12     m_dev = nullptr;
13 
14     QAudioFormat fmt;
15     fmt.setSampleRate(SAMPLERATE);
16     fmt.setChannelCount(CHANNELS);
17     fmt.setSampleSize(SAMPLESIZE);
18     fmt.setByteOrder(QAudioFormat::LittleEndian);
19     fmt.setCodec("audio/pcm");
20     fmt.setSampleType(QAudioFormat::SignedInt);
21 
22     m_audio = new QAudioOutput(fmt, this);
23     if (m_audio == nullptr)
24         return;
25     connect(m_audio, SIGNAL(notify()), this, SLOT(OnNotify()));
26     m_audio->setBufferSize(FRAMEBYTES * 2);
27     m_audio->setNotifyInterval(40); //1/25 sec = 40mS
28     m_dev = m_audio->start();
29     if (m_dev == nullptr)
30     {
31         disconnect(this, SLOT(OnNotify()));
32         delete(m_audio);
33         m_audio = nullptr;
34         return;
35     }
36 
37     m_kick.setSingleShot(true);
38     m_kick.connect(&m_kick, SIGNAL(timeout()), this, SLOT(OnNotify()));
39     m_kick.start(40); //kick it first!
40 }
41 
~QSoundOut()42 QSoundOut::~QSoundOut()
43 {
44     if (m_dev)
45     {
46         m_audio->stop();
47         disconnect(this, SLOT(OnNotify()));
48         delete(m_audio); //this will delete m_dev too!!!!
49         m_audio = nullptr;
50     }
51 }
52 
OnNotify()53 void QSoundOut::OnNotify()
54 {
55     char dummy[FRAMEBYTES];
56 
57     if ((m_dev == nullptr) || (m_audio == nullptr))
58         return;
59 
60     m_lock.lock();
61     if (rcnt)
62     {
63         m_dev->write((const char*)&rbuf[rrd], (qint64)FRAMEBYTES);
64         rrd++;
65         if (rrd >= BUFFERS)
66             rrd = 0;
67         rcnt--;
68     }
69     else
70     {
71         memset(dummy, 0, FRAMEBYTES);
72         m_dev->write((const char*)dummy, (qint64)FRAMEBYTES);
73     }
74     m_lock.unlock();
75 }
76 
FeedDAC(unsigned short left,unsigned short right)77 void QSoundOut::FeedDAC(unsigned short left, unsigned short right)
78 {
79     if ((m_dev == nullptr) || (m_audio == nullptr))
80         return;
81     switch (SAMPLESIZE)
82     {
83     case 8:
84         fbuf[fptr++] = left >> 8;
85         fbuf[fptr++] = right >> 8;
86         break;
87     case 16:
88         fbuf[fptr++] = left & 0xff;
89         fbuf[fptr++] = left >> 8;
90         fbuf[fptr++] = right & 0xff;
91         fbuf[fptr++] = right >> 8;
92         break;
93     }
94     if (fptr >= FRAMEBYTES)
95     {
96         fptr = 0;
97         m_lock.lock();
98         if (rcnt >= BUFFERS)
99         {
100             m_dev->write((const char*)&rbuf[rrd], (qint64)FRAMEBYTES);
101             rrd++;
102             if (rrd >= BUFFERS)
103                 rrd = 0;
104             rcnt--;
105         }
106         memcpy(&rbuf[rwr], fbuf, FRAMEBYTES);
107         rwr++;
108         if (rwr >= BUFFERS)
109             rwr = 0;
110         rcnt++;
111         m_lock.unlock();
112     }
113 }
114