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"