2021-08-27 16:18:11 +02:00
/*
2022-01-13 12:07:00 +01:00
* Copyright ( c ) 2021 , kleines Filmröllchen < filmroellchen @ serenityos . org >
2021-08-27 16:18:11 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-05-11 23:24:46 +02:00
# include <AK/FixedArray.h>
# include <AK/NoAllocationGuard.h>
2022-07-23 15:51:00 +02:00
# include <AK/NonnullRefPtr.h>
2021-09-28 17:54:48 +02:00
# include <AK/Optional.h>
2022-05-11 23:24:46 +02:00
# include <AK/StdLibExtras.h>
# include <AK/TypedTransfer.h>
2021-08-27 16:18:11 +02:00
# include <AK/Types.h>
2022-05-11 23:24:46 +02:00
# include <LibDSP/Music.h>
2021-09-28 17:54:48 +02:00
# include <LibDSP/Processor.h>
# include <LibDSP/Track.h>
2021-08-27 16:18:11 +02:00
2022-07-17 11:35:31 +02:00
namespace DSP {
2021-08-27 16:18:11 +02:00
bool Track : : add_processor ( NonnullRefPtr < Processor > new_processor )
{
m_processor_chain . append ( move ( new_processor ) ) ;
if ( ! check_processor_chain_valid ( ) ) {
2021-12-02 11:04:04 +00:00
( void ) m_processor_chain . take_last ( ) ;
2021-08-27 16:18:11 +02:00
return false ;
}
return true ;
}
bool Track : : check_processor_chain_valid_with_initial_type ( SignalType initial_type ) const
{
Processor const * previous_processor = nullptr ;
for ( auto & processor : m_processor_chain ) {
// The first processor must have the given initial signal type as input.
if ( previous_processor = = nullptr ) {
2023-03-06 14:17:01 +01:00
if ( processor - > input_type ( ) ! = initial_type )
2021-08-27 16:18:11 +02:00
return false ;
2023-03-06 14:17:01 +01:00
} else if ( previous_processor - > output_type ( ) ! = processor - > input_type ( ) )
2021-08-27 16:18:11 +02:00
return false ;
2023-03-06 14:17:01 +01:00
previous_processor = processor . ptr ( ) ;
2021-08-27 16:18:11 +02:00
}
return true ;
}
2022-07-13 12:44:19 +02:00
NonnullRefPtr < Synthesizers : : Classic > Track : : synth ( )
{
2023-03-06 14:17:01 +01:00
return static_ptr_cast < Synthesizers : : Classic > ( m_processor_chain [ 0 ] ) ;
2022-07-13 12:44:19 +02:00
}
NonnullRefPtr < Effects : : Delay > Track : : delay ( )
{
2023-03-06 14:17:01 +01:00
return static_ptr_cast < Effects : : Delay > ( m_processor_chain [ 1 ] ) ;
2022-07-13 12:44:19 +02:00
}
2021-08-27 16:18:11 +02:00
bool AudioTrack : : check_processor_chain_valid ( ) const
{
return check_processor_chain_valid_with_initial_type ( SignalType : : Sample ) ;
}
bool NoteTrack : : check_processor_chain_valid ( ) const
{
return check_processor_chain_valid_with_initial_type ( SignalType : : Note ) ;
}
2022-05-11 23:24:46 +02:00
ErrorOr < void > Track : : resize_internal_buffers_to ( size_t buffer_size )
{
2023-01-28 20:12:17 +00:00
m_secondary_sample_buffer = TRY ( FixedArray < Sample > : : create ( buffer_size ) ) ;
2022-05-11 23:24:46 +02:00
return { } ;
}
void Track : : current_signal ( FixedArray < Sample > & output_signal )
2021-08-27 16:18:11 +02:00
{
2022-05-11 23:24:46 +02:00
// This is real-time code. We must NEVER EVER EVER allocate.
NoAllocationGuard guard ;
2022-07-13 12:44:19 +02:00
VERIFY ( m_secondary_sample_buffer . type ( ) = = SignalType : : Sample ) ;
2022-05-11 23:24:46 +02:00
VERIFY ( output_signal . size ( ) = = m_secondary_sample_buffer . get < FixedArray < Sample > > ( ) . size ( ) ) ;
2021-09-28 17:54:48 +02:00
compute_current_clips_signal ( ) ;
2022-05-11 23:24:46 +02:00
Signal * source_signal = & m_current_signal ;
// This provides an audio buffer of the right size. It is not allocated here, but whenever we are informed about a buffer size change.
Signal * target_signal = & m_secondary_sample_buffer ;
2021-09-28 17:54:48 +02:00
2021-08-27 16:18:11 +02:00
for ( auto & processor : m_processor_chain ) {
2022-05-11 23:24:46 +02:00
// Depending on what the processor needs to have as output, we need to place either a pre-allocated note hash map or a pre-allocated sample buffer in the target signal.
2023-03-06 14:17:01 +01:00
if ( processor - > output_type ( ) = = SignalType : : Note )
2022-05-11 23:24:46 +02:00
target_signal = & m_secondary_note_buffer ;
else
target_signal = & m_secondary_sample_buffer ;
2023-03-06 14:17:01 +01:00
processor - > process ( * source_signal , * target_signal ) ;
2022-05-11 23:24:46 +02:00
swap ( source_signal , target_signal ) ;
2021-08-27 16:18:11 +02:00
}
2022-05-11 23:24:46 +02:00
VERIFY ( source_signal - > type ( ) = = SignalType : : Sample ) ;
VERIFY ( output_signal . size ( ) = = source_signal - > get < FixedArray < Sample > > ( ) . size ( ) ) ;
2022-07-23 15:51:00 +02:00
// The last processor is the fixed mastering processor. This can write directly to the output data. We also just trust this processor that it does the right thing :^)
m_track_mastering - > process_to_fixed_array ( * source_signal , output_signal ) ;
2021-08-27 16:18:11 +02:00
}
2021-09-28 17:54:48 +02:00
void NoteTrack : : compute_current_clips_signal ( )
2021-08-27 16:18:11 +02:00
{
2022-07-13 12:44:19 +02:00
// FIXME: Handle looping properly
u32 start_time = m_transport - > time ( ) ;
VERIFY ( m_secondary_sample_buffer . type ( ) = = SignalType : : Sample ) ;
size_t sample_count = m_secondary_sample_buffer . get < FixedArray < Sample > > ( ) . size ( ) ;
u32 end_time = start_time + static_cast < u32 > ( sample_count ) ;
// Find the currently playing clips.
// We can't handle more than 32 playing clips at a time, but that is a ridiculous number.
Array < RefPtr < NoteClip > , 32 > playing_clips ;
size_t playing_clips_index = 0 ;
2021-08-27 16:18:11 +02:00
for ( auto & clip : m_clips ) {
2022-07-13 12:44:19 +02:00
// A clip is playing if its start time or end time fall in the current time range.
// Or, if they both enclose the current time range.
2023-03-06 14:17:01 +01:00
if ( ( clip - > start ( ) < = start_time & & clip - > end ( ) > = end_time )
| | ( clip - > start ( ) > = start_time & & clip - > start ( ) < end_time )
| | ( clip - > end ( ) > start_time & & clip - > end ( ) < = end_time ) ) {
2022-07-13 12:44:19 +02:00
VERIFY ( playing_clips_index < playing_clips . size ( ) ) ;
playing_clips [ playing_clips_index + + ] = clip ;
2021-08-27 16:18:11 +02:00
}
}
2021-09-28 17:54:48 +02:00
auto & current_notes = m_current_signal . get < RollNotes > ( ) ;
2022-07-13 12:44:19 +02:00
m_current_signal . get < RollNotes > ( ) . fill ( { } ) ;
2021-09-28 17:54:48 +02:00
2022-07-13 12:44:19 +02:00
if ( playing_clips_index = = 0 )
2021-09-28 17:54:48 +02:00
return ;
2022-07-13 12:44:19 +02:00
for ( auto const & playing_clip : playing_clips ) {
if ( playing_clip . is_null ( ) )
break ;
for ( auto const & note : playing_clip - > notes ( ) ) {
if ( note . is_playing_during ( start_time , end_time ) )
current_notes [ note . pitch ] = note ;
2021-08-27 16:18:11 +02:00
}
}
2022-07-13 12:44:19 +02:00
for ( auto const & keyboard_note : m_keyboard - > notes ( ) ) {
if ( ! keyboard_note . has_value ( ) | | ! keyboard_note - > is_playing_during ( start_time , end_time ) )
continue ;
// Always overwrite roll notes with keyboard notes.
current_notes [ keyboard_note - > pitch ] = keyboard_note ;
}
2021-08-27 16:18:11 +02:00
}
2021-09-28 17:54:48 +02:00
void AudioTrack : : compute_current_clips_signal ( )
2021-08-27 16:18:11 +02:00
{
2022-05-11 23:24:46 +02:00
// This is quite involved as we need to look at multiple clips and take looping into account.
TODO ( ) ;
2021-08-27 16:18:11 +02:00
}
2023-02-06 20:46:41 +01:00
Optional < RollNote > NoteTrack : : note_at ( u32 time , u8 pitch ) const
{
for ( auto & clip : m_clips ) {
2023-03-06 14:17:01 +01:00
if ( time > = clip - > start ( ) & & time < = clip - > end ( ) )
return clip - > note_at ( time , pitch ) ;
2023-02-06 20:46:41 +01:00
}
return { } ;
}
2022-07-13 12:44:19 +02:00
void NoteTrack : : set_note ( RollNote note )
{
for ( auto & clip : m_clips ) {
2023-03-06 14:17:01 +01:00
if ( clip - > start ( ) < = note . on_sample & & clip - > end ( ) > = note . on_sample )
clip - > set_note ( note ) ;
2022-07-13 12:44:19 +02:00
}
}
void NoteTrack : : remove_note ( RollNote note )
{
for ( auto & clip : m_clips )
2023-03-06 14:17:01 +01:00
clip - > remove_note ( note ) ;
2022-07-13 12:44:19 +02:00
}
void NoteTrack : : add_clip ( u32 start_time , u32 end_time )
{
m_clips . append ( AK : : make_ref_counted < NoteClip > ( start_time , end_time ) ) ;
}
2021-08-27 16:18:11 +02:00
}