Hi, I was looking at a tutorial for a wavetable synthesizer and am trying to go a little deeper, no I am trying to use a function to change the value of a member variable in a struct but I am coming to the error:
borrow of moved value: oscillator
value borrowed here after moverustcClick for full compiler diagnostic
main.rs(238, 26): oscillator
moved due to this method call
main.rs(230, 9): move occurs because oscillator
has type WavetableOscillator
, which does not implement the Copy
trait
mod.rs(292, 27): this function takes ownership of the receiver self
, which moves oscillator
I pasted my code below the error is at line 261 where I make the function call "oscillator.set_frequency(freq)". I have been trying to wrap my mind around this but I dont know where to go from here. Can someone help?
use rodio::Sink;
use rodio::source::SineWave;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::{Keycode, KeyboardState};
use sdl2::video::WindowContext;
use sdl2::rect::Rect;
use sdl2::render::{WindowCanvas, TextureCreator};
use sdl2::ttf;
use sdl2::keyboard::Scancode;
use rodio::{OutputStream, source::Source};
use std::ops::Div;
use std::time::Duration;
use std::path::Path;
use enum_iterator::{all, cardinality, first, last, next, previous, reverse_all, Sequence};
use enum_map::{enum_map, Enum, EnumMap};
//////////////////////////////////////////
const SampleRate: usize = 44100;
const DesiredFreq: usize = 30;
const waveformSampleCount: usize = SampleRate/ DesiredFreq;
//for now just populated with sin vals
/* fn populate_tables(wavetable: &mut wavetable) -> Result<(), String> {
for i in 0..waveformSampleCount {
wavetable.samples.push((i as f32 * 2.0 * std::f32::consts::PI as f32/ waveformSampleCount as f32).sin());
}
Ok(())
}
pub struct Wavetable_settings {
pub waveform_length: usize,
pub dimension_count: usize,
pub waveforms_per_dim: usize,
pub base_freq: f32,
}
pub struct wavetable{
pub settings: Wavetable_settings,
pub samples: Vec<f32>,
}
pub struct Wavetable_handle {
pub table: &'static mut wavetable,
pub sample_ix: f32,
pub mixes: Vec<f32>,
pub mixes_for_sample : Vec<f32>,
pub sample_buffer: Vec<f32>,
pub frequency_buffer: Vec<f32>,
} */
//implement semitone calculation
//enum variants cant be used as params
//midi note freq is 0 - 127 or a u8 value
// fn calc_semitonefreq(key: i32) -> f32{
// }
#[derive(Clone)]
struct WavetableOscillator {
sample_rate: u32,
wave_table: Vec<f32>,
index: f32,
index_increment: f32,
}
impl WavetableOscillator {
fn new(sample_rate: u32, wave_table: Vec<f32>) -> WavetableOscillator {
return WavetableOscillator {
sample_rate: sample_rate,
wave_table: wave_table,
index: 0.0,
index_increment: 0.0,
};
}
fn set_frequency(&mut self, frequency: f32) {
self.index_increment = frequency * self.wave_table.len() as f32 / self.sample_rate as f32;
}
fn get_sample(&mut self) -> f32 {
let sample = self.lerp();
self.index += self.index_increment;
self.index %= self.wave_table.len() as f32;
return sample;
}
fn lerp(&self) -> f32 {
let truncated_index = self.index as usize;
let next_index = (truncated_index + 1) % self.wave_table.len();
let next_index_weight = self.index - truncated_index as f32;
let truncated_index_weight = 1.0 - next_index_weight;
return truncated_index_weight * self.wave_table[truncated_index]
+ next_index_weight * self.wave_table[next_index];
}
}
impl Source for WavetableOscillator {
fn channels(&self) -> u16 {
return 1;
}
fn sample_rate(&self) -> u32 {
return self.sample_rate;
}
fn current_frame_len(&self) -> Option<usize> {
return None;
}
fn total_duration(&self) -> Option<Duration> {
return None;
}
}
impl Iterator for WavetableOscillator {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
return Some(self.get_sample());
}
}
// impl Clone for WavetableOscillator{
// fn clone(&self) -> Self {
// let clone_table =self.wave_table.clone();
// return WavetableOscillator { sample_rate: self.sample_rate, wave_table: clone_table, index: self.index, index_increment: self.index_increment }
// }
// fn clone_from(&mut self, original: &Self) {}
// }
fn render(canvas: &mut WindowCanvas, color: Color, font: &sdl2::ttf::Font, texture_creator: &TextureCreator<WindowContext>, txt_inj: &mut String) -> Result<(), String> {
canvas.set_draw_color(color);
canvas.clear();
//text
if (txt_inj.len() >0){
let surface = font.render(&txt_inj)
.blended(Color::RGBA(255 -color.r, 255 -color.g, 255 - color.b, 255 -color.a))
.map_err(|e| e.to_string())?;
let texture = texture_creator
.create_texture_from_surface(&surface)
.map_err(|e| e.to_string())?;
let target = Rect::new(10 as i32, 0 as i32, 200 as u32, 100 as u32);
canvas.copy(&texture, None, Some(target))?;
}
if txt_inj.len() > 30 {
txt_inj.clear();
}
canvas.present();
Ok(())
}
fn main() -> Result<(), String> {
let SEMITONE_RATIO: f32 = 2.0_f32.powf(1.0/12.0); // approx 1.0594631
let NOTE_C5: f32 = 220.0 * SEMITONE_RATIO.powi(3);
let NOTE_C0: f32 = NOTE_C5 * 0.5_f32.powi(5);
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
//prep fonts
let ttf_context = sdl2::ttf::init().map_err(|e| e.to_string())?;
let font_path: &Path = Path::new(&"fonts/OpenSans-BoldItalic.ttf");
let mut font = ttf_context.load_font(font_path, 128)?;
font.set_style(sdl2::ttf::FontStyle::BOLD);
let window = video_subsystem.window("game window", 600, 800)
.position_centered()
.build()
.expect("could not create video subsystem");
let mut canvas = window.into_canvas().build()
.expect("could not create canvas");
let texture_creator = canvas.texture_creator();
let mut event_pump = sdl_context.event_pump()?;
let mut text: String = "".to_string();
let wave_table_size = 64;
let mut wave_table: Vec<f32> = Vec::with_capacity(wave_table_size);
for n in 0..wave_table_size {
wave_table.push((2.0 * std::f32::consts::PI * n as f32 / wave_table_size as f32).sin());
}
let mut oscillator = WavetableOscillator::new(44100, wave_table);
oscillator.set_frequency(440.0);
text = "".to_string();
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let src = oscillator.convert_samples::<f32>();
let sink = Sink::try_new(&stream_handle).unwrap();
let mut i =0;
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} => {
break 'running;
},
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running;
},
//left
Event::KeyDown { timestamp , window_id , keycode, scancode, keymod, repeat } =>{
let freq = NOTE_C0 * SEMITONE_RATIO.powi(76);
let comp = String::from("D");
if keycode.unwrap().to_string().eq(&comp) {
println!("new freq{}, ratio {}", freq, SEMITONE_RATIO);
oscillator.set_frequency(freq);
}
//println!("key: {}, freq: {}",keycode.unwrap().to_string(), oscillator.get_sample());
text.push_str(&keycode.unwrap().to_string());
sink.append(src.clone());
sink.play();
},
Event::KeyUp { timestamp, window_id, keycode, scancode, keymod, repeat } => {
sink.pause();
},
_ => {}
}
}
i = (i+1) %255;
render(&mut canvas, Color::RGB(i,64, 255-i),&font,&texture_creator, &mut text)?;
std::thread::sleep(Duration::new(0,1_000_000_000u32 / 60));
}
Ok(())
}