d@0
|
1 /*
|
d@0
|
2 ==============================================================================
|
d@0
|
3
|
d@0
|
4 AudioReader.cpp
|
d@0
|
5 Created: 27 Aug 2014 3:17:10pm
|
d@0
|
6 Author: david.ronan
|
d@0
|
7
|
d@0
|
8 ==============================================================================
|
d@0
|
9 */
|
d@0
|
10
|
d@0
|
11
|
d@0
|
12
|
d@0
|
13
|
d@0
|
14 #include "AudioReader.h"
|
d@0
|
15 #include "WriteCSV.h"
|
d@0
|
16 #include <iostream>
|
d@0
|
17 #include <vector>
|
d@0
|
18
|
d@0
|
19 #define ENERGYSEARCHTIME 3
|
d@0
|
20 #define SAMPLERATE 22050.0f
|
d@13
|
21 #include "XMLWrite.h"
|
d@0
|
22
|
d@0
|
23 AudioReader::AudioReader()
|
d@2
|
24 {
|
d@1
|
25
|
d@0
|
26 };
|
d@0
|
27
|
d@0
|
28 AudioReader::~AudioReader()
|
d@0
|
29 {
|
d@0
|
30
|
d@0
|
31 };
|
d@0
|
32
|
d@0
|
33 std::vector<FeatureData> AudioReader::Read(AudioFileData audioFileData, float poolTimeSecs, int analysisWindowSize)
|
d@0
|
34 {
|
d@0
|
35 WriteCSV writeCSV = WriteCSV();
|
d@13
|
36 XMLWrite xmlWrite = XMLWrite();
|
d@0
|
37 std::vector<FeatureData> featureData = std::vector<FeatureData>();
|
d@0
|
38 std::string CSVFileName = "..\\FeatureData" + writeCSV.currentDateTime();
|
d@1
|
39
|
d@0
|
40 vector<string> audioFileNames = audioFileData.GetFileNames();
|
d@2
|
41 vector<string> labels = audioFileData.GetLabels();
|
d@2
|
42
|
d@1
|
43 AudioFormatManager m_formatManager;
|
d@1
|
44 m_formatManager.registerBasicFormats();
|
d@1
|
45 m_AudioSourceFeatureExtractor.Initialise(SAMPLERATE);
|
d@0
|
46
|
d@0
|
47 for(size_t i=0; i<audioFileNames.size(); i++)
|
d@0
|
48 {
|
d@3
|
49 float percentcomplete = static_cast<float>(i) / static_cast<float>(audioFileNames.size()) * 100.0f;
|
d@0
|
50
|
d@0
|
51 std::string outputStr = "Extracting features for " + audioFileNames[i] + "\n" + std::to_string(percentcomplete) + "% complete...";
|
d@0
|
52 cout << outputStr;
|
d@9
|
53
|
d@0
|
54 //Create file from our audio data
|
d@0
|
55 File audioFile(audioFileNames[i].c_str());
|
d@0
|
56
|
d@9
|
57 unique_ptr<AudioFormatReader> audioFileReader(m_formatManager.createReaderFor(audioFile));
|
d@1
|
58
|
d@3
|
59 if(audioFileReader != nullptr)
|
d@3
|
60 {
|
d@3
|
61 float fSampleRate = static_cast<float>(audioFileReader->sampleRate);
|
d@3
|
62 int iLengthInSamples = static_cast<int>(audioFileReader->lengthInSamples);
|
d@3
|
63 int iNumOfChannels = audioFileReader->numChannels;
|
d@1
|
64
|
d@3
|
65 if (fSampleRate != 22050.0f)
|
d@0
|
66 {
|
d@0
|
67 cout << "\n\n\nERROR: File is not the required 22050 Hz sample rate.!!!\n\n\n";
|
d@0
|
68 }
|
d@1
|
69
|
d@0
|
70 //Get loudest 30 secs. of audio
|
d@3
|
71 int numOfSamplesToCollect = static_cast<int>(analysisWindowSize * fSampleRate);
|
d@0
|
72
|
d@3
|
73 if(iLengthInSamples <= numOfSamplesToCollect)
|
d@0
|
74 {
|
d@3
|
75 numOfSamplesToCollect = iLengthInSamples;
|
d@0
|
76 }
|
d@0
|
77
|
d@0
|
78 //Length of the full track in stereo;
|
d@9
|
79 int* destSamples[2] = { nullptr };
|
d@9
|
80 unique_ptr<int> L(new int[iLengthInSamples]);
|
d@9
|
81 memset(L.get(), 0, iLengthInSamples);
|
d@9
|
82 destSamples[0] = L.get();
|
d@9
|
83 destSamples[1] = L.get();
|
d@1
|
84
|
d@9
|
85
|
d@0
|
86 //30 sec clips to check energy levels
|
d@9
|
87 std::vector<float> destSamplesFloat = std::vector<float>(static_cast<size_t>(numOfSamplesToCollect, 0));
|
d@0
|
88
|
d@1
|
89 int timesToLoop = 0;
|
d@0
|
90
|
d@3
|
91 if(iLengthInSamples == numOfSamplesToCollect)
|
d@0
|
92 {
|
d@0
|
93 timesToLoop = 1;
|
d@0
|
94 }
|
d@0
|
95 else
|
d@0
|
96 {
|
d@3
|
97 timesToLoop = static_cast<int>((iLengthInSamples - numOfSamplesToCollect) / (ENERGYSEARCHTIME * fSampleRate));
|
d@0
|
98 }
|
d@0
|
99
|
d@0
|
100 std::vector<float> thirtySecEnergy = std::vector<float>();
|
d@0
|
101
|
d@0
|
102 //float loudestEnergy = 0.0;
|
d@9
|
103 bool dave;
|
d@9
|
104 dave = audioFileReader->readSamples(destSamples, iNumOfChannels, 0, 0, iLengthInSamples);
|
d@0
|
105
|
d@0
|
106 for(int j=0; j < timesToLoop;j++)
|
d@1
|
107 {
|
d@0
|
108 float fSum=0.f;
|
d@0
|
109
|
d@0
|
110 for(int n=0; n<numOfSamplesToCollect; n++)
|
d@0
|
111 {
|
d@0
|
112 //Sum to mono if needed and workout the energy for each 30 sec. frame
|
d@3
|
113 if(iNumOfChannels > 1)
|
d@0
|
114 {
|
d@9
|
115 destSamplesFloat.push_back(static_cast<float>((destSamples[0][int(j * ENERGYSEARCHTIME * fSampleRate) + n] + destSamples[1][int( j * ENERGYSEARCHTIME * fSampleRate) + n]) / 2) / (0x7fffffff));
|
d@0
|
116 }
|
d@0
|
117 else
|
d@0
|
118 {
|
d@9
|
119 destSamplesFloat.push_back(static_cast<float>(destSamples[0][int(j * ENERGYSEARCHTIME * fSampleRate) + n]) / (0x7fffffff));
|
d@0
|
120 }
|
d@0
|
121
|
d@0
|
122 fSum+=(destSamplesFloat[n] * destSamplesFloat[n]);
|
d@0
|
123 }
|
d@0
|
124
|
d@0
|
125 //Normalise and push onto the list of 30 sec clips.
|
d@0
|
126 fSum /= numOfSamplesToCollect;
|
d@0
|
127
|
d@0
|
128 //if (fSum > loudestEnergy)
|
d@0
|
129 //{
|
d@0
|
130 // loudestEnergy = fSum;
|
d@0
|
131 // destSamplesFloatLoudest = destSamplesFloat;
|
d@0
|
132 //}
|
d@0
|
133
|
d@0
|
134 thirtySecEnergy.push_back(fSum);
|
d@0
|
135 }
|
d@0
|
136
|
d@1
|
137 //Find the index of the section with the most energy
|
d@0
|
138 int maxIdx = std::distance(thirtySecEnergy.begin(), max_element(thirtySecEnergy.begin(), thirtySecEnergy.end()));
|
d@0
|
139
|
d@0
|
140 int* thirtySecSamples[2] = {0};
|
d@9
|
141 unique_ptr<int> L30(new int[iLengthInSamples]{ 0 });
|
d@9
|
142 memset(L30.get(), 0, iLengthInSamples);
|
d@9
|
143 thirtySecSamples[0]=L30.get(); //Left channel
|
d@9
|
144 thirtySecSamples[1]=L30.get(); //Left right
|
d@0
|
145
|
d@0
|
146 //Read the 30 secs. in
|
d@3
|
147 audioFileReader->readSamples(thirtySecSamples, iNumOfChannels, 0, int(maxIdx * ENERGYSEARCHTIME * fSampleRate), numOfSamplesToCollect);
|
d@9
|
148
|
d@9
|
149 destSamplesFloat = std::vector<float>(static_cast<size_t>(numOfSamplesToCollect, 0));
|
d@0
|
150
|
d@0
|
151 for(int n=0; n<numOfSamplesToCollect; n++)
|
d@1
|
152 {
|
d@1
|
153 //Sum to mono if needed
|
d@3
|
154 if(iNumOfChannels > 1)
|
d@0
|
155 {
|
d@9
|
156 destSamplesFloat.push_back(static_cast<float>((thirtySecSamples[0][n] + thirtySecSamples[1][n]) / 2) / (0x7fffffff));
|
d@0
|
157 }
|
d@0
|
158 else
|
d@0
|
159 {
|
d@9
|
160 destSamplesFloat.push_back(static_cast<float>(thirtySecSamples[0][n]) / (0x7fffffff));
|
d@0
|
161 }
|
d@0
|
162 }
|
d@0
|
163
|
d@9
|
164 std::vector<ObservationData> newObs = m_AudioSourceFeatureExtractor.Process(destSamplesFloat);
|
d@1
|
165
|
d@3
|
166 FeatureData newFeature = FeatureData(newObs, labels[i], audioFileNames[i], fSampleRate, FFTSIZE, static_cast<float>(numOfSamplesToCollect), poolTimeSecs);
|
d@1
|
167
|
d@14
|
168 //XML from now on.
|
d@0
|
169 writeCSV.Write(CSVFileName, newFeature);
|
d@13
|
170 xmlWrite.Write(CSVFileName, newFeature);
|
d@1
|
171
|
d@0
|
172 //Update the screen information;
|
d@2
|
173
|
d@9
|
174 cout << string(outputStr.length(),'\b');
|
d@3
|
175
|
d@0
|
176 }
|
d@0
|
177 else
|
d@0
|
178 {
|
d@0
|
179 cout << "\n\n\nERROR: Could not find file!!!\n\n\n";
|
d@3
|
180 }
|
d@0
|
181 }
|
d@0
|
182
|
d@0
|
183 m_AudioSourceFeatureExtractor.Finalize();
|
d@1
|
184
|
d@0
|
185 return featureData;
|
d@2
|
186 };
|