2021-08-27 16:18:11 +02:00
/*
* Copyright ( c ) 2021 , kleines Filmröllchen < malu . bertsch @ gmail . com >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# pragma once
# include <AK/FixedPoint.h>
# include <AK/Format.h>
2021-09-28 17:50:12 +02:00
# include <AK/Forward.h>
2021-08-27 16:18:11 +02:00
# include <AK/Types.h>
# include <LibCore/Object.h>
2021-09-28 17:50:12 +02:00
# include <LibDSP/Music.h>
2021-08-27 16:18:11 +02:00
namespace LibDSP {
using ParameterFixedPoint = FixedPoint < 8 , i64 > ;
2021-09-28 18:01:39 +02:00
// Identifies the different kinds of parameters.
// Note that achieving parameter type identification is NOT possible with typeid().
enum class ParameterType : u8 {
Invalid = 0 ,
Range ,
Enum ,
Boolean ,
} ;
2021-08-27 16:18:11 +02:00
// Processors have modifiable parameters that should be presented to the UI in a uniform way without requiring the processor itself to implement custom interfaces.
class ProcessorParameter {
public :
2021-09-28 18:01:39 +02:00
ProcessorParameter ( String name , ParameterType type )
2021-08-27 16:18:11 +02:00
: m_name ( move ( name ) )
2021-09-28 18:01:39 +02:00
, m_type ( type )
2021-08-27 16:18:11 +02:00
{
}
String const & name ( ) const { return m_name ; }
2021-09-28 18:01:39 +02:00
ParameterType type ( ) const { return m_type ; }
2021-08-27 16:18:11 +02:00
private :
String const m_name ;
2021-09-28 18:01:39 +02:00
ParameterType const m_type ;
2021-08-27 16:18:11 +02:00
} ;
namespace Detail {
struct ProcessorParameterSetValueTag {
explicit ProcessorParameterSetValueTag ( ) = default ;
} ;
template < typename ParameterT >
class ProcessorParameterSingleValue : public ProcessorParameter {
public :
2021-09-28 18:01:39 +02:00
ProcessorParameterSingleValue ( String name , ParameterType type , ParameterT initial_value )
: ProcessorParameter ( move ( name ) , type )
2021-08-27 16:18:11 +02:00
, m_value ( move ( initial_value ) )
{
}
operator ParameterT ( ) const
{
return value ( ) ;
}
operator double ( ) const requires ( IsSame < ParameterT , ParameterFixedPoint > )
{
return static_cast < double > ( value ( ) ) ;
}
ParameterT value ( ) const { return m_value ; } ;
void set_value ( ParameterT value )
{
set_value_sneaky ( value , LibDSP : : Detail : : ProcessorParameterSetValueTag { } ) ;
if ( did_change_value )
did_change_value ( value ) ;
}
// Use of this function is discouraged. It doesn't notify the value listener.
void set_value_sneaky ( ParameterT value , [ [ maybe_unused ] ] Detail : : ProcessorParameterSetValueTag )
{
if ( value ! = m_value )
m_value = value ;
}
Function < void ( ParameterT const & ) > did_change_value ;
protected :
ParameterT m_value ;
} ;
}
class ProcessorBooleanParameter final : public Detail : : ProcessorParameterSingleValue < bool > {
public :
ProcessorBooleanParameter ( String name , bool initial_value )
2021-09-28 18:01:39 +02:00
: Detail : : ProcessorParameterSingleValue < bool > ( move ( name ) , ParameterType : : Boolean , move ( initial_value ) )
2021-08-27 16:18:11 +02:00
{
}
} ;
class ProcessorRangeParameter final : public Detail : : ProcessorParameterSingleValue < ParameterFixedPoint > {
public :
ProcessorRangeParameter ( String name , ParameterFixedPoint min_value , ParameterFixedPoint max_value , ParameterFixedPoint initial_value )
2021-09-28 18:01:39 +02:00
: Detail : : ProcessorParameterSingleValue < ParameterFixedPoint > ( move ( name ) , ParameterType : : Range , move ( initial_value ) )
2021-08-27 16:18:11 +02:00
, m_min_value ( move ( min_value ) )
, m_max_value ( move ( max_value ) )
, m_default_value ( move ( initial_value ) )
{
VERIFY ( initial_value < = max_value & & initial_value > = min_value ) ;
}
ProcessorRangeParameter ( ProcessorRangeParameter const & to_copy )
: ProcessorRangeParameter ( to_copy . name ( ) , to_copy . min_value ( ) , to_copy . max_value ( ) , to_copy . value ( ) )
{
}
ParameterFixedPoint min_value ( ) const { return m_min_value ; }
ParameterFixedPoint max_value ( ) const { return m_max_value ; }
ParameterFixedPoint default_value ( ) const { return m_default_value ; }
void set_value ( ParameterFixedPoint value )
{
VERIFY ( value < = m_max_value & & value > = m_min_value ) ;
Detail : : ProcessorParameterSingleValue < ParameterFixedPoint > : : set_value ( value ) ;
}
private :
double const m_min_value ;
double const m_max_value ;
double const m_default_value ;
} ;
2021-10-31 14:09:43 +01:00
template < typename EnumT >
requires ( IsEnum < EnumT > ) class ProcessorEnumParameter final : public Detail : : ProcessorParameterSingleValue < EnumT > {
public :
ProcessorEnumParameter ( String name , EnumT initial_value )
2021-09-28 18:01:39 +02:00
: Detail : : ProcessorParameterSingleValue < EnumT > ( move ( name ) , ParameterType : : Enum , initial_value )
2021-10-31 14:09:43 +01:00
{
}
} ;
2021-08-27 16:18:11 +02:00
}
template < >
struct AK : : Formatter < LibDSP : : ProcessorRangeParameter > : AK : : StandardFormatter {
Formatter ( ) = default ;
explicit Formatter ( StandardFormatter formatter )
: StandardFormatter ( formatter )
{
}
2021-11-16 01:15:21 +01:00
ErrorOr < void > format ( FormatBuilder & builder , LibDSP : : ProcessorRangeParameter value )
2021-08-27 16:18:11 +02:00
{
if ( m_mode = = Mode : : Pointer ) {
Formatter < FlatPtr > formatter { * this } ;
2021-11-16 01:15:21 +01:00
return formatter . format ( builder , reinterpret_cast < FlatPtr > ( & value ) ) ;
2021-08-27 16:18:11 +02:00
}
if ( m_sign_mode ! = FormatBuilder : : SignMode : : Default )
VERIFY_NOT_REACHED ( ) ;
if ( m_alternative_form )
VERIFY_NOT_REACHED ( ) ;
if ( m_zero_pad )
VERIFY_NOT_REACHED ( ) ;
if ( m_mode ! = Mode : : Default )
VERIFY_NOT_REACHED ( ) ;
if ( m_width . has_value ( ) & & m_precision . has_value ( ) )
VERIFY_NOT_REACHED ( ) ;
m_width = m_width . value_or ( 0 ) ;
m_precision = m_precision . value_or ( NumericLimits < size_t > : : max ( ) ) ;
2021-11-16 01:15:21 +01:00
TRY ( builder . put_literal ( String : : formatted ( " [{} - {}]: {} " , value . min_value ( ) , value . max_value ( ) , value . value ( ) ) ) ) ;
return { } ;
2021-08-27 16:18:11 +02:00
}
} ;