diff --git a/src/device/chain/sampler.rs b/src/device/chain/sampler.rs index 66ab3705..953ea912 100644 --- a/src/device/chain/sampler.rs +++ b/src/device/chain/sampler.rs @@ -5,13 +5,19 @@ pub struct Voice { position: usize, } impl Voice { - fn chunk (&mut self, frames: usize) -> Vec> { + fn chunk (&mut self, frames: usize) -> Option>> { let mut chunk = vec![]; - for channel in self.sample.channels.iter() { - chunk.push(channel[self.position..self.position+frames].into()); - }; - self.position = self.position + frames; - chunk + if self.position < self.sample.end { + let start = self.position.min(self.sample.end); + let end = (self.position + frames).min(self.sample.end); + for channel in self.sample.channels.iter() { + chunk.push(channel[start..end].into()); + }; + self.position = self.position + frames; + Some(chunk) + } else { + None + } } } @@ -68,14 +74,23 @@ impl Sampler { let channel_count = self.audio_outs.len(); let mut mixed = vec![vec![0.0;scope.n_frames() as usize];channel_count]; - // emit currently playing voices - for voice in self.voices.iter_mut() { - let chunk = voice.chunk(scope.n_frames() as usize); - for (i, channel) in chunk.iter().enumerate() { - let buffer = &mut mixed[i % channel_count]; - for (i, sample) in channel.iter().enumerate() { - buffer[i] += sample; + // Emit next chunk of each currently playing voice, + // removing voices that have completed playing. + let mut voices = vec![]; + std::mem::swap(&mut voices, &mut self.voices); + loop { + if voices.len() < 1 { + break + } + let mut voice = voices.swap_remove(0); + if let Some(chunk) = voice.chunk(scope.n_frames() as usize) { + for (i, channel) in chunk.iter().enumerate() { + let buffer = &mut mixed[i % channel_count]; + for (i, sample) in channel.iter().enumerate() { + buffer[i] += sample; + } } + self.voices.push(voice); } } for (i, port) in self.audio_outs.iter_mut().enumerate() {