File indexing completed on 2024-05-12 16:23:35
0001 /*************************************************************************** 0002 * Copyright (C) 2017 by Linuxstopmotion contributors; * 0003 * see the AUTHORS file for details. * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 0021 #include "qtaudiodriver.h" 0022 #include "src/foundation/logger.h" 0023 #include "src/technical/audio/audioformat.h" 0024 0025 #include <QAudioFormat> 0026 #include <QAudioDeviceInfo> 0027 #include <QIODevice> 0028 #include <QAudioOutput> 0029 0030 #include <stdint.h> 0031 #include <algorithm> 0032 #include <list> 0033 #include <vector> 0034 0035 class QtAudioDriver::Impl : public QIODevice { 0036 Q_OBJECT 0037 static const int buffer_size = 4096; 0038 typedef int16_t sample_t; 0039 QAudioFormat audioFormat; 0040 QAudioOutput* output; 0041 std::list<AudioFormat*> sounds; 0042 std::vector<sample_t> buffer; 0043 public: 0044 Impl() : output(0), buffer(buffer_size) { 0045 QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); 0046 audioFormat.setSampleRate(44100); 0047 audioFormat.setChannelCount(2); 0048 audioFormat.setByteOrder(QAudioFormat::LittleEndian); 0049 audioFormat.setSampleType(QAudioFormat::UnSignedInt); 0050 audioFormat.setSampleSize(16); 0051 QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); 0052 if (!info.isFormatSupported(audioFormat)) { 0053 // Trying to find out what Qt thinks it CAN do!... 0054 info = QAudioDeviceInfo::defaultOutputDevice(); 0055 audioFormat = info.nearestFormat(audioFormat); 0056 // Is this OK? 0057 } 0058 output = new QAudioOutput(info, audioFormat); 0059 setOpenMode(ReadOnly); 0060 } 0061 ~Impl() { 0062 delete output; 0063 } 0064 void addSound(AudioFormat* a) { 0065 a->reset(); 0066 sounds.push_back(a); 0067 Logger::get().logDebug("Added sound"); 0068 emit output->stateChanged(QAudio::ActiveState); 0069 } 0070 qint64 readData(char *data, qint64 maxlen) { 0071 std::list<AudioFormat*>::iterator s = sounds.begin(); 0072 int len = 0; 0073 for (; s != sounds.end(); ++s) { 0074 len = (*s)->fillBuffer(data, maxlen); 0075 if (len != 0) 0076 break; 0077 sounds.pop_front(); 0078 s = sounds.begin(); 0079 } 0080 while (s != sounds.end()) { 0081 if (mixSound(*s, reinterpret_cast<int16_t*>(data), len)) 0082 ++s; 0083 else 0084 s = sounds.erase(s); 0085 } 0086 if (len == 0) { 0087 emit output->stateChanged(QAudio::IdleState); 0088 Logger::get().logDebug("out of sound"); 0089 return 0; 0090 } 0091 Logger::get().logDebug("Sent data %d", len); 0092 return len; 0093 } 0094 qint64 writeData(const char *, qint64) { 0095 return 0; 0096 } 0097 void play() { 0098 output->start(this); 0099 } 0100 void stop() { 0101 output->stop(); 0102 } 0103 private: 0104 // returns false if s is exhausted after the call 0105 bool mixSound(AudioFormat* s, sample_t* out, unsigned long length) { 0106 char* buf = reinterpret_cast<char*>(&*buffer.begin()); 0107 while (0 < length) { 0108 int len2 = s->fillBuffer(buf, 0109 std::min(length, (unsigned long)buffer_size * sizeof(sample_t))); 0110 if (len2 == 0) { 0111 return false; 0112 } 0113 length -= len2; 0114 int samples = len2 / sizeof(sample_t); 0115 for (int i = 0; i != samples; ++i) { 0116 *out += buf[i]; 0117 ++out; 0118 } 0119 } 0120 return true; 0121 } 0122 }; 0123 0124 QtAudioDriver::QtAudioDriver() : impl(0) { 0125 impl = new Impl(); 0126 } 0127 0128 QtAudioDriver::~QtAudioDriver() { 0129 delete impl; 0130 } 0131 0132 void QtAudioDriver::play() { 0133 } 0134 0135 void QtAudioDriver::playInThread() { 0136 impl->play(); 0137 } 0138 0139 void QtAudioDriver::addAudioFile(AudioFormat* audioFile) { 0140 impl->addSound(audioFile); 0141 } 0142 0143 bool QtAudioDriver::initialize() { 0144 return true; 0145 } 0146 0147 void QtAudioDriver::shutdown() { 0148 impl->stop(); 0149 } 0150 0151 #include "qtaudiodriver.moc"