-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
ALSAFullDuplexMinScan.C
128 lines (107 loc) · 4.73 KB
/
ALSAFullDuplexMinScan.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* Copyright 2000-2021 Matt Flax <flatmax@flatmax.org>
This file is part of GTK+ IOStream class set
GTK+ IOStream is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
GTK+ IOStream is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You have received a copy of the GNU General Public License
along with GTK+ IOStream
*/
#include "ALSA/ALSA.H"
#include <iostream>
using namespace std;
using namespace ALSA;
#include "Sox.H"
class FullDuplexTest : public FullDuplex<int> {
#define CH_CNT 8
int N; ///< The number of frames
int ch; ///< The number of channels
int ch7Offset=-3; ///< The channel 7 offset from zero
Eigen::Array<int, Eigen::Dynamic, CH_CNT> shiftedData;
/** Your class must inherit this class and implement the process method.
The inputAudio and outputAudio variables should be resized to the number of channels
and frames you want to process. Note that the number of frames must be the same for
both the inputAudio and outputAudio variables.
\return <0 on error, 0 to continue and >0 to stop.
*/
int process(){
if (inputAudio.rows()!=N || inputAudio.cols()!=ch){
inputAudio.resize(N, ch);
outputAudio.resize(N, ch);
shiftedData.resize(N, ch);
inputAudio.setZero();
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////
// The following ensures that shiftedData contains the input audio WITHOUT channel swapping
//
// find the zero columns (for the Audio Injector Octo these are actually -256 not zero)
Eigen::Array<int, 1, CH_CNT> mins = inputAudio.colwise().minCoeff();
if (mins(0)==mins(CH_CNT-1)==-256)
ch7Offset=7;
else
for(int i=0; i<mins.cols()-1; ++i)
if(mins(i)==-256 && mins(i+1)==-256){
ch7Offset=i;
break;
}
// cout<<mins<<'\t'<<ch7Offset<<'\n';
// printf("ch7Offset %d \n",ch7Offset);
// if necessary circularly shift audio channels to realign input
if (ch7Offset!=6) // when it is 6, it is in the right location so skip that case
if (ch7Offset!=7){ // here we need a variable amount of circular column shifting
shiftedData.leftCols(CH_CNT-ch7Offset-2)=inputAudio.rightCols(CH_CNT-ch7Offset-2);
shiftedData.rightCols(ch7Offset+2)=inputAudio.leftCols(ch7Offset+2);
} else { // ch 7 is in ch 8's position so circularly shift by one
shiftedData.leftCols(CH_CNT-1)=inputAudio.rightCols(CH_CNT-1);
shiftedData.rightCols(1)=inputAudio.leftCols(1);
}
//
// shiftedData has the correct channel alignment at this point
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// handle channel rotations for output audio.
//
// TODO : If your algorithm outputs audio, handle your audio data here, performing the necessary steps to
// ensure that channel swapping doesn't exist in your output audio - in a similar way to the input audio.
// Question : If you swap the output audio in the opposite direction to the input audio swap above, does this ensure that output audio is always in the correct channel alignment ?
//
////////////////////////////////////////////////////////////////////
outputAudio=inputAudio; // copy the shifted data out - assumes that both output and input are equally shifted
return 0; // return 0 to continue
}
public:
FullDuplexTest(const char*devName, int latency) : FullDuplex(devName){
ch=CH_CNT; // use this static number of input and output channels.
N=latency;
inputAudio.resize(0,0); // force zero size to ensure resice on the first process.
outputAudio.resize(0,0);
}
};
int main(int argc, char *argv[]) {
int latency=4096;
int fs=48000; // The sample rate
cout<<"latency = "<<(float)latency/(float)fs<<" s"<<endl;
const char deviceName[]="hw:0";
FullDuplexTest fullDuplex(deviceName, latency);
cout<<"opened the device "<<fullDuplex.Playback::getDeviceName()<<endl;
cout<<"channels max "<<fullDuplex.Playback::getMaxChannels()<<endl;
// we don't want defaults so reset and refil the params ...
int res=fullDuplex.resetParams();
if (res<0)
return res;
snd_pcm_format_t format=SND_PCM_FORMAT_S32_LE;
if ((res=fullDuplex.setFormat(format))<0)
return res;
res=fullDuplex.setAccess(SND_PCM_ACCESS_RW_INTERLEAVED);
if (res<0)
return res;
if ((res=fullDuplex.setSampleRate(fs))<0)
return res;
res=fullDuplex.go(); // start the full duplex read/write/process going.
return ALSADebug().evaluateError(res);
}