siglus_scene_vm/runtime/forms/
pcm.rs1use anyhow::{bail, Result};
2
3use crate::runtime::{CommandContext, Value};
4
5use super::codes::pcm_op;
6
7fn store_or_push_pcm_prop(ctx: &mut CommandContext, op: i32, args: &[Value]) {
8 let form_key = if ctx.ids.form_global_pcm != 0 {
9 ctx.ids.form_global_pcm
10 } else {
11 super::codes::FORM_GLOBAL_PCM
12 };
13 let prop = op;
14 if let Some(v) = args.get(0).cloned() {
15 match v {
16 Value::Str(s) => {
17 ctx.globals
18 .str_props
19 .entry(form_key)
20 .or_default()
21 .insert(prop, s);
22 }
23 Value::Int(n) => {
24 ctx.globals
25 .int_props
26 .entry(form_key)
27 .or_default()
28 .insert(prop, n);
29 }
30 _ => {}
31 }
32 ctx.push(Value::Int(0));
33 return;
34 }
35 if let Some(s) = ctx
36 .globals
37 .str_props
38 .get(&form_key)
39 .and_then(|m| m.get(&prop))
40 .cloned()
41 {
42 ctx.push(Value::Str(s));
43 return;
44 }
45 let v = ctx
46 .globals
47 .int_props
48 .get(&form_key)
49 .and_then(|m| m.get(&prop).copied())
50 .unwrap_or(0);
51 ctx.push(Value::Int(v));
52}
53
54fn arg_str<'a>(args: &'a [Value], idx: usize) -> Option<&'a str> {
55 match args.get(idx) {
56 Some(Value::Str(s)) => Some(s.as_str()),
57 _ => None,
58 }
59}
60
61pub fn dispatch(ctx: &mut CommandContext, args: &[Value]) -> Result<bool> {
62 let Some(op) = crate::runtime::forms::prop_access::current_op_from_ctx_or_args(ctx, args)
63 else {
64 bail!("PCM form expects an element opcode");
65 };
66 let args = crate::runtime::forms::prop_access::params_without_op(ctx, args);
67
68 match op {
69 pcm_op::PLAY => {
70 let name = match arg_str(args, 0) {
71 Some(s) => s,
72 None => {
73 store_or_push_pcm_prop(ctx, op, args);
74 return Ok(true);
75 }
76 };
77 let ok = {
78 let (pcm, audio) = (&mut ctx.pcm, &mut ctx.audio);
79 pcm.play_file_name(audio, name).is_ok()
80 };
81 if !ok {
82 ctx.unknown.record_note(&format!("pcm.play.failed:{name}"));
83 }
84 Ok(true)
85 }
86 pcm_op::STOP => {
87 ctx.pcm.stop(None)?;
88 Ok(true)
89 }
90 _ => {
91 store_or_push_pcm_prop(ctx, op, args);
92 Ok(true)
93 }
94 }
95}