Compare commits

...

10 Commits

Author SHA1 Message Date
50ebac998c Add a feature based dummy implementation
Some checks failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
ci/woodpecker/push/code_tests Pipeline failed
2025-12-01 22:42:06 +01:00
Nikolai Rodionov
af97801d31 Trying to come up with the structure
Some checks failed
ci/woodpecker/push/code_tests Pipeline failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
2025-12-01 14:35:28 +01:00
dcb6d7b0ea Update protos
Some checks failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
ci/woodpecker/push/code_tests Pipeline failed
Signed-off-by: Nikolai Rodionov <allanger@badhouseplants.net>
2025-12-01 12:37:11 +01:00
2385d3901f Adding backend discovery
Some checks failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
ci/woodpecker/push/code_tests Pipeline failed
Signed-off-by: Nikolai Rodionov <allanger@badhouseplants.net>
2025-11-30 22:41:48 +01:00
85aac6c8aa Add grpc reflections
Some checks failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
ci/woodpecker/push/code_tests Pipeline failed
Signed-off-by: Nikolai Rodionov <allanger@badhouseplants.net>
2025-11-30 19:06:52 +01:00
61c5799ffc Keep adding irrelevant stuff
Some checks failed
ci/woodpecker/push/pre_commit_test Pipeline failed
ci/woodpecker/push/code_tests Pipeline failed
2025-11-30 16:55:27 +01:00
8a6227d382 Keep adding irrelevant stuff
Some checks failed
ci/woodpecker/push/pre_commit_test Pipeline failed
ci/woodpecker/push/code_tests Pipeline failed
2025-11-30 14:22:16 +01:00
86566221b1 Start implementing the grpc
Some checks failed
ci/woodpecker/push/code_tests Pipeline failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
Signed-off-by: Nikolai Rodionov <allanger@badhouseplants.net>
2025-11-30 13:06:58 +01:00
2052178ebf Trying to use the prost
Some checks failed
ci/woodpecker/push/code_tests Pipeline failed
ci/woodpecker/push/pre_commit_test Pipeline failed
2025-11-28 19:18:04 +01:00
Nikolai Rodionov
56aa1e1bbf Trying to add protoc
Some checks failed
ci/woodpecker/push/code_tests Pipeline failed
ci/woodpecker/push/pre_commit_test Pipeline was successful
2025-11-28 17:07:02 +01:00
19 changed files with 2023 additions and 43 deletions

2
.codespellrc Normal file
View File

@@ -0,0 +1,2 @@
[codespell]
ignore-words-list = ratatui

1744
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
[workspace] [workspace]
resolver = "3" resolver = "3"
members = ["engine", "examples/jack-sine", "lib"] members = ["engine", "examples/jack-sine", "lib", "tui"]
[workspace.dependencies] [workspace.dependencies]

View File

