@@ -608,41 +608,80 @@ class ConvertedStream : public AudioStreamX {
608
608
609
609
};
610
610
611
+ /* *
612
+ * @brief Config for VolumeStream
613
+ * @author Phil Schatzmann
614
+ * @copyright GPLv3
615
+ */
616
+ struct VolumeStreamConfig : public AudioBaseInfo {
617
+ VolumeStreamConfig (){
618
+ bits_per_sample = 16 ;
619
+ channels = 2 ;
620
+ }
621
+ bool allow_boost = false ;
622
+ float volume=1.0 ; // start_volume
623
+ };
624
+
611
625
/* *
612
626
* @brief Output PWM object on which we can apply some volume settings. To work properly the class needs to know the
613
- * bits per sample. If nothing is defined we assume 16 bits !
627
+ * bits per sample and number of channels !
614
628
* @author Phil Schatzmann
615
629
* @copyright GPLv3
616
630
*/
617
- // class VolumeOutput : public AudioPrint {
618
631
class VolumeStream : public AudioStreamX {
619
632
public:
620
633
// / Default Constructor
621
634
VolumeStream () = default ;
622
635
623
- VolumeStream (Print &out, bool allowBoost=false ) {
624
- begin (out, allowBoost);
636
+ ~VolumeStream () {
637
+ cleanup ();
638
+ };
639
+
640
+ VolumeStream (Print &out) {
641
+ setTarget (out);
625
642
}
626
643
627
644
// / Constructor which automatically calls begin(Print out)!
628
- VolumeStream (Stream &out, bool allowBoost= false ) {
629
- begin (out, allowBoost );
645
+ VolumeStream (Stream &in ) {
646
+ setTarget (in );
630
647
}
631
648
632
- // / Assigns the final output
633
- bool begin (Print &out, bool allowBoost=true ){
634
- LOGD (LOG_METHOD);
649
+ void setTarget (Print &out){
635
650
p_out = &out;
636
- allow_boost = allowBoost;
637
- return true ;
638
651
}
639
-
640
- // / Assigns the final output
641
- bool begin (Stream &in, bool allowBoost=false ){
642
- LOGD (LOG_METHOD);
652
+
653
+ void setTarget (Stream &in){
643
654
p_in = ∈
644
655
p_out = p_in;
645
- allow_boost = allowBoost;
656
+ }
657
+
658
+ VolumeStreamConfig defaultConfig () {
659
+ VolumeStreamConfig c;
660
+ return c;
661
+ }
662
+
663
+ bool begin (AudioBaseInfo cfg){
664
+ VolumeStreamConfig cfg1;
665
+ cfg1.channels = cfg.channels ;
666
+ cfg1.sample_rate = cfg.sample_rate ;
667
+ cfg1.bits_per_sample = cfg.bits_per_sample ;
668
+ return begin (cfg1);
669
+ }
670
+
671
+ void end () {
672
+ is_active = false ;
673
+ }
674
+
675
+ // / starts the processing
676
+ bool begin (VolumeStreamConfig cfg){
677
+ LOGD (LOG_METHOD);
678
+ info = cfg;
679
+ max_value = NumberConverter::maxValue (info.bits_per_sample );
680
+ if (info.channels >max_channels){
681
+ max_channels = info.channels ;
682
+ }
683
+ // set start volume
684
+ setVolume (cfg.volume );
646
685
return true ;
647
686
}
648
687
@@ -664,19 +703,18 @@ class VolumeStream : public AudioStreamX {
664
703
return 0 ;
665
704
}
666
705
size_t result = p_in->readBytes (buffer, length);
667
- if (volume_value != 1.0 ) applyVolume (buffer, result);
706
+ if (is_active ) applyVolume (buffer, result);
668
707
return result;
669
708
}
670
709
671
-
672
710
// / Writes raw PCM audio data, which will be the input for the volume control
673
711
virtual size_t write (const uint8_t *buffer, size_t size) override {
674
712
LOGD (LOG_METHOD);
675
713
if (buffer==nullptr || p_out==nullptr ){
676
714
LOGE (" NPE" );
677
715
return 0 ;
678
716
}
679
- if (volume_value != 1.0 ) applyVolume (buffer,size);
717
+ if (is_active ) applyVolume (buffer,size);
680
718
return p_out->write (buffer, size);
681
719
}
682
720
@@ -691,54 +729,95 @@ class VolumeStream : public AudioStreamX {
691
729
}
692
730
693
731
// / Detines the Audio info - The bits_per_sample are critical to work properly!
694
- void setAudioInfo (AudioBaseInfo info ) override {
732
+ void setAudioInfo (AudioBaseInfo cfg ) override {
695
733
LOGD (LOG_METHOD);
696
- this ->info = info;
697
- max_value = NumberConverter::maxValue (info.bits_per_sample );
734
+ begin (cfg);
698
735
}
699
736
700
- // / Shortcut method to define the sample size (alternative to setAudioInfo())
701
- void setBitsPerSample (int bits_per_sample){
702
- info.bits_per_sample = bits_per_sample;
703
- max_value = NumberConverter::maxValue (info.bits_per_sample );
704
- }
705
-
706
- // / Shortcut method to define the sample size (alternative to setAudioInfo())
707
- void setBytesPerSample (int bytes_per_sample){
708
- info.bits_per_sample = bytes_per_sample * 8 ;
709
- max_value = NumberConverter::maxValue (info.bits_per_sample );
710
- }
711
-
712
- // / Decreases the volume: needs to be in the range of 0 to 1.0
737
+ // / Defines the volume for all channels: needs to be in the range of 0 to 1.0
713
738
void setVolume (float vol){
714
- if (!allow_boost && vol>1.0 ) vol = 1.0 ;
715
- if (vol<0.0 ) vol = 0.0 ;
739
+ for (int j=0 ;j<info.channels ;j++){
740
+ setVolume (vol, j);
741
+ }
742
+ }
716
743
717
- // round to 2 digits
718
- float value = (int )(vol * 100 + .5 );
719
- volume_value = (float )value / 100 ;;
720
- LOGI (" setVolume: %f" , volume_value);
744
+ // / Sets the volume for one channel
745
+ void setVolume (float vol, int channel){
746
+ if (channel<info.channels ){
747
+ setup (vol);
748
+ float volume_value = volumeValue (vol);
749
+ LOGI (" setVolume: %f" , volume_value);
750
+ float factor = volumeControl ().getVolumeFactor (volume_value);
751
+ factor_for_channel[channel]=factor;
752
+ } else {
753
+ LOGE (" Invalid channel %d - max: %d" , channel, info.channels -1 );
754
+ }
721
755
}
722
756
723
757
// / Provides the current volume setting
724
758
float volume () {
725
- return volume_value;
759
+ return volume_values[0 ];
760
+ }
761
+
762
+ // / Provides the current volume setting for the indicated channel
763
+ float volume (int channel) {
764
+ return channel>=info.channels ? 0 : volume_values[channel];
726
765
}
727
766
728
767
protected:
729
768
Print *p_out=nullptr ;
730
769
Stream *p_in=nullptr ;
731
- AudioBaseInfo info;
732
- float volume_value=1.0 ;
770
+ VolumeStreamConfig info;
733
771
SimulatedAudioPot default_volume;
734
772
CachedVolumeControl cached_volume = CachedVolumeControl(default_volume);
735
- bool allow_boost = false ; // allows a factor > 1.0
736
- float max_value = NumberConverter::maxValue(info.bits_per_sample); // max value for clippint
773
+ float *volume_values = nullptr ;
774
+ float *factor_for_channel = nullptr ;
775
+ bool is_active = false ;
776
+ float max_value = 32767 ; // max value for clipping
777
+ int max_channels=0 ;
778
+
779
+ void setup (float vol) {
780
+ is_active = vol!=1.0 ;
781
+ if (info.channels >max_channels){
782
+ cleanup ();
783
+ }
784
+ if (factor_for_channel==nullptr ){
785
+ factor_for_channel = new float [info.channels ];
786
+ }
787
+ if (volume_values==nullptr ){
788
+ volume_values = new float [info.channels ];
789
+ }
790
+ }
791
+
792
+ void cleanup () {
793
+ if (factor_for_channel!=nullptr ) {
794
+ delete [] factor_for_channel;
795
+ factor_for_channel = nullptr ;
796
+ }
797
+ if (volume_values!=nullptr ) {
798
+ delete [] volume_values;
799
+ volume_values = nullptr ;
800
+ }
801
+ }
802
+
803
+ float volumeValue (float vol){
804
+ if (!info.allow_boost && vol>1.0 ) vol = 1.0 ;
805
+ if (vol<0.0 ) vol = 0.0 ;
806
+
807
+ // round to 2 digits
808
+ float value = (int )(vol * 100 + .5 );
809
+ float volume_value = (float )value / 100 ;
810
+ return volume_value;
811
+ }
737
812
738
813
VolumeControl &volumeControl (){
739
814
return cached_volume;
740
815
}
741
816
817
+ float factorForChannel (int channel){
818
+ return factor_for_channel==nullptr ? 1.0 : factor_for_channel[channel];
819
+ }
820
+
742
821
void applyVolume (const uint8_t *buffer, size_t size){
743
822
switch (info.bits_per_sample ){
744
823
case 16 :
@@ -756,10 +835,9 @@ class VolumeStream : public AudioStreamX {
756
835
}
757
836
758
837
void applyVolume16 (int16_t * data, size_t size){
759
- float factor = volumeControl ().getVolumeFactor (volume_value);
760
838
for (size_t j=0 ;j<size;j++){
761
- float result = factor * data[j];
762
- if (allow_boost){
839
+ float result = factorForChannel (j%info. channels ) * data[j];
840
+ if (info. allow_boost ){
763
841
if (result>max_value) result = max_value;
764
842
if (result<-max_value) result = -max_value;
765
843
}
@@ -768,10 +846,9 @@ class VolumeStream : public AudioStreamX {
768
846
}
769
847
770
848
void applyVolume24 (int24_t * data, size_t size) {
771
- float factor = volumeControl ().getVolumeFactor (volume_value);
772
849
for (size_t j=0 ;j<size;j++){
773
- float result = factor * data[j];
774
- if (allow_boost){
850
+ float result = factorForChannel (j%info. channels ) * data[j];
851
+ if (info. allow_boost ){
775
852
if (result>max_value) result = max_value;
776
853
if (result<-max_value) result = -max_value;
777
854
}
@@ -781,10 +858,9 @@ class VolumeStream : public AudioStreamX {
781
858
}
782
859
783
860
void applyVolume32 (int32_t * data, size_t size) {
784
- float factor = volumeControl ().getVolumeFactor (volume_value);
785
861
for (size_t j=0 ;j<size;j++){
786
- float result = factor * data[j];
787
- if (allow_boost){
862
+ float result = factorForChannel (j%info. channels ) * data[j];
863
+ if (info. allow_boost ){
788
864
if (result>max_value) result = max_value;
789
865
if (result<-max_value) result = -max_value;
790
866
}
0 commit comments