@@ -119,9 +119,12 @@ impl FreeplayRecorder {
119119 matches ! ( self . state, RecorderState :: Recording ( _) )
120120 }
121121
122- fn has_events ( & self ) -> bool {
122+ fn has_note_events ( & self ) -> bool {
123123 match & self . state {
124- RecorderState :: Recorded ( recorded_take) => !recorded_take. events . is_empty ( ) ,
124+ // Preview/export requires at least one played note, not just release/control data.
125+ RecorderState :: Recorded ( recorded_take) => recorded_take. events . iter ( ) . any ( |event| {
126+ matches ! ( event. message, MidiMessage :: NoteOn { .. } )
127+ } ) ,
125128 RecorderState :: Idle | RecorderState :: Recording ( _) => false ,
126129 }
127130 }
@@ -188,8 +191,8 @@ impl FreeplayRecorder {
188191 }
189192
190193 fn save_to_path ( & self , path : & Path ) -> Result < ( ) , String > {
191- if !self . has_events ( ) {
192- return Err ( "Nothing recorded yet" . to_string ( ) ) ;
194+ if !self . has_note_events ( ) {
195+ return Err ( "No note events recorded yet" . to_string ( ) ) ;
193196 }
194197
195198 let smf = self . to_smf ( ) ;
@@ -200,8 +203,8 @@ impl FreeplayRecorder {
200203 }
201204
202205 fn to_song ( & self ) -> Result < Song , String > {
203- if !self . has_events ( ) {
204- return Err ( "Nothing recorded yet" . to_string ( ) ) ;
206+ if !self . has_note_events ( ) {
207+ return Err ( "No note events recorded yet" . to_string ( ) ) ;
205208 }
206209
207210 let midi = midi_file:: MidiFile :: from_smf ( "freeplay-recording.mid" , self . to_smf ( ) ) ?;
@@ -293,15 +296,64 @@ mod freeplay_recorder_tests {
293296 ) ;
294297 recorder. stop ( ) ;
295298
296- assert ! ( recorder. has_events ( ) ) ;
299+ assert ! ( recorder. has_note_events ( ) ) ;
297300 assert_eq ! ( recorder. event_count( ) , 2 ) ;
298301
299302 recorder. start ( ) ;
300303
301304 assert ! ( recorder. is_recording( ) ) ;
302- assert ! ( !recorder. has_events ( ) ) ;
305+ assert ! ( !recorder. has_note_events ( ) ) ;
303306 assert_eq ! ( recorder. event_count( ) , 0 ) ;
304307 }
308+
309+ #[ test]
310+ fn pedal_only_recording_is_rejected_for_preview_song ( ) {
311+ let mut recorder = FreeplayRecorder :: default ( ) ;
312+
313+ recorder. start ( ) ;
314+ recorder. push_event (
315+ 0 ,
316+ MidiMessage :: Controller {
317+ controller : 64 . into ( ) ,
318+ value : 127 . into ( ) ,
319+ } ,
320+ ) ;
321+ recorder. push_event (
322+ 0 ,
323+ MidiMessage :: Controller {
324+ controller : 64 . into ( ) ,
325+ value : 0 . into ( ) ,
326+ } ,
327+ ) ;
328+ recorder. stop ( ) ;
329+
330+ assert ! ( !recorder. has_note_events( ) ) ;
331+ let error = recorder
332+ . to_song ( )
333+ . expect_err ( "pedal-only recordings should not create preview songs" ) ;
334+ assert_eq ! ( error, "No note events recorded yet" ) ;
335+ }
336+
337+ #[ test]
338+ fn note_off_only_recording_is_rejected_for_preview_song ( ) {
339+ let mut recorder = FreeplayRecorder :: default ( ) ;
340+
341+ recorder. start ( ) ;
342+ recorder. push_event (
343+ 0 ,
344+ MidiMessage :: NoteOff {
345+ key : 60 . into ( ) ,
346+ vel : 0 . into ( ) ,
347+ } ,
348+ ) ;
349+ recorder. stop ( ) ;
350+
351+ assert ! ( !recorder. has_note_events( ) ) ;
352+ let error = recorder
353+ . to_song ( )
354+ . expect_err ( "note-off-only recordings should not create preview songs" ) ;
355+ assert_eq ! ( error, "No note events recorded yet" ) ;
356+ }
305357}
306358
307359impl FreeplayScene {
@@ -531,7 +583,7 @@ impl FreeplayScene {
531583 return ;
532584 }
533585
534- if !self . recorder . has_events ( ) {
586+ if !self . recorder . has_note_events ( ) {
535587 self . recorder_status = "Nothing recorded yet" . to_string ( ) ;
536588 return ;
537589 }
0 commit comments