@@ -1,2 +1,8 @@
# termix # termix
[![status-badge](https://ci.badhouseplants.net/api/badges/19/status.svg)](https://ci.badhouseplants.net/repos/19) [![status-badge](https://ci.badhouseplants.net/api/badges/19/status.svg)](https://ci.badhouseplants.net/repos/19)
# Requirenments
On all systems:
- protoc

View File

@@ -4,9 +4,17 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
clap = { version = "4.5.53", features = ["derive"] }
coreaudio-rs = { version = "0.13.0", optional = true } coreaudio-rs = { version = "0.13.0", optional = true }
env_logger = "0.11.8"
jack = {version = "0.13.3", optional = true } jack = {version = "0.13.3", optional = true }
lib = { path = "../lib/" } lib = { path = "../lib/" }
log = "0.4.28"
prost = "0.14.1"
tokio = { version = "1.48.0", features = ["rt-multi-thread"] }
tonic = "0.14.2"
tonic-prost = "0.14.2"
tonic-reflection = "0.14.2"
[features] [features]
jack = ["dep:jack"] jack = ["dep:jack"]

View File

@@ -0,0 +1,46 @@
use crate::audio_engine::AudioBackend;
pub(crate) struct JackAudioBackend {
pub(crate) feature_jack: bool,
pub(crate) running: bool,
}
impl JackAudioBackend {
pub(crate) fn new() -> Self {
let feature_jack = cfg!(feature = "jack");
// TODO: It should be retrieved from the system
let running = true;
Self { feature_jack, running }
}
}
#[cfg(feature = "jack")]
impl AudioBackend for JackAudioBackend {
fn start_client(&self) {
todo!()
}
fn init_client(&self) {
todo!()
}
fn discover(&self) {
todo!()
}
}
#[cfg(not(feature = "jack"))]
impl AudioBackend for JackAudioBackend {
fn start_client(&self) {
unimplemented!()
}
fn init_client(&self) {
unimplemented!()
}
fn discover(&self) {
unimplemented!()
}
}

View File

@@ -1,12 +1,12 @@
mod jack; pub(crate) mod jack_ab;
mod coreaudio;
trait AudioBackend { pub(crate) trait AudioBackend {
// Start a audio backend client // Start a audio backend client
// It should be executed either on the startup, // It should be executed either on the startup,
// or when the audio backend is switched // or when the audio backend is switched
fn start_client(); fn start_client(&self);
// Initialization of the client should happen // Initialization of the client should happen
// when a project is opened. // when a project is opened.
fn init_client(); fn init_client(&self);
fn discover(&self);
} }

View File

@@ -0,0 +1,9 @@
use crate::control_pane::ControlPane;
struct Dummy {}
impl ControlPane for Dummy {
async fn start_server(&self) -> Result<(), Box<dyn std::error::Error>> {
todo!()
}
}

View File

@@ -0,0 +1,74 @@
use lib::termix::audio_backend::{
self, Backend, BackendList, FILE_DESCRIPTOR_SET,
audio_backend_server::{AudioBackend, AudioBackendServer},
};
use log::info;
use tonic::{Response, transport::Server};
use tonic_reflection::server;
use crate::{audio_engine::jack_ab::JackAudioBackend, control_pane::ControlPane};
pub(crate) struct Grpc {
pub(crate) port: i32,
pub(crate) enable_reflections: bool,
}
impl ControlPane for Grpc {
async fn start_server(&self) -> Result<(), Box<dyn std::error::Error>> {
info!("starting the grpc server on port {}", self.port);
// TODO: Use the port from self
let addr = "[::1]:50051".parse()?;
let mut server = Server::builder();
let audio_backend_reflections = server::Builder::configure()
.register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET)
.build_v1()
.unwrap();
let audio_backend = TermixAudioBackend::default();
server
.add_service(audio_backend_reflections)
.add_service(AudioBackendServer::new(audio_backend))
.serve(addr)
.await?;
Ok(())
}
}
#[derive(Debug, Default)]
pub struct TermixAudioBackend {}
#[tonic::async_trait]
impl AudioBackend for TermixAudioBackend {
async fn start_client(
&self,
requesa: tonic::Request<()>,
) -> std::result::Result<tonic::Response<()>, tonic::Status> {
info!("starting the audio backend client");
todo!()
}
async fn init_connection(
&self,
request: tonic::Request<()>,
) -> std::result::Result<tonic::Response<()>, tonic::Status> {
info!("initializing the connection to the audio backend");
todo!()
}
async fn get_available_backends(
&self,
request: tonic::Request<()>,
) -> Result<Response<BackendList>, tonic::Status> {
info!("discovering available backends");
let mut response = BackendList::default();
let jack = JackAudioBackend::new();
if jack.feature_jack {
response.backends.push(Backend {
name: "jack".to_string(),
});
}
Ok(Response::new(response))
}
}

View File

@@ -0,0 +1,6 @@
pub(crate) mod dummy;
pub(crate) mod grpc;
pub(crate) trait ControlPane {
async fn start_server(&self) -> Result<(), Box<dyn std::error::Error>>;
}

View File

@@ -1,35 +1,29 @@
mod audio_engine; pub(crate) mod audio_engine;
pub(crate) mod control_pane;
use lib::{self, metadata::Metadata, track::Track}; use crate::control_pane::ControlPane;
use clap::Parser;
fn main() { /// Simple program to greet a person
let mut current_project = lib::project::Project { #[derive(Parser, Debug)]
name: "test".to_string(), #[command(version, about, long_about = None)]
tracks: None, struct Args {
regions: None, #[arg(long, default_value_t = 50051)]
current_sample: 0, grpc_port: i32,
}; #[arg(long, default_value_t = true)]
grpc_enable_reflections: bool,
let track = Track { }
metadata: Metadata::new("test".to_string()),
track_type: lib::track::TrackType::Audio, #[tokio::main]
active: true, async fn main() -> Result<(), Box<dyn std::error::Error>> {
}; env_logger::init();
let args = Args::parse();
current_project.tracks = Some(vec![track]);
let grpc_control_pane = control_pane::grpc::Grpc {
/* port: args.grpc_port,
* Engine should run and wait for commands, enable_reflections: args.grpc_enable_reflections,
* but currently I need to implement the multitrack };
* audio player somehow grpc_control_pane.start_server().await?;
*
* Ok(())
* for track in tracks {
* if track.is_region_playing(now: time) {
* let current_region = track.get_current_region(now: time)
* let audio = current_region.get_data(now: time)
* }
* }
*/
println!("Hello, world!");
} }

View File

@@ -4,4 +4,13 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
prost = "0.14.1"
tokio = { version = "1.48.0", features = ["rt-multi-thread"] }
tonic = "0.14.2"
tonic-prost = "0.14.2"
uuid = { version = "1.18.1", features = ["v4"] } uuid = { version = "1.18.1", features = ["v4"] }
[build-dependencies]
prost-build = "0.14.1"
prost-types = "0.14.1"
tonic-prost-build = "0.14.2"

17
lib/build.rs Normal file
View File

@@ -0,0 +1,17 @@
use std::{env, io::Result, path::PathBuf};
fn main() -> Result<()> {
//let proto_dir = "proto";
//let paths = fs::read_dir(proto_dir).unwrap();
//for path in paths {
// prost_build::compile_protos(&[path.unwrap().path()], &[proto_dir])?;
//}
//
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
tonic_prost_build::configure()
.file_descriptor_set_path(out_dir.join("audio_backend_descriptor.bin"))
.compile_protos(&["proto/audio_backend.proto"], &["proto"])
.unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e));
Ok(())
}

View File

@@ -0,0 +1,22 @@
syntax = "proto3";
package termix.audio_backend;
import "google/protobuf/empty.proto";
service AudioBackend {
rpc StartClient(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc InitConnection(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc GetAvailableBackends(google.protobuf.Empty) returns (BackendList);
}
message BackendList {
repeated Backend backends = 1;
}
message Backend {
string name = 1;
}
message Shirt {
google.protobuf.Empty dummy = 1;
}

View File

@@ -1,5 +1,7 @@
pub mod metadata; pub mod termix {
pub mod audio_backend {
pub mod project; pub const FILE_DESCRIPTOR_SET: &[u8] =
pub mod region; tonic::include_file_descriptor_set!("audio_backend_descriptor");
pub mod track; tonic::include_proto!("termix.audio_backend");
}
}

10
tui/Cargo.toml Normal file
View File

@@ -0,0 +1,10 @@
[package]
name = "tui"
version = "0.1.0"
edition = "2024"
[dependencies]
clap = { version = "4.5.53", features = ["derive"] }
color-eyre = "0.6.5"
crossterm = "0.29.0"
ratatui = "0.29.0"

31
tui/src/main.rs Normal file
View File

@@ -0,0 +1,31 @@
use clap::Parser;
use color_eyre::Result;
use crossterm::event::{self, Event};
use ratatui::{DefaultTerminal, Frame};
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {}
fn main() -> Result<()> {
let _ = Args::parse();
color_eyre::install()?;
let terminal = ratatui::init();
let result = run(terminal);
ratatui::restore();
result
}
fn run(mut terminal: DefaultTerminal) -> Result<()> {
loop {
terminal.draw(render)?;
if matches!(event::read()?, Event::Key(_)) {
break Ok(());
}
}
}
fn render(frame: &mut Frame) {
frame.render_widget("hello world", frame.area());
}