2024-12-26 11:48:03 +08:00
|
|
|
#include <iostream>
|
2024-12-26 16:18:43 +08:00
|
|
|
#include <thread>
|
|
|
|
#include <cstdint>
|
2024-12-26 11:48:03 +08:00
|
|
|
|
2024-12-26 12:33:11 +08:00
|
|
|
#include <GLFW/glfw3.h>
|
2024-12-26 16:18:43 +08:00
|
|
|
#include <sndio.h>
|
2024-12-26 17:33:59 +08:00
|
|
|
#include <poll.h>
|
2024-12-26 16:18:43 +08:00
|
|
|
#include <math.h>
|
2024-12-26 12:33:11 +08:00
|
|
|
|
|
|
|
#include "imgui.h"
|
|
|
|
#include "imgui_impl_glfw.h"
|
|
|
|
#include "imgui_impl_opengl3.h"
|
|
|
|
|
2024-12-26 16:18:43 +08:00
|
|
|
static std::atomic<bool> shutdown_threads;
|
|
|
|
static std::atomic<float> frequency = 440.0f;
|
|
|
|
|
|
|
|
#define SND_SIG 1
|
|
|
|
#define SND_BITS 16
|
|
|
|
#define SND_PCHAN 2
|
2024-12-26 17:45:59 +08:00
|
|
|
#define SND_RCHAN 1
|
2024-12-26 16:18:43 +08:00
|
|
|
#define SND_RATE 44100
|
|
|
|
#define SND_BUFLEN 4096
|
|
|
|
|
|
|
|
static void dsp_thread()
|
|
|
|
{
|
|
|
|
struct sio_hdl *hdl;
|
|
|
|
struct sio_par par;
|
|
|
|
|
2024-12-26 17:45:59 +08:00
|
|
|
hdl = sio_open(SIO_DEVANY, SIO_PLAY|SIO_REC, 1);
|
2024-12-26 16:18:43 +08:00
|
|
|
if(hdl == nullptr) {
|
|
|
|
std::cerr << "failed to open sound device" << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sio_initpar(&par);
|
|
|
|
par.sig = SND_SIG;
|
|
|
|
par.bits = SND_BITS;
|
|
|
|
par.pchan = SND_PCHAN;
|
2024-12-26 17:45:59 +08:00
|
|
|
par.pchan = SND_RCHAN;
|
2024-12-26 16:18:43 +08:00
|
|
|
par.rate = SND_RATE;
|
|
|
|
par.le = SIO_LE_NATIVE;
|
2024-12-26 17:33:59 +08:00
|
|
|
par.xrun = SIO_ERROR;
|
2024-12-26 16:18:43 +08:00
|
|
|
if(!sio_setpar(hdl, &par)) {
|
|
|
|
std::cerr << "failed to set sound device parameters" << std::endl;
|
|
|
|
sio_close(hdl);
|
|
|
|
return;
|
|
|
|
}
|
2024-12-26 17:33:59 +08:00
|
|
|
if(!sio_getpar(hdl, &par)) {
|
|
|
|
std::cerr << "failed to get back sound device parameters" << std::endl;
|
|
|
|
sio_close(hdl);
|
|
|
|
return;
|
|
|
|
}
|
2024-12-26 16:18:43 +08:00
|
|
|
|
|
|
|
if(!sio_start(hdl)) {
|
|
|
|
std::cerr << "failed to start sound device" << std::endl;
|
|
|
|
sio_close(hdl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t phase = 0;
|
2024-12-26 17:33:59 +08:00
|
|
|
|
|
|
|
int16_t buf_out[SND_BUFLEN*SND_PCHAN];
|
|
|
|
size_t buf_out_idx = SND_BUFLEN*SND_PCHAN;
|
|
|
|
nfds_t nfds = sio_nfds(hdl);
|
|
|
|
struct pollfd pfd[nfds];
|
2024-12-26 17:45:59 +08:00
|
|
|
|
2024-12-26 16:18:43 +08:00
|
|
|
while(!shutdown_threads) {
|
2024-12-26 17:45:59 +08:00
|
|
|
sio_pollfd(hdl, pfd, POLLOUT|POLLIN);
|
2024-12-26 17:33:59 +08:00
|
|
|
poll(pfd, nfds, INFTIM);
|
|
|
|
int revents = sio_revents(hdl, pfd);
|
|
|
|
|
|
|
|
if(revents & POLLOUT) {
|
|
|
|
if(buf_out_idx == SND_BUFLEN*SND_PCHAN) {
|
2024-12-26 17:45:59 +08:00
|
|
|
uint32_t ftw = frequency*(float)UINT32_MAX/SND_RATE;
|
2024-12-26 17:33:59 +08:00
|
|
|
for(int i=0;i<SND_BUFLEN;i++) {
|
2024-12-27 15:10:15 +08:00
|
|
|
buf_out[2*i] = buf_out[2*i+1] = (INT16_MAX-1)*sinf(phase*2.0f*(float)M_PI/(float)UINT32_MAX);
|
2024-12-26 17:33:59 +08:00
|
|
|
phase += ftw;
|
|
|
|
}
|
|
|
|
buf_out_idx = 0;
|
|
|
|
}
|
|
|
|
size_t written = sio_write(hdl, &buf_out[buf_out_idx], sizeof(buf_out) - buf_out_idx*sizeof(buf_out[0]));
|
|
|
|
buf_out_idx += written/sizeof(buf_out[0]);
|
2024-12-26 17:45:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(revents & POLLIN) {
|
|
|
|
int16_t buf_in[SND_BUFLEN*SND_RCHAN];
|
|
|
|
sio_read(hdl, buf_in, sizeof(buf_in));
|
|
|
|
for(int i=0;i<10;i++)
|
|
|
|
std::cout << buf_in[i] << " ";
|
|
|
|
std::cout << std::endl;
|
2024-12-26 16:18:43 +08:00
|
|
|
}
|
2024-12-27 15:14:08 +08:00
|
|
|
|
|
|
|
if(sio_eof(hdl)) {
|
|
|
|
std::cerr << "sound I/O error" << std::endl;
|
|
|
|
sio_close(hdl);
|
|
|
|
return;
|
|
|
|
}
|
2024-12-26 16:18:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
sio_stop(hdl);
|
|
|
|
sio_close(hdl);
|
|
|
|
}
|
|
|
|
|
2024-12-26 12:33:11 +08:00
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
if(!glfwInit()) {
|
|
|
|
std::cerr << "failed to initialize GLFW" << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
std::atexit(glfwTerminate);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
|
|
static GLFWwindow* window = glfwCreateWindow(1024, 768, "sndlock", nullptr, nullptr);
|
|
|
|
if(window == nullptr) {
|
|
|
|
std::cerr << "failed to create GLFW window" << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static auto DestroyWindow = []() {
|
|
|
|
glfwDestroyWindow(window);
|
|
|
|
};
|
|
|
|
std::atexit(DestroyWindow);
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
glfwSwapInterval(1);
|
|
|
|
|
|
|
|
IMGUI_CHECKVERSION();
|
|
|
|
ImGui::CreateContext();
|
|
|
|
static auto ImGuiDestroyContext = []() {
|
|
|
|
ImGui::DestroyContext();
|
|
|
|
};
|
|
|
|
std::atexit(ImGuiDestroyContext);
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
|
|
|
std::atexit(ImGui_ImplGlfw_Shutdown);
|
|
|
|
ImGui_ImplOpenGL3_Init("#version 130");
|
|
|
|
std::atexit(ImGui_ImplOpenGL3_Shutdown);
|
|
|
|
|
2024-12-26 16:18:43 +08:00
|
|
|
static std::thread dsp_thread_h = std::thread(dsp_thread);
|
|
|
|
static auto JoinDSP = []() {
|
|
|
|
dsp_thread_h.join();
|
|
|
|
};
|
|
|
|
std::atexit(JoinDSP);
|
|
|
|
|
|
|
|
shutdown_threads = false;
|
|
|
|
static auto SetShutdown = []() {
|
|
|
|
shutdown_threads = true;
|
|
|
|
};
|
|
|
|
std::atexit(SetShutdown);
|
|
|
|
|
2024-12-26 12:33:11 +08:00
|
|
|
bool exit = false;
|
|
|
|
while(!exit && !glfwWindowShouldClose(window)) {
|
|
|
|
glfwPollEvents();
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
|
|
ImGui_ImplGlfw_NewFrame();
|
|
|
|
ImGui::NewFrame();
|
|
|
|
|
|
|
|
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
|
|
|
|
ImGui::SetNextWindowSize(io.DisplaySize);
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
|
|
|
ImGui::Begin("sndlock", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize);
|
|
|
|
|
2024-12-26 16:18:43 +08:00
|
|
|
float frequency_l = frequency;
|
|
|
|
ImGui::SliderFloat("Frequency", &frequency_l, 50.0f, 8000.0f);
|
|
|
|
frequency = frequency_l;
|
2024-12-26 12:33:11 +08:00
|
|
|
if(ImGui::Button("Exit"))
|
|
|
|
exit = true;
|
|
|
|
|
|
|
|
ImGui::End();
|
|
|
|
ImGui::PopStyleVar(1);
|
|
|
|
|
|
|
|
ImGui::Render();
|
|
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
|
|
int display_w, display_h;
|
|
|
|
glfwGetFramebufferSize(window, &display_w, &display_h);
|
|
|
|
glViewport(0, 0, display_w, display_h);
|
|
|
|
glfwSwapBuffers(window);
|
|
|
|
}
|
|
|
|
|
2024-12-26 11:48:03 +08:00
|
|
|
return 0;
|
|
|
|
}
|