| 764 | released: false, |
| 765 | stopped: false, |
| 766 | volume: request.options.volume.max(0.0), |
| 767 | current_program: request.options.program, |
| 768 | sine: sine_table(), |
| 769 | control_counter: 0, |
| 770 | }; |
| 771 | source.voices.push(Voice::new( |
| 772 | request.note, |
| 773 | request.options.velocity, |
| 774 | source.volume, |
| 775 | request.options.program, |
| 776 | )); |
| 777 | if !request.held { |
| 778 | source.events = Arc::from( |
| 779 | vec![MidiEvent { |
| 780 | sample: duration_samples(request.options.sustain), |
| 781 | kind: MidiEventKind::NoteOff { note: request.note }, |
| 782 | }] |
| 783 | .into_boxed_slice(), |
| 784 | ); |
| 785 | } |
| 786 | source |
| 787 | } |
| 788 | |
| 789 | pub fn file(bytes: &[u8], song: MidiSong, rx: Receiver<MidiControl>) -> Result<Self, String> { |
| 790 | let data = parse_built_in_midi_file(bytes)?; |
| 791 | Ok(Self::file_data(data, song, rx)) |
| 792 | } |
| 793 | |
| 794 | #[doc(hidden)] |
| 795 | pub fn file_data( |
| 796 | data: Arc<BuiltInMidiFileData>, |
| 797 | song: MidiSong, |
| 798 | rx: Receiver<MidiControl>, |
| 799 | ) -> Self { |
| 800 | let loop_samples = song |
| 801 | .looped |
| 802 | .then_some(data.end_sample.max(SAMPLE_RATE as u64 / 2)); |