66
77use std:: f32:: consts:: PI ;
88
9- use ctru:: linear:: LinearAllocator ;
9+ use ctru:: linear:: { LinearAllocation , LinearAllocator } ;
1010use ctru:: prelude:: * ;
1111use ctru:: services:: ndsp:: {
1212 AudioFormat , AudioMix , InterpolationType , Ndsp , OutputMode ,
1313 wave:: { Status , Wave } ,
1414} ;
1515
16+ // Buffer holding type (defined separately to implement the AsRef trait)
17+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
18+ struct Buffer ( Vec < [ i16 ; 2 ] , LinearAllocator > ) ;
19+
1620// Configuration for the NDSP process and channels.
1721const SAMPLE_RATE : usize = 22050 ;
1822const SAMPLES_PER_BUF : usize = SAMPLE_RATE / 10 ; // 2205
19- const BYTES_PER_SAMPLE : usize = AudioFormat :: PCM16Stereo . size ( ) ;
20- const AUDIO_WAVE_LENGTH : usize = SAMPLES_PER_BUF * BYTES_PER_SAMPLE ;
2123
2224// Note frequencies.
2325const NOTEFREQ : [ f32 ; 7 ] = [ 220. , 440. , 880. , 1760. , 3520. , 7040. , 14080. ] ;
2426
25- fn fill_buffer ( audio_data : & mut [ u8 ] , frequency : f32 ) {
27+ fn fill_buffer ( audio_data : & mut Buffer , frequency : f32 ) {
2628 // The audio format is Stereo PCM16.
2729 // As such, a sample is made up of 2 "Mono" samples (2 * i16), one for each channel (left and right).
28- let formatted_data = bytemuck:: cast_slice_mut :: < _ , [ i16 ; 2 ] > ( audio_data) ;
2930
30- for ( i , chunk ) in formatted_data . iter_mut ( ) . enumerate ( ) {
31+ for i in 0 .. SAMPLES_PER_BUF {
3132 // This is a simple sine wave, with a frequency of `frequency` Hz, and an amplitude 30% of maximum.
3233 let sample: f32 = ( frequency * ( i as f32 / SAMPLE_RATE as f32 ) * 2. * PI ) . sin ( ) ;
3334 let amplitude = 0.3 * i16:: MAX as f32 ;
3435
3536 let result = ( sample * amplitude) as i16 ;
3637
3738 // Stereo samples are interleaved: left and right channels.
38- * chunk = [ result, result] ;
39+ if audio_data. 0 . len ( ) <= i {
40+ audio_data. 0 . push ( [ result, result] ) ;
41+ } else {
42+ audio_data. 0 [ i] = [ result, result] ;
43+ }
3944 }
4045}
4146
@@ -64,7 +69,7 @@ fn main() {
6469
6570 // We create a buffer on the LINEAR memory that will hold our audio data.
6671 // It's necessary for the buffer to live on the LINEAR memory sector since it needs to be accessed by the DSP processor.
67- let mut audio_data1: Box < [ _ ] , _ > = Box :: new_in ( [ 0u8 ; AUDIO_WAVE_LENGTH ] , LinearAllocator ) ;
72+ let mut audio_data1 = Buffer ( Vec :: with_capacity_in ( SAMPLES_PER_BUF , LinearAllocator ) ) ;
6873
6974 // Fill the buffer with the first set of data. This simply writes a sine wave into the buffer.
7075 fill_buffer ( & mut audio_data1, NOTEFREQ [ 4 ] ) ;
@@ -97,6 +102,10 @@ fn main() {
97102
98103 println ! ( "\x1b [1;1HPress up/down to change tone frequency" ) ;
99104 println ! ( "\x1b [2;1HPress left/right to change filter" ) ;
105+
106+ #[ cfg( debug_assertions) ]
107+ println ! ( "\x1b [3;1HWarning: Running in debug mode may produce gaps." ) ;
108+
100109 println ! ( "\x1b [4;1Hnote = {} Hz " , NOTEFREQ [ note] ) ;
101110 println ! (
102111 "\x1b [5;1Hfilter = {} " ,
@@ -163,7 +172,7 @@ fn main() {
163172 // If the current buffer has finished playing, we can refill it with new data and re-queue it.
164173 let status = current. status ( ) ;
165174 if let Status :: Done = status {
166- fill_buffer ( current. get_buffer_mut ( ) . unwrap ( ) , NOTEFREQ [ note] ) ;
175+ fill_buffer ( current. get_raw_buffer_mut ( ) . unwrap ( ) , NOTEFREQ [ note] ) ;
167176
168177 channel_zero. queue_wave ( current) . unwrap ( ) ;
169178
@@ -173,3 +182,17 @@ fn main() {
173182 gfx. wait_for_vblank ( ) ;
174183 }
175184}
185+
186+ impl AsRef < [ u8 ] > for Buffer {
187+ fn as_ref ( & self ) -> & [ u8 ] {
188+ bytemuck:: cast_slice ( & self . 0 )
189+ }
190+ }
191+
192+ impl AsMut < [ u8 ] > for Buffer {
193+ fn as_mut ( & mut self ) -> & mut [ u8 ] {
194+ bytemuck:: cast_slice_mut ( & mut self . 0 )
195+ }
196+ }
197+
198+ unsafe impl LinearAllocation for Buffer { }
0 commit comments