Verified Commit 6673c294 authored by Phobos D'thorga's avatar Phobos D'thorga 🐲
Browse files

Introducing microphone functionality.

parent 74de645f
......@@ -231,6 +231,7 @@ if(WIN32)
src/audio_devices.hpp
src/spectro_fftw.hpp
src/spectro_gui.hpp
src/pa_mic.hpp
src/string_funcs_windows.hpp)
elseif(UNIX)
qt5_wrap_cpp(UI_MOC
......@@ -244,6 +245,7 @@ elseif(UNIX)
src/audio_devices.hpp
src/spectro_fftw.hpp
src/spectro_gui.hpp
src/pa_mic.hpp
src/string_funcs_linux.hpp)
elseif(APPLE)
message(SEND_ERROR "We do not currently support compilation for Apple Mac OS/X systems at this stage. Sorry!")
......@@ -273,6 +275,7 @@ if(WIN32)
src/audio_devices.cpp
src/spectro_fftw.cpp
src/spectro_gui.cpp
src/pa_mic.cpp
src/string_funcs_windows.cpp)
elseif(UNIX)
set(GALAXY_UI_CPP
......@@ -287,6 +290,7 @@ elseif(UNIX)
src/audio_devices.cpp
src/spectro_fftw.cpp
src/spectro_gui.cpp
src/pa_mic.cpp
src/string_funcs_linux.cpp)
elseif(APPLE)
message(SEND_ERROR "We do not currently support compilation for Apple Mac OS/X systems at this stage. Sorry!")
......
......@@ -65,6 +65,7 @@ public:
std::vector<GekkoFyre::Database::Settings::Audio::Device> defaultAudioDevices();
std::vector<double> enumSupportedStdSampleRates(const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters);
std::vector<GekkoFyre::Database::Settings::Audio::Device> enumAudioDevices();
void portAudioErr(const PaError &err);
void testSinewave(const GekkoFyre::Database::Settings::Audio::Device &device);
void volumeSetting();
double vuMeter();
......@@ -82,7 +83,6 @@ private:
static void streamFinished(void *userData);
bool filterAudioInputEnum(const PaHostApiTypeId &host_api_type);
bool filterAudioOutputEnum(const PaHostApiTypeId &host_api_type);
void portAudioErr(const PaError &err);
};
};
......@@ -95,7 +95,7 @@ namespace GekkoFyre {
#define AUDIO_OUTPUT_CHANNEL_MIN_LIMIT (-1024)
#define AUDIO_INPUT_CHANNEL_MAX_LIMIT (1024)
#define AUDIO_INPUT_CHANNEL_MIN_LIMIT (-1024)
#define AUDIO_FRAMES_PER_BUFFER (256) // Frames per buffer, i.e. the number of sample frames that PortAudio will request from the callback. Many apps may want to use paFramesPerBufferUnspecified, which tells PortAudio to pick the best, possibly changing, buffer size
#define AUDIO_FRAMES_PER_BUFFER (512) // Frames per buffer, i.e. the number of sample frames that PortAudio will request from the callback. Many apps may want to use paFramesPerBufferUnspecified, which tells PortAudio to pick the best, possibly changing, buffer size
#define AUDIO_TEST_SAMPLE_LENGTH_SEC (3)
#define AUDIO_TEST_SAMPLE_TABLE_SIZE (200)
#define AUDIO_SPEC_FLOOR_DECIBELS (-180.0)
......@@ -214,18 +214,10 @@ namespace Database {
std::string message;
};
struct Spectrum {
Device audio_dev;
size_t speclen;
fftw_plan plan;
double max_freq;
double min_freq;
double *window;
double linear_floor;
double mag_to_norm;
double *time_domain;
double *freq_domain;
double *mag_spec;
struct paRecData {
int frameIndex;
int maxFrameIndex;
int *rec_samples;
};
}
}
......
/**
** ______ ______ ___ ___ ______ ______ ______ ______
** /_____/\/_____/\/___/\/__/\/_____/\/_____/\/_____/\/_____/\
** \:::_ \ \::::_\/\::.\ \\ \ \:::_ \ \:::_ \ \::::_\/\:::_ \ \
** \:\ \ \ \:\/___/\:: \/_) \ \:\ \ \ \:\ \ \ \:\/___/\:(_) ) )_
** \:\ \ \ \::___\/\:. __ ( (\:\ \ \ \:\ \ \ \::___\/\: __ `\ \
** \:\/.:| \:\____/\: \ ) \ \\:\_\ \ \:\/.:| \:\____/\ \ `\ \ \
** \____/_/\_____\/\__\/\__\/ \_____\/\____/_/\_____\/\_\/ \_\/
**
**
** If you have downloaded the source code for "Dekoder for Morse" and are reading this,
** then thank you from the bottom of our hearts for making use of our hard work, sweat
** and tears in whatever you are implementing this into!
**
** Copyright (C) 2020. GekkoFyre.
**
** Dekoder for Morse is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Dekoder is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Dekoder for Morse. If not, see <http://www.gnu.org/licenses/>.
**
**
** The latest source code updates can be obtained from [ 1 ] below at your
** discretion. A web-browser or the 'git' application may be required.
**
** [ 1 ] - https://code.gekkofyre.io/phobos-dthorga/small-world-deluxe
**
****************************************************************************************************/
#include "pa_mic.hpp"
#include <boost/circular_buffer.hpp>
#include <vector>
using namespace GekkoFyre;
using namespace GekkoFyre;
using namespace Database;
using namespace Settings;
using namespace Audio;
/**
* @brief PaMic::PaMic handles most microphone functions via PortAudio.
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param parent
*/
PaMic::PaMic(std::shared_ptr<AudioDevices> gkAudio, QObject *parent) : QObject(parent)
{
gkAudioDevices = gkAudio;
}
PaMic::~PaMic()
{}
/**
* @brief PaMic::recordMic Record from a selected/given microphone device on the user's computing device.
* @author Phil Burk <http://www.softsynth.com> <https://github.com/EddieRingle/portaudio/blob/master/examples/paex_record.c>
* Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param device
* @param total_sec_record
*/
void PaMic::recordMic(const Device &device, PaStream *stream, const int &total_sec_record)
{
PaError err = paNoError;
paRecData data;
int totalFrames;
int numSamples;
int numBytes;
data.maxFrameIndex = totalFrames = total_sec_record * device.def_sample_rate;
data.frameIndex = 0;
numSamples = totalFrames * device.dev_input_channel_count;
numBytes = numSamples * sizeof(int);
data.rec_samples = (int *)malloc(numBytes); // From now on, `rec_samples` is initialised
if (data.rec_samples == nullptr) {
throw std::runtime_error(tr("Could not allocate record array.").toStdString());
}
for (int i = 0; i < numSamples; ++i) {
data.rec_samples[i] = 0;
}
err = Pa_OpenStream(&stream, &device.stream_parameters, nullptr, device.def_sample_rate, AUDIO_FRAMES_PER_BUFFER, paClipOff, nullptr, nullptr);
if (err != paNoError) {
gkAudioDevices->portAudioErr(err);
}
err = Pa_StartStream(stream);
if (err != paNoError) {
gkAudioDevices->portAudioErr(err);
}
//
// Keep a 'circular buffer' within memory
// https://www.boost.org/doc/libs/1_72_0/doc/html/circular_buffer.html
//
boost::circular_buffer<float> cb(4096);
Pa_Sleep(5000);
while((err = Pa_IsStreamActive(stream)) == 1) {
if (err != paNoError) {
gkAudioDevices->portAudioErr(err);
}
}
return;
}
/**
** ______ ______ ___ ___ ______ ______ ______ ______
** /_____/\/_____/\/___/\/__/\/_____/\/_____/\/_____/\/_____/\
** \:::_ \ \::::_\/\::.\ \\ \ \:::_ \ \:::_ \ \::::_\/\:::_ \ \
** \:\ \ \ \:\/___/\:: \/_) \ \:\ \ \ \:\ \ \ \:\/___/\:(_) ) )_
** \:\ \ \ \::___\/\:. __ ( (\:\ \ \ \:\ \ \ \::___\/\: __ `\ \
** \:\/.:| \:\____/\: \ ) \ \\:\_\ \ \:\/.:| \:\____/\ \ `\ \ \
** \____/_/\_____\/\__\/\__\/ \_____\/\____/_/\_____\/\_\/ \_\/
**
**
** If you have downloaded the source code for "Small World Deluxe" and are reading this,
** then thank you from the bottom of our hearts for making use of our hard work, sweat
** and tears in whatever you are implementing this into!
**
** Copyright (C) 2020. GekkoFyre.
**
** Small World Deluxe is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Small World is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Small World Deluxe. If not, see <http://www.gnu.org/licenses/>.
**
**
** The latest source code updates can be obtained from [ 1 ] below at your
** discretion. A web-browser or the 'git' application may be required.
**
** [ 1 ] - https://code.gekkofyre.io/phobos-dthorga/small-world-deluxe
**
****************************************************************************************************/
#pragma once
#include "src/defines.hpp"
#include "src/audio_devices.hpp"
#include <portaudio.h>
#include <QObject>
#include <memory>
namespace GekkoFyre {
class PaMic : public QObject {
Q_OBJECT
public:
explicit PaMic(std::shared_ptr<GekkoFyre::AudioDevices> gkAudio, QObject *parent = nullptr);
~PaMic() override;
void recordMic(const GekkoFyre::Database::Settings::Audio::Device &device, PaStream *stream, const int &total_sec_record);
private:
std::shared_ptr<GekkoFyre::AudioDevices> gkAudioDevices;
};
};
......@@ -169,15 +169,18 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
std::thread t1(&MainWindow::infoBar, this);
t1.detach();
// The spectrometer must listen to the chosen *output* audio device
Device output_audio_dev;
// The spectrometer must listen to the chosen *input* audio device
Device input_audio_dev;
for (const auto &device: pref_audio_devices) {
if (device.is_output_dev == true) {
output_audio_dev = device;
if (device.is_output_dev == false) {
input_audio_dev = device;
break;
}
}
gkPaMic = std::make_shared<GekkoFyre::PaMic>(gkAudioDevices, this);
gkPaMic->recordMic(input_audio_dev, &micStream, 30);
QPointer<SpectroDialog> dlg_spectro = new SpectroDialog(this);
dlg_spectro->setWindowFlags(Qt::Tool | Qt::Dialog);
dlg_spectro->show();
......@@ -203,6 +206,11 @@ MainWindow::~MainWindow()
spectro_thread.join();
}
err = Pa_CloseStream(&micStream);
if (err != paNoError) {
gkAudioDevices->portAudioErr(err);
}
delete db;
delete timer;
Pa_Terminate();
......
......@@ -37,9 +37,11 @@
#pragma once
#include "src/defines.hpp"
#include "src/file_io.hpp"
#include "src/dek_db.hpp"
#include "src/audio_devices.hpp"
#include "src/pa_mic.hpp"
#include "src/radiolibs.hpp"
#include <boost/filesystem.hpp>
#include <memory>
......@@ -50,6 +52,17 @@
#include <QMultiMap>
#include <QChart>
#ifdef __cplusplus
extern "C"
{
#endif
#include <portaudio.h>
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef _WIN32
#include "src/string_funcs_windows.hpp"
#elif __linux__
......@@ -102,16 +115,20 @@ private:
std::shared_ptr<GekkoFyre::FileIo> fileIo;
std::shared_ptr<GekkoFyre::DekodeDb> dekodeDb;
std::shared_ptr<GekkoFyre::AudioDevices> gkAudioDevices;
std::shared_ptr<GekkoFyre::PaMic> gkPaMic;
std::shared_ptr<GekkoFyre::StringFuncs> gkStringFuncs;
std::shared_ptr<GekkoFyre::RadioLibs> gkRadioLibs;
std::future<GekkoFyre::AmateurRadio::Control::Radio *> rig_thread;
std::thread spectro_thread;
std::vector<GekkoFyre::Database::Settings::Audio::Device> pref_audio_devices; // The configured audio devices for the user's system
std::vector<GekkoFyre::Database::Settings::Audio::Device> pref_audio_devices; // The configured audio devices for the user's system
GekkoFyre::AmateurRadio::Control::Radio *radio;
QTimer *timer;
PaError err = paNoError;
std::shared_ptr<PaStream> micStream;
void radioStats(GekkoFyre::AmateurRadio::Control::Radio *radio_dev);
void procVuMeter(const GekkoFyre::Database::Settings::Audio::Device &audio_stream);
};
......@@ -66,4 +66,6 @@ void SpectroDialog::on_pushButton_reset_clicked()
{}
void SpectroDialog::on_pushButton_exit_clicked()
{}
{
this->close();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment