@devaloop/devalang 0.0.1-beta.1 → 0.0.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devalang +9 -10
- package/Cargo.toml +5 -4
- package/README.md +7 -5
- package/docs/CHANGELOG.md +42 -0
- package/docs/ROADMAP.md +5 -1
- package/docs/TODO.md +3 -14
- package/examples/bus.deva +10 -0
- package/examples/effect.deva +2 -0
- package/examples/filter.deva +11 -0
- package/examples/lfo.deva +9 -0
- package/examples/synth.deva +11 -1
- package/examples/synth_types.deva +17 -0
- package/out-tsc/core/functions/index.d.ts +5 -0
- package/out-tsc/core/functions/index.js +11 -0
- package/out-tsc/pkg/devalang_core.d.ts +2 -0
- package/out-tsc/pkg/devalang_core.js +17 -2
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +8 -7
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/bank/api.rs +122 -122
- package/rust/cli/bank/commands.rs +33 -2
- package/rust/cli/bank/mod.rs +29 -29
- package/rust/cli/build/commands.rs +53 -3
- package/rust/cli/build/mod.rs +2 -2
- package/rust/cli/build/process.rs +26 -7
- package/rust/cli/check/mod.rs +2 -2
- package/rust/cli/discover/commands.rs +253 -253
- package/rust/cli/discover/config.rs +111 -111
- package/rust/cli/discover/fs.rs +19 -19
- package/rust/cli/discover/install.rs +103 -103
- package/rust/cli/discover/metadata.rs +48 -48
- package/rust/cli/discover/mod.rs +5 -5
- package/rust/cli/install/addon.rs +118 -118
- package/rust/cli/install/bank.rs +22 -3
- package/rust/cli/install/commands.rs +35 -35
- package/rust/cli/install/mod.rs +4 -4
- package/rust/cli/install/plugin.rs +80 -61
- package/rust/cli/login/commands.rs +124 -124
- package/rust/cli/mod.rs +12 -12
- package/rust/cli/parser.rs +46 -1
- package/rust/cli/play/commands.rs +71 -20
- package/rust/cli/play/mod.rs +5 -5
- package/rust/cli/play/process.rs +14 -5
- package/rust/cli/play/realtime.rs +91 -91
- package/rust/cli/telemetry/commands.rs +22 -22
- package/rust/cli/telemetry/event_creator.rs +80 -80
- package/rust/cli/telemetry/mod.rs +3 -3
- package/rust/cli/telemetry/send.rs +51 -51
- package/rust/cli/template/commands.rs +69 -69
- package/rust/config/driver.rs +112 -103
- package/rust/config/mod.rs +3 -3
- package/rust/config/ops.rs +26 -26
- package/rust/config/settings.rs +101 -101
- package/rust/core/audio/engine/driver.rs +220 -0
- package/rust/core/audio/engine/export.rs +169 -0
- package/rust/core/audio/engine/helpers.rs +178 -170
- package/rust/core/audio/engine/mod.rs +51 -2
- package/rust/core/audio/engine/notes/dsp.rs +85 -0
- package/rust/core/audio/engine/notes/mod.rs +44 -0
- package/rust/core/audio/engine/notes/params.rs +294 -0
- package/rust/core/audio/engine/sample/insert.rs +199 -0
- package/rust/core/audio/engine/sample/mod.rs +40 -0
- package/rust/core/audio/engine/sample/padding.rs +170 -0
- package/rust/core/audio/evaluator/condition.rs +61 -0
- package/rust/core/audio/evaluator/mod.rs +9 -0
- package/rust/core/audio/{evaluator.rs → evaluator/numeric.rs} +1 -159
- package/rust/core/audio/evaluator/rhs.rs +16 -0
- package/rust/core/audio/evaluator/string_expr.rs +94 -0
- package/rust/core/audio/interpreter/driver.rs +55 -23
- package/rust/core/audio/interpreter/mod.rs +1 -13
- package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +175 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +384 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +2 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +316 -0
- package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
- package/rust/core/audio/interpreter/{automate.rs → statements/automate.rs} +16 -18
- package/rust/core/audio/interpreter/{call.rs → statements/call.rs} +5 -4
- package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +2 -1
- package/rust/core/audio/interpreter/{function.rs → statements/function.rs} +2 -4
- package/rust/core/audio/interpreter/{let_.rs → statements/let_.rs} +2 -4
- package/rust/core/audio/interpreter/{load.rs → statements/load.rs} +2 -4
- package/rust/core/audio/interpreter/{loop_.rs → statements/loop_.rs} +2 -1
- package/rust/core/audio/interpreter/statements/mod.rs +12 -0
- package/rust/core/audio/interpreter/{sleep.rs → statements/sleep.rs} +28 -28
- package/rust/core/audio/interpreter/{spawn.rs → statements/spawn.rs} +3 -2
- package/rust/core/audio/interpreter/{tempo.rs → statements/tempo.rs} +40 -40
- package/rust/core/audio/interpreter/{trigger.rs → statements/trigger.rs} +1 -1
- package/rust/core/audio/loader/trigger.rs +2 -1
- package/rust/core/audio/mod.rs +6 -7
- package/rust/core/audio/player.rs +70 -70
- package/rust/core/audio/special/easing.rs +189 -189
- package/rust/core/audio/special/env.rs +45 -45
- package/rust/core/audio/special/math.rs +134 -134
- package/rust/core/audio/special/mod.rs +9 -9
- package/rust/core/audio/special/modulator.rs +143 -143
- package/rust/core/builder/mod.rs +45 -2
- package/rust/core/debugger/lexer.rs +27 -27
- package/rust/core/debugger/{module.rs → logs.rs} +3 -6
- package/rust/core/debugger/mod.rs +30 -30
- package/rust/core/debugger/preprocessor.rs +27 -27
- package/rust/core/debugger/store.rs +2 -4
- package/rust/core/error/mod.rs +269 -269
- package/rust/core/lexer/driver.rs +59 -61
- package/rust/core/lexer/handler/arrow.rs +82 -82
- package/rust/core/lexer/handler/at.rs +21 -21
- package/rust/core/lexer/handler/brace.rs +41 -41
- package/rust/core/lexer/handler/colon.rs +21 -21
- package/rust/core/lexer/handler/comment.rs +30 -30
- package/rust/core/lexer/handler/dot.rs +21 -21
- package/rust/core/lexer/handler/driver.rs +337 -337
- package/rust/core/lexer/handler/identifier.rs +47 -47
- package/rust/core/lexer/handler/indent.rs +66 -66
- package/rust/core/lexer/handler/mod.rs +15 -15
- package/rust/core/lexer/handler/newline.rs +23 -23
- package/rust/core/lexer/handler/number.rs +31 -31
- package/rust/core/lexer/handler/operator.rs +46 -46
- package/rust/core/lexer/handler/parenthesis.rs +41 -41
- package/rust/core/lexer/handler/slash.rs +21 -21
- package/rust/core/lexer/handler/string.rs +63 -63
- package/rust/core/lexer/mod.rs +3 -3
- package/rust/core/mod.rs +0 -1
- package/rust/core/parser/driver/block.rs +111 -0
- package/rust/core/parser/driver/cursor.rs +82 -0
- package/rust/core/parser/driver/driver_impl.rs +139 -0
- package/rust/core/parser/driver/mod.rs +6 -0
- package/rust/core/parser/driver/parse_array.rs +120 -0
- package/rust/core/parser/driver/parse_map.rs +223 -0
- package/rust/core/parser/driver/parser.rs +160 -0
- package/rust/core/parser/handler/arrow_call.rs +28 -4
- package/rust/core/parser/handler/at.rs +279 -279
- package/rust/core/parser/handler/bank.rs +104 -104
- package/rust/core/parser/handler/condition.rs +83 -83
- package/rust/core/parser/handler/dot.rs +148 -148
- package/rust/core/parser/handler/identifier/automate.rs +254 -254
- package/rust/core/parser/handler/identifier/call.rs +91 -91
- package/rust/core/parser/handler/identifier/emit.rs +70 -70
- package/rust/core/parser/handler/identifier/function.rs +113 -113
- package/rust/core/parser/handler/identifier/group.rs +89 -89
- package/rust/core/parser/handler/identifier/let_.rs +173 -173
- package/rust/core/parser/handler/identifier/mod.rs +55 -55
- package/rust/core/parser/handler/identifier/on.rs +107 -107
- package/rust/core/parser/handler/identifier/print.rs +49 -49
- package/rust/core/parser/handler/identifier/sleep.rs +96 -43
- package/rust/core/parser/handler/identifier/spawn.rs +91 -91
- package/rust/core/parser/handler/identifier/synth.rs +135 -135
- package/rust/core/parser/handler/loop_.rs +194 -194
- package/rust/core/parser/handler/mod.rs +9 -9
- package/rust/core/parser/handler/pattern.rs +1 -1
- package/rust/core/parser/handler/tempo.rs +105 -57
- package/rust/core/parser/statement.rs +10 -11
- package/rust/core/plugin/loader.rs +1 -1
- package/rust/core/plugin/mod.rs +2 -2
- package/rust/core/plugin/runner/mod.rs +11 -0
- package/rust/core/plugin/{runner.rs → runner/non_wasm.rs} +297 -347
- package/rust/core/plugin/runner/wasm32.rs +43 -0
- package/rust/core/preprocessor/loader/inject.rs +278 -0
- package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
- package/rust/core/preprocessor/loader/mod.rs +235 -0
- package/rust/core/preprocessor/module.rs +2 -7
- package/rust/core/preprocessor/{processor.rs → processor/handlers.rs} +6 -13
- package/rust/core/preprocessor/processor/mod.rs +1 -0
- package/rust/core/preprocessor/resolver/bank.rs +49 -49
- package/rust/core/preprocessor/resolver/call.rs +124 -124
- package/rust/core/preprocessor/resolver/condition.rs +95 -95
- package/rust/core/preprocessor/resolver/driver.rs +324 -324
- package/rust/core/preprocessor/resolver/function.rs +2 -2
- package/rust/core/preprocessor/resolver/group.rs +46 -18
- package/rust/core/preprocessor/resolver/let_.rs +32 -32
- package/rust/core/preprocessor/resolver/loop_.rs +318 -318
- package/rust/core/preprocessor/resolver/mod.rs +16 -16
- package/rust/core/preprocessor/resolver/pattern.rs +83 -83
- package/rust/core/preprocessor/resolver/spawn.rs +99 -99
- package/rust/core/preprocessor/resolver/synth.rs +54 -54
- package/rust/core/preprocessor/resolver/tempo.rs +48 -48
- package/rust/core/preprocessor/resolver/trigger.rs +116 -116
- package/rust/core/preprocessor/resolver/value.rs +176 -176
- package/rust/core/store/global.rs +2 -6
- package/rust/core/store/mod.rs +1 -5
- package/rust/lib.rs +18 -3
- package/rust/main.rs +27 -3
- package/rust/types/Cargo.toml +1 -1
- package/rust/types/src/addons.rs +55 -55
- package/rust/types/src/config.rs +84 -74
- package/rust/types/src/lib.rs +15 -12
- package/rust/types/src/plugin.rs +20 -0
- package/rust/types/src/store.rs +139 -0
- package/rust/types/src/telemetry.rs +85 -85
- package/rust/utils/Cargo.toml +2 -2
- package/rust/utils/src/file.rs +94 -94
- package/rust/utils/src/first_usage.rs +97 -97
- package/rust/utils/src/lib.rs +9 -9
- package/rust/utils/src/logger.rs +200 -200
- package/rust/utils/src/path.rs +129 -88
- package/rust/utils/src/signature.rs +41 -41
- package/rust/utils/src/spinner.rs +20 -20
- package/rust/utils/src/version.rs +27 -27
- package/rust/utils/src/watcher.rs +46 -46
- package/rust/web/api.rs +5 -5
- package/rust/web/cdn.rs +34 -34
- package/rust/web/mod.rs +3 -3
- package/tests/integration.rs +21 -21
- package/typescript/core/functions/index.ts +11 -0
- package/typescript/pkg/devalang_core.ts +20 -4
- package/rust/core/audio/engine/sample.rs +0 -366
- package/rust/core/audio/engine/synth.rs +0 -325
- package/rust/core/audio/interpreter/arrow_call.rs +0 -311
- package/rust/core/audio/renderer.rs +0 -54
- package/rust/core/parser/driver.rs +0 -584
- package/rust/core/preprocessor/loader.rs +0 -637
- package/rust/core/store/export.rs +0 -28
- package/rust/core/store/function.rs +0 -40
- package/rust/core/store/import.rs +0 -28
- package/rust/core/store/variable.rs +0 -51
- package/rust/core/utils/mod.rs +0 -1
- package/rust/core/utils/path.rs +0 -37
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
use crate::core::parser::statement::Statement;
|
|
2
|
-
use devalang_types::Value;
|
|
3
|
-
|
|
4
|
-
pub fn interprete_sleep_statement(
|
|
5
|
-
stmt: &Statement,
|
|
6
|
-
cursor_time: f32,
|
|
7
|
-
max_end_time: f32,
|
|
8
|
-
) -> (f32, f32) {
|
|
9
|
-
let duration_secs = match &stmt.value {
|
|
10
|
-
Value::Number(ms) => *ms / 1000.0,
|
|
11
|
-
Value::String(s) if s.ends_with("ms") => s
|
|
12
|
-
.trim_end_matches("ms")
|
|
13
|
-
.parse::<f32>()
|
|
14
|
-
.map(|ms| ms / 1000.0)
|
|
15
|
-
.unwrap_or_else(|_| {
|
|
16
|
-
eprintln!("❌ Invalid sleep value (ms): {}", s);
|
|
17
|
-
0.0
|
|
18
|
-
}),
|
|
19
|
-
other => {
|
|
20
|
-
eprintln!("❌ Invalid sleep value: {:?}", other);
|
|
21
|
-
0.0
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
let new_cursor = cursor_time + duration_secs;
|
|
26
|
-
let new_max = max_end_time.max(new_cursor);
|
|
27
|
-
(new_cursor, new_max)
|
|
28
|
-
}
|
|
1
|
+
use crate::core::parser::statement::Statement;
|
|
2
|
+
use devalang_types::Value;
|
|
3
|
+
|
|
4
|
+
pub fn interprete_sleep_statement(
|
|
5
|
+
stmt: &Statement,
|
|
6
|
+
cursor_time: f32,
|
|
7
|
+
max_end_time: f32,
|
|
8
|
+
) -> (f32, f32) {
|
|
9
|
+
let duration_secs = match &stmt.value {
|
|
10
|
+
Value::Number(ms) => *ms / 1000.0,
|
|
11
|
+
Value::String(s) if s.ends_with("ms") => s
|
|
12
|
+
.trim_end_matches("ms")
|
|
13
|
+
.parse::<f32>()
|
|
14
|
+
.map(|ms| ms / 1000.0)
|
|
15
|
+
.unwrap_or_else(|_| {
|
|
16
|
+
eprintln!("❌ Invalid sleep value (ms): {}", s);
|
|
17
|
+
0.0
|
|
18
|
+
}),
|
|
19
|
+
other => {
|
|
20
|
+
eprintln!("❌ Invalid sleep value: {:?}", other);
|
|
21
|
+
0.0
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
let new_cursor = cursor_time + duration_secs;
|
|
26
|
+
let new_max = max_end_time.max(new_cursor);
|
|
27
|
+
(new_cursor, new_max)
|
|
28
|
+
}
|
|
@@ -3,8 +3,9 @@ use devalang_types::{Duration, Value};
|
|
|
3
3
|
use crate::core::{
|
|
4
4
|
audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
|
|
5
5
|
parser::statement::{Statement, StatementKind},
|
|
6
|
-
store::
|
|
6
|
+
store::global::GlobalStore,
|
|
7
7
|
};
|
|
8
|
+
use devalang_types::store::{FunctionTable, VariableTable};
|
|
8
9
|
|
|
9
10
|
pub fn interprete_spawn_statement(
|
|
10
11
|
stmt: &Statement,
|
|
@@ -79,7 +80,7 @@ pub fn interprete_spawn_statement(
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
let final_variable_table = if let Some(parent) = &variable_table.parent {
|
|
82
|
-
|
|
83
|
+
devalang_types::VariableTable {
|
|
83
84
|
variables: parent.variables.clone(),
|
|
84
85
|
parent: None,
|
|
85
86
|
}
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
use crate::core::parser::statement::{Statement, StatementKind};
|
|
2
|
-
use devalang_types::Value;
|
|
3
|
-
use devalang_utils::logger::{LogLevel, Logger};
|
|
4
|
-
|
|
5
|
-
pub fn interprete_tempo_statement(stmt: &Statement) -> Option<(f32, f32)> {
|
|
6
|
-
if let StatementKind::Tempo = &stmt.kind {
|
|
7
|
-
match &stmt.value {
|
|
8
|
-
Value::Number(bpm) => {
|
|
9
|
-
let bpm = { *bpm };
|
|
10
|
-
let duration = 60.0 / bpm;
|
|
11
|
-
|
|
12
|
-
return Some((bpm, duration));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
Value::String(bpm_str) => {
|
|
16
|
-
if let Ok(bpm) = bpm_str.parse::<f32>() {
|
|
17
|
-
let duration = 60.0 / bpm;
|
|
18
|
-
return Some((bpm, duration));
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
Value::Identifier(bpm_ident) => {
|
|
23
|
-
if let Ok(bpm) = bpm_ident.parse::<f32>() {
|
|
24
|
-
let duration = 60.0 / bpm;
|
|
25
|
-
return Some((bpm, duration));
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
_ => {
|
|
30
|
-
let logger = Logger::new();
|
|
31
|
-
logger.log_message(
|
|
32
|
-
LogLevel::Warning,
|
|
33
|
-
format!("Invalid tempo value: {:?}", stmt.value).as_str(),
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
None
|
|
40
|
-
}
|
|
1
|
+
use crate::core::parser::statement::{Statement, StatementKind};
|
|
2
|
+
use devalang_types::Value;
|
|
3
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
4
|
+
|
|
5
|
+
pub fn interprete_tempo_statement(stmt: &Statement) -> Option<(f32, f32)> {
|
|
6
|
+
if let StatementKind::Tempo = &stmt.kind {
|
|
7
|
+
match &stmt.value {
|
|
8
|
+
Value::Number(bpm) => {
|
|
9
|
+
let bpm = { *bpm };
|
|
10
|
+
let duration = 60.0 / bpm;
|
|
11
|
+
|
|
12
|
+
return Some((bpm, duration));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Value::String(bpm_str) => {
|
|
16
|
+
if let Ok(bpm) = bpm_str.parse::<f32>() {
|
|
17
|
+
let duration = 60.0 / bpm;
|
|
18
|
+
return Some((bpm, duration));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Value::Identifier(bpm_ident) => {
|
|
23
|
+
if let Ok(bpm) = bpm_ident.parse::<f32>() {
|
|
24
|
+
let duration = 60.0 / bpm;
|
|
25
|
+
return Some((bpm, duration));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_ => {
|
|
30
|
+
let logger = Logger::new();
|
|
31
|
+
logger.log_message(
|
|
32
|
+
LogLevel::Warning,
|
|
33
|
+
format!("Invalid tempo value: {:?}", stmt.value).as_str(),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
None
|
|
40
|
+
}
|
|
@@ -3,8 +3,8 @@ use std::collections::HashMap;
|
|
|
3
3
|
use crate::core::{
|
|
4
4
|
audio::{engine::AudioEngine, loader::trigger::load_trigger},
|
|
5
5
|
parser::statement::{Statement, StatementKind},
|
|
6
|
-
store::variable::VariableTable,
|
|
7
6
|
};
|
|
7
|
+
use devalang_types::store::VariableTable;
|
|
8
8
|
use devalang_types::{Duration, Value};
|
|
9
9
|
use devalang_utils::logger::Logger;
|
|
10
10
|
|
package/rust/core/audio/mod.rs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
pub mod engine;
|
|
2
|
-
pub mod evaluator;
|
|
3
|
-
pub mod interpreter;
|
|
4
|
-
pub mod loader;
|
|
5
|
-
pub mod player;
|
|
6
|
-
pub mod
|
|
7
|
-
pub mod special;
|
|
1
|
+
pub mod engine;
|
|
2
|
+
pub mod evaluator;
|
|
3
|
+
pub mod interpreter;
|
|
4
|
+
pub mod loader;
|
|
5
|
+
pub mod player;
|
|
6
|
+
pub mod special;
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink, Source};
|
|
2
|
-
use std::{fs::File, io::BufReader};
|
|
3
|
-
|
|
4
|
-
pub struct AudioPlayer {
|
|
5
|
-
_stream: OutputStream,
|
|
6
|
-
handle: OutputStreamHandle,
|
|
7
|
-
sink: Sink,
|
|
8
|
-
last_path: Option<String>,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
impl Default for AudioPlayer {
|
|
12
|
-
fn default() -> Self {
|
|
13
|
-
Self::new()
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
impl AudioPlayer {
|
|
18
|
-
pub fn new() -> Self {
|
|
19
|
-
let (stream, handle) = OutputStream::try_default().unwrap();
|
|
20
|
-
let sink = Sink::try_new(&handle).unwrap();
|
|
21
|
-
|
|
22
|
-
Self {
|
|
23
|
-
_stream: stream,
|
|
24
|
-
handle,
|
|
25
|
-
sink,
|
|
26
|
-
last_path: None,
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
fn load_source(&self, path: &str) -> Option<impl Source<Item = f32> + Send + 'static> {
|
|
31
|
-
if let Ok(file) = File::open(path) {
|
|
32
|
-
let reader = BufReader::new(file);
|
|
33
|
-
match Decoder::new(reader) {
|
|
34
|
-
Ok(decoder) => Some(decoder.convert_samples()),
|
|
35
|
-
Err(e) => {
|
|
36
|
-
eprintln!("❌ Failed to decode audio file '{}': {}", path, e);
|
|
37
|
-
None
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
eprintln!("❌ Could not open audio file: {}", path);
|
|
42
|
-
None
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
pub fn play_file_once(&mut self, path: &str) {
|
|
47
|
-
self.sink.stop();
|
|
48
|
-
self.sink = Sink::try_new(&self.handle).unwrap();
|
|
49
|
-
self.sink.set_volume(1.0);
|
|
50
|
-
|
|
51
|
-
if let Some(source) = self.load_source(path) {
|
|
52
|
-
self.sink.append(source);
|
|
53
|
-
self.last_path = Some(path.to_string());
|
|
54
|
-
} else {
|
|
55
|
-
eprintln!("⚠️ Skipping playback: failed to load '{}'", path);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
pub fn replay_last(&mut self) {
|
|
60
|
-
if let Some(path) = self.last_path.clone() {
|
|
61
|
-
self.play_file_once(&path);
|
|
62
|
-
} else {
|
|
63
|
-
eprintln!("⚠️ No previous audio to replay.");
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
pub fn wait_until_end(&self) {
|
|
68
|
-
self.sink.sleep_until_end();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
use rodio::{Decoder, OutputStream, OutputStreamHandle, Sink, Source};
|
|
2
|
+
use std::{fs::File, io::BufReader};
|
|
3
|
+
|
|
4
|
+
pub struct AudioPlayer {
|
|
5
|
+
_stream: OutputStream,
|
|
6
|
+
handle: OutputStreamHandle,
|
|
7
|
+
sink: Sink,
|
|
8
|
+
last_path: Option<String>,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
impl Default for AudioPlayer {
|
|
12
|
+
fn default() -> Self {
|
|
13
|
+
Self::new()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl AudioPlayer {
|
|
18
|
+
pub fn new() -> Self {
|
|
19
|
+
let (stream, handle) = OutputStream::try_default().unwrap();
|
|
20
|
+
let sink = Sink::try_new(&handle).unwrap();
|
|
21
|
+
|
|
22
|
+
Self {
|
|
23
|
+
_stream: stream,
|
|
24
|
+
handle,
|
|
25
|
+
sink,
|
|
26
|
+
last_path: None,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn load_source(&self, path: &str) -> Option<impl Source<Item = f32> + Send + 'static> {
|
|
31
|
+
if let Ok(file) = File::open(path) {
|
|
32
|
+
let reader = BufReader::new(file);
|
|
33
|
+
match Decoder::new(reader) {
|
|
34
|
+
Ok(decoder) => Some(decoder.convert_samples()),
|
|
35
|
+
Err(e) => {
|
|
36
|
+
eprintln!("❌ Failed to decode audio file '{}': {}", path, e);
|
|
37
|
+
None
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
eprintln!("❌ Could not open audio file: {}", path);
|
|
42
|
+
None
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub fn play_file_once(&mut self, path: &str) {
|
|
47
|
+
self.sink.stop();
|
|
48
|
+
self.sink = Sink::try_new(&self.handle).unwrap();
|
|
49
|
+
self.sink.set_volume(1.0);
|
|
50
|
+
|
|
51
|
+
if let Some(source) = self.load_source(path) {
|
|
52
|
+
self.sink.append(source);
|
|
53
|
+
self.last_path = Some(path.to_string());
|
|
54
|
+
} else {
|
|
55
|
+
eprintln!("⚠️ Skipping playback: failed to load '{}'", path);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn replay_last(&mut self) {
|
|
60
|
+
if let Some(path) = self.last_path.clone() {
|
|
61
|
+
self.play_file_once(&path);
|
|
62
|
+
} else {
|
|
63
|
+
eprintln!("⚠️ No previous audio to replay.");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn wait_until_end(&self) {
|
|
68
|
+
self.sink.sleep_until_end();
|
|
69
|
+
}
|
|
70
|
+
}
|