makepad_audio_widgets/
display_audio.rs

1
2use {
3    crate::{
4        makepad_draw::*,
5        makepad_widgets::*,
6    }
7};
8
9live_design!{
10    use link::shaders::*;
11    
12    DrawWave = {{DrawWave}} {
13        texture wave_texture: texture2d
14        
15        fn vu_fill(self)->vec4{
16            return vec4(Pal::iq1((1.0-0.5*self.pos.y)),1.0)
17        }
18        
19        fn pixel(self) -> vec4 {
20            let wave = sample2d(self.wave_texture, vec2(self.pos.x, 0.0));
21            let right = (wave.y + wave.z / 256.0 - 0.5) * 3.0;
22            let left = (wave.w + wave.x / 256.0 - 0.5) * 3.0;
23            //return mix(#f00,#0f0, left+0.5);
24            let sdf = Sdf2d::viewport(self.pos * self.rect_size);
25            let step = 0.0;
26            // lets draw a gradient vu meter
27            let vu_ht = self.rect_size.y*(1.0-self.vu_left * self.gain);
28            sdf.rect(0.,vu_ht,self.rect_size.x, self.rect_size.y-vu_ht);
29            sdf.fill(self.vu_fill())
30            for i in 0..4 {
31                let wave = sample2d(self.wave_texture, vec2(self.pos.x, step));
32                let right = (wave.y + wave.z / 256.0 - 0.5) * 3.0;
33                let left = (wave.w + wave.x / 256.0 - 0.5) * 3.0;
34                let audio = (left + right) - 0.01;
35                let half = self.rect_size.y * 0.5;
36                let scale = half * 2.0;
37                sdf.hline(half + audio * scale, abs(audio) * scale);
38                let color = Pal::iq1(0.35 + 2.0 * step) * 0.8;
39                sdf.fill_premul(vec4(color, 0.0))
40                step += 1.0 / 16.0;
41            }
42            return sdf.result
43        }
44    }
45    
46    pub DisplayAudio = {{DisplayAudio}} {
47        width: Fill,
48        height: Fill
49    }
50}
51
52// TODO support a shared 'inputs' struct on drawshaders
53#[derive(Live, LiveHook, LiveRegister)]#[repr(C)]
54struct DrawWave {
55    #[deref] draw_super: DrawQuad,
56    #[live] gain: f32,
57    #[live] vu_left: f32,
58    #[live] vu_right: f32
59}
60
61#[derive(Live, Widget)]
62pub struct DisplayAudio {
63    #[walk] walk: Walk,
64    #[redraw] #[live] draw_wave: DrawWave,
65    #[rust(Texture::new(cx))] wave_texture: Texture,
66    #[rust] data_offset: [usize; 32],
67    #[rust([0; 32])] active: [usize; 32],
68    #[rust([(0.0,0.0);32])] vu:[(f32,f32); 32],
69}
70
71
72impl Widget for DisplayAudio {
73    fn handle_event(&mut self, _cx: &mut Cx, _event: &Event, _scope: &mut Scope){
74    }
75    
76    fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep { 
77        self.draw_wave.draw_vars.set_texture(0, &self.wave_texture);
78        self.draw_wave.vu_left = self.vu[0].0.powf(1.0/3.0)*1.2;
79        self.draw_wave.vu_right = self.vu[0].1.powf(1.0/3.0)*1.2;
80        self.vu[0].0 *= 0.95;
81        self.vu[0].1 *= 0.95;
82        self.draw_wave.draw_walk(cx, walk);
83        DrawStep::done()
84    }
85}
86
87#[derive(Clone, DefaultNone)]
88pub enum DisplayAudioAction {
89    None
90}
91const WAVE_SIZE_X: usize = 1024;
92const WAVE_SIZE_Y: usize = 16;
93
94impl LiveHook for DisplayAudio {
95
96    fn after_new_from_doc(&mut self, cx: &mut Cx) {
97        self.wave_texture = Texture::new_with_format(cx, TextureFormat::VecBGRAu8_32 {
98            data: {
99                let mut data = Vec::new();
100                data.resize(WAVE_SIZE_X * WAVE_SIZE_Y, 0);
101                for j in 0..WAVE_SIZE_Y {
102                    for i in 0..WAVE_SIZE_X {
103                        let left_u16 = 32767;
104                        let right_u16 = 32767;
105                        data[j * WAVE_SIZE_X + i] = left_u16 << 16 | right_u16;
106                    }
107                }
108                Some(data)
109            },
110            width: WAVE_SIZE_X,
111            height: WAVE_SIZE_Y,
112            updated: TextureUpdated::Full,
113        });
114    }
115}
116
117impl DisplayAudio {
118    pub fn process_buffer(&mut self, cx: &mut Cx, chan: Option<usize>, voice: usize, audio: &AudioBuffer, gain:f32) {
119        let mut wave_buf = self.wave_texture.take_vec_u32(cx);
120        let frames = audio.frame_count();
121        let wave_off = self.data_offset[voice];
122        let voice_offset = voice * WAVE_SIZE_X;
123        let mut is_active = false;
124        for i in 0..frames {
125            let left = audio.channel(chan.unwrap_or(0))[i];
126            let right = audio.channel(chan.unwrap_or(audio.channel_count().min(1)))[i];
127            if left.abs() > self.vu[voice].0 {self.vu[voice].0 = left.abs()};
128            if right.abs() > self.vu[voice].1 {self.vu[voice].1 = right.abs()};
129            let left_u16 = ((left + 0.5) * 65536.0).max(0.0).min(65535.0) as u32;
130            let right_u16 = ((right + 0.5) * 65536.0).max(0.0).min(65535.0) as u32;
131            if left.abs()>0.0000000000001 || right.abs()>0.0000000000001 {
132                is_active = true;
133            }
134            let off = voice_offset + ((wave_off + i) % (WAVE_SIZE_X));
135            wave_buf[off] = left_u16 << 16 | right_u16;
136        }
137        self.draw_wave.gain = gain;
138        self.wave_texture.put_back_vec_u32(cx, wave_buf, None);
139        self.data_offset[voice] = (self.data_offset[voice] + frames) % (WAVE_SIZE_X);
140        if is_active {
141            self.active[voice] = 6
142        }
143        if self.active[voice]>0 {
144            self.draw_wave.redraw(cx);
145            self.active[voice] -= 1;
146        }
147    }
148}
149
150impl DisplayAudioRef {
151    pub fn process_buffer(&self, cx: &mut Cx, chan: Option<usize>, voice: usize, buffer: &AudioBuffer, gain:f32) {
152        if let Some(mut inner) = self.borrow_mut() {
153            inner.process_buffer(cx, chan, voice, buffer, gain);
154        }
155    }
156    
157    pub fn voice_off(&self, _cx: &mut Cx, _voice: usize,) {
158    }
159}
160
161impl DisplayAudioSet {
162    pub fn process_buffer(&self, cx: &mut Cx, chan: Option<usize>, voice: usize, buffer: &AudioBuffer, gain:f32) {
163        for item in self.iter(){
164            item.process_buffer(cx, chan, voice, buffer, gain);
165        }
166    }
167    
168    pub fn voice_off(&self, cx: &mut Cx, voice: usize,) {
169        for item in self.iter(){
170            item.voice_off(cx, voice);
171        }
172    }
173}