mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Makes an unsuccessful attempt at producing audio.
On the plus side, it does seem successfully to sniff out an appropriate audio format and to communicate mono/stereo onward.
This commit is contained in:
parent
e47cb91223
commit
378ff39e5e
@ -1,4 +1,4 @@
|
|||||||
QT += core gui
|
QT += core gui multimedia
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
@ -142,9 +142,17 @@ void MainWindow::launchMachine() {
|
|||||||
|
|
||||||
switch(error) {
|
switch(error) {
|
||||||
default: {
|
default: {
|
||||||
|
// TODO: correct assumptions herein that this is the first machine to be
|
||||||
|
// assigned to this window.
|
||||||
ui->missingROMsBox->setVisible(false);
|
ui->missingROMsBox->setVisible(false);
|
||||||
uiPhase = UIPhase::RunningMachine;
|
uiPhase = UIPhase::RunningMachine;
|
||||||
|
|
||||||
|
// Install user-friendly options. TODO: plus user overrides.
|
||||||
|
// const auto configurable = machine->configurable_device();
|
||||||
|
// if(configurable) {
|
||||||
|
// configurable->set_options(configurable->get_options());
|
||||||
|
// }
|
||||||
|
|
||||||
// Supply the scan target.
|
// Supply the scan target.
|
||||||
// TODO: in the future, hypothetically, deal with non-scan producers.
|
// TODO: in the future, hypothetically, deal with non-scan producers.
|
||||||
const auto scan_producer = machine->scan_producer();
|
const auto scan_producer = machine->scan_producer();
|
||||||
@ -152,6 +160,33 @@ void MainWindow::launchMachine() {
|
|||||||
scan_producer->set_scan_target(ui->openGLWidget->getScanTarget());
|
scan_producer->set_scan_target(ui->openGLWidget->getScanTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Install audio output if required.
|
||||||
|
const auto audio_producer = machine->audio_producer();
|
||||||
|
if(audio_producer) {
|
||||||
|
const auto speaker = audio_producer->get_speaker();
|
||||||
|
if(speaker) {
|
||||||
|
const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultOutputDevice();
|
||||||
|
QAudioFormat idealFormat = defaultDeviceInfo.preferredFormat();
|
||||||
|
|
||||||
|
// Use the ideal format's sample rate, provide stereo as long as at least two channels
|
||||||
|
// are available, and — at least for now — assume 512 samples/buffer is a good size.
|
||||||
|
audioIsStereo = (idealFormat.channelCount() > 1) && speaker->get_is_stereo();
|
||||||
|
audioIs8bit = idealFormat.sampleSize() < 16;
|
||||||
|
const int samplesPerBuffer = 512;
|
||||||
|
speaker->set_output_rate(idealFormat.sampleRate(), samplesPerBuffer, audioIsStereo);
|
||||||
|
|
||||||
|
// Adjust format appropriately, and create an audio output.
|
||||||
|
idealFormat.setChannelCount(1 + int(audioIsStereo));
|
||||||
|
idealFormat.setSampleSize(audioIs8bit ? 8 : 16);
|
||||||
|
audioOutput = std::make_unique<QAudioOutput>(idealFormat, this);
|
||||||
|
audioOutput->setBufferSize(samplesPerBuffer * (audioIsStereo ? 2 : 1) * (audioIs8bit ? 1 : 2));
|
||||||
|
|
||||||
|
// Start the output.
|
||||||
|
speaker->set_delegate(this);
|
||||||
|
audioIODevice = audioOutput->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If this is a timed machine, start up the timer.
|
// If this is a timed machine, start up the timer.
|
||||||
const auto timedMachine = machine->timed_machine();
|
const auto timedMachine = machine->timed_machine();
|
||||||
if(timedMachine) {
|
if(timedMachine) {
|
||||||
@ -189,6 +224,12 @@ void MainWindow::launchMachine() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::speaker_did_complete_samples(Outputs::Speaker::Speaker *, const std::vector<int16_t> &buffer) {
|
||||||
|
const auto bytesWritten = audioIODevice->write(reinterpret_cast<const char *>(buffer.data()), qint64(buffer.size()));
|
||||||
|
// qDebug() << bytesWritten << "; " << audioOutput->state();
|
||||||
|
(void)bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::dragEnterEvent(QDragEnterEvent* event) {
|
void MainWindow::dragEnterEvent(QDragEnterEvent* event) {
|
||||||
// Always accept dragged files.
|
// Always accept dragged files.
|
||||||
if(event->mimeData()->hasUrls())
|
if(event->mimeData()->hasUrls())
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QAudioOutput>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
@ -13,7 +15,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
namespace Ui { class MainWindow; }
|
namespace Ui { class MainWindow; }
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow, public Outputs::Speaker::Speaker::Delegate {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
void createActions();
|
void createActions();
|
||||||
@ -49,6 +51,11 @@ class MainWindow : public QMainWindow {
|
|||||||
std::unique_ptr<Machine::DynamicMachine> machine;
|
std::unique_ptr<Machine::DynamicMachine> machine;
|
||||||
std::mutex machineMutex;
|
std::mutex machineMutex;
|
||||||
|
|
||||||
|
std::unique_ptr<QAudioOutput> audioOutput;
|
||||||
|
QIODevice *audioIODevice = nullptr;
|
||||||
|
bool audioIs8bit = false, audioIsStereo = false;
|
||||||
|
void speaker_did_complete_samples(Outputs::Speaker::Speaker *speaker, const std::vector<int16_t> &buffer) override;
|
||||||
|
|
||||||
bool processEvent(QKeyEvent *);
|
bool processEvent(QKeyEvent *);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
Loading…
Reference in New Issue
Block a user