File Coverage

blib/lib/Audio/C4Stream/Mixer.pm
Criterion Covered Total %
statement 15 68 22.0
branch 0 20 0.0
condition n/a
subroutine 5 9 55.5
pod 2 3 66.6
total 22 100 22.0


line stmt bran cond sub pod time code
1             package Audio::C4Stream::Mixer;
2              
3 1     1   26588 use 5.010001;
  1         4  
  1         37  
4 1     1   6 use strict;
  1         2  
  1         32  
5 1     1   6 use warnings;
  1         7  
  1         157  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             our %EXPORT_TAGS = ( 'all' => [ qw() ] );
12             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
13             our @EXPORT = qw();
14              
15             our $VERSION = '1.00';
16              
17             require XSLoader;
18             XSLoader::load('Audio::C4Stream::Mixer', $VERSION);
19              
20 1     1   39 use Carp;
  1         2  
  1         7223  
21              
22             # 44100, 16bits, stereo
23 1     1   8 use constant PCMRATE => 176_400;
  1         2  
  1         774  
24              
25             sub new {
26 0     0 0   my $class = shift;
27 0           my %parms = @_;
28              
29 0           my $this = {
30             duration => 5,
31             silentOut => 2,
32             silentIn => 0,
33             %parms,
34             _buffer => '',
35             _decks => ['', ''], # just two deck A, B
36             _currentDeck => 0,
37             _crossfading => 0
38             };
39            
40 0           $this->{_crossfadeLen} = $this->{duration} * PCMRATE;
41 0           $this->{_crossfader} = CROSSFADE_init ($this->{duration});
42            
43 0           $this->{_silentOutData} = '';
44 0 0         if ($this->{silentOut}) {
45 0           my $size = int (($this->{silentOut} * PCMRATE) / 4) * 4;
46 0           $this->{_silentOutData} = pack ('c', 0) x $size;
47             }
48            
49 0           $this->{_silentInData} = '';
50 0 0         if ($this->{silentIn}) {
51 0           my $size = int (($this->{silentIn} * PCMRATE) / 4) * 4;
52 0           $this->{_silentInData} = pack ('c', 0) x $size;
53             }
54            
55 0           $this->{_crossfadeLen} = int ($this->{_crossfadeLen} / 4) * 4;
56            
57 0           return bless $this, $class;
58             }
59              
60             sub mixPcmFrames {
61 0     0 1   my $this = shift;
62 0           my $frames = shift;
63              
64 0           my $decks = $this->{_decks};
65              
66 0           $decks->[$this->{_currentDeck}] .= $frames;
67 0           my $len = length($decks->[$this->{_currentDeck}]);
68            
69             # buffer for crossfading has reach the good len
70 0 0         if (! $this->{_crossfading}) {
71 0 0         if ($len > $this->{_crossfadeLen}) {
72 0           my $data = substr ($decks->[$this->{_currentDeck}], 0, $len - $this->{_crossfadeLen}, '');
73            
74 0           return $data;
75             }
76             }
77             else {
78 0 0         if ($len >= $this->{_crossfadeLen}) {
79 0           my $prevDeck = ($this->{_currentDeck} + 1) % 2;
80            
81             # if silentOut append silentOutData to the end of the previous deck
82 0 0         if ($this->{silentOut}) {
83 0           $decks->[$prevDeck] .= $this->{_silentOutData};
84             }
85            
86 0           my $crossfadeLen = $this->{_crossfadeLen};
87            
88 0           my $lenPrevDeck = length($decks->[$prevDeck]);
89            
90 0           my $left = '';
91 0 0         if ($lenPrevDeck >= $crossfadeLen) {
92 0           $left = substr ($decks->[$prevDeck], 0, $lenPrevDeck - $crossfadeLen, '');
93             }
94            
95 0           my $dataP = $decks->[$prevDeck];
96 0 0         if (! length($dataP)) {
97 0           my $data = substr ($decks->[$this->{_currentDeck}], 0, $len - $crossfadeLen, '');
98            
99 0           return $data;
100             }
101              
102             # if silentIn add silentInData in front of the current deck
103 0 0         if ($this->{silentIn}) {
104 0           $decks->[$this->{_currentDeck}] = $this->{_silentInData} . $decks->[$this->{_currentDeck}];
105             }
106            
107 0           my $dataN = substr ($decks->[$this->{_currentDeck}], 0, $crossfadeLen, '');
108 0           $decks->[$prevDeck] = '';
109              
110 0           $this->{_crossfading} = 0;
111            
112             # if there is not enough in dataP simple concat
113 0 0         if ($lenPrevDeck < $crossfadeLen) {
114 0           return $dataN.$dataP;
115             }
116            
117 0           my $mixed = $dataP;
118 0           CROSSFADE_ease_in_out_quad ($this->{_crossfader}, $dataP, $dataN, $mixed);
119              
120 0           return $left.$mixed;
121             }
122             }
123            
124 0           return '';
125             }
126              
127             sub switch {
128 0     0 1   my $this = shift;
129            
130 0           my $decks = $this->{_decks};
131            
132             # switch the current deck
133 0           $this->{_currentDeck} = ($this->{_currentDeck} + 1) % 2;
134            
135 0           $this->{_crossfading} = 1;
136             }
137              
138             sub DESTROY {
139 0     0     my $this = shift;
140             }
141              
142             1;
143             __END__