gtkIOStream  1.7.0
GTK+ << C++ IOStream operators for GTK+. Now with ORBing, numerical computation, audio client and more ...
Sox.H
Go to the documentation of this file.
1 /* This file was contributed by Deqx.com
2  Copyright 2000-2018 Matt Flax <flatmax@flatmax.org>
3  This file is part of GTK+ IOStream class set
4 
5  GTK+ IOStream is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  GTK+ IOStream is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You have received a copy of the GNU General Public License
16  along with GTK+ IOStream
17 */
18 #ifndef SOX_H_
19 #define SOX_H_
20 
21 #if defined(_MSC_VER) || defined(__CYGWIN__)
22 #error On microsoft, please rename this file to SoxWindows.H and delete this line.
23 #endif
24 
25 #include <Debug.H>
26 #pragma GCC diagnostic push
27 #pragma GCC diagnostic ignored "-Wignored-attributes"
28 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
29 #include <Eigen/Dense>
30 #pragma GCC diagnostic pop
31 
32 #define SOX_READ_FILE_OPEN_ERROR SOX_ERROR_OFFSET-1
33 #define SOX_CLOSE_FILE_ERROR SOX_ERROR_OFFSET-2
34 #define SOX_READ_FILE_NOT_OPENED_ERROR SOX_ERROR_OFFSET-3
35 #define SOX_EOF_OR_ERROR SOX_ERROR_OFFSET-4
36 #define SOX_READ_MAXSCALE_ERROR SOX_ERROR_OFFSET-6
37 #define SOX_WRITE_FILE_OPEN_ERROR SOX_ERROR_OFFSET-7
38 #define SOX_WRITE_FILE_NOT_OPENED_ERROR SOX_ERROR_OFFSET-8
39 #define SOX_WRITE_OUT_CHANNEL_MISMATCH SOX_ERROR_OFFSET-9
40 #define SOX_WRITE_SAMPLES_WRITTEN_MISMATCH_ERROR SOX_ERROR_OFFSET-10
41 #define SOX_ROW_BOUNDS_ERROR SOX_ERROR_OFFSET-11
42 #define SOX_COL_BOUNDS_ERROR SOX_ERROR_OFFSET-12
43 
44 #include <sox.h>
45 
46 #include <limits> // for NaN
47 #include <vector>
48 using namespace std;
49 
50 #include "config.h"
51 
54 class SoxDebug : virtual public Debug {
55 public:
59 #ifndef NDEBUG
60  errors[SOX_READ_FILE_OPEN_ERROR]=string("SOX: Couldn't open the input file");
61  errors[SOX_CLOSE_FILE_ERROR]=string("SOX: Couldn't open the output file");
62  errors[SOX_READ_FILE_NOT_OPENED_ERROR]=string("SOX: Couldn't read from file as the input file hasn't been opened yet");
63  errors[SOX_EOF_OR_ERROR]=string("SOX: Either an error or the EOF was hit whilst operating on the file");
64  errors[SOX_READ_MAXSCALE_ERROR]=string("SOX: couldn't open the max file to find the value to rescale the maximum to, if you continue the audio file will not be re-scaled correctly");
65  errors[SOX_WRITE_FILE_OPEN_ERROR]=string("SOX: Couldn't write to file as the output file hasn't been opened yet");
66  errors[SOX_WRITE_FILE_NOT_OPENED_ERROR]=string("SOX: Couldn't write to the file as the output file hasn't been opened yet");
67  errors[SOX_WRITE_OUT_CHANNEL_MISMATCH]=string("SOX: you provided data to write out which doesn't match the number of channels specified during openWrite for the output file");
68  errors[SOX_WRITE_SAMPLES_WRITTEN_MISMATCH_ERROR]=string("SOX: The incorrect number of samples were written to file. ");
69  errors[SOX_ROW_BOUNDS_ERROR]=string("SOX: Row larger then the matrix size error. ");
70  errors[SOX_COL_BOUNDS_ERROR]=string("SOX: Col larger then the matrix size error. ");
71 #endif
72  }
73 
75  virtual ~SoxDebug() {}
76 };
77 
94 template<typename FP_TYPE_>
95 class Sox {
96  sox_format_t *in;
97  double maxVal;
98  sox_format_t *out;
99 
100  double outputMaxVal;
101  vector<sox_sample_t> outputBuffer;
102 
107  int close(bool inputFile);
108 
109  static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap);
110 
111 public:
112  Sox();
113  virtual ~Sox();
114 
120  int openRead(string fileName);
121 
126  int openRead(intptr_t buffer, size_t len);
127 
134  template <typename Derived>
135  int read(Eigen::DenseBase<Derived> &audioData, int count=0){
136  typedef typename Derived::Scalar Scalar;
137  int retVal=NO_ERROR; // start assuming no error
138  if (in) { // if the input file has been opened...
139  if (count==0) // if we want everything
140  count = in->signal.length/in->signal.channels;
141  Eigen::Array<sox_sample_t, Eigen::Dynamic, Eigen::Dynamic> readData(count*in->signal.channels,1); // generate the necessary data store to read into.
142  size_t readCount=sox_read(in, readData.data(), count*in->signal.channels); // try to read
143  if (readCount==SOX_EOF) { // if we hit the end of file or have an error
144  retVal=SOX_EOF_OR_ERROR;
145  audioData.resize(0,0);
146  } else { // all requested audio has been read, now resize the readData and
147  // ensure the audioData matrix is the correct size
148  if (audioData.cols()!= in->signal.channels | audioData.rows()!=readCount/in->signal.channels)
149  audioData.derived().resize(readCount/in->signal.channels, in->signal.channels);
150  if (!(maxVal != maxVal)) // if we know our desired maxval
151  for (int i=0; i<readCount; i++)
152  audioData(i/in->signal.channels,i%in->signal.channels)=(Scalar)(maxVal*(double)readData(i)/(double)numeric_limits<sox_sample_t>::max());
153  else {// scale to fullscale for the type
154  double scaleFact=(double)pow(2.,(double)sizeof(Scalar)*8.-1.);
155  for (int i=0; i<readCount; i++)
156  audioData(i/in->signal.channels,i%in->signal.channels)=(Scalar)(scaleFact*(double)readData(i)/(double)numeric_limits<sox_sample_t>::max());
157  }
158  }
159  } else
161  return retVal;
162  }
163 
174  virtual int openWrite(const string &fileName, double fs, int channels, double maxVal){
175  return openWrite(fileName, fs, channels, maxVal, sizeof(FP_TYPE_)*CHAR_BIT, false, sox_option_default, sox_option_default, sox_option_default);
176  }
177 
192  virtual int openWrite(const string &fileName, double fs, int channels, double maxVal, unsigned int wordSize, bool switchEndian, int revBytes, int revNibbles, int revBits);
193 
202  int openMemWrite(void *buffer, size_t len, double fs, int channels, double maxVal){
203  return openMemWrite(buffer, len, fs, channels, maxVal, sizeof(FP_TYPE_)*CHAR_BIT, false, sox_option_default, sox_option_default, sox_option_default);
204  }
205 
221  virtual int openMemWrite(void *buffer, size_t len, double fs, int channels, double maxVal, unsigned int wordSize, bool switchEndian, int revBytes, int revNibbles, int revBits);
222 
228  virtual int write(const vector<vector<FP_TYPE_> > &audioData);
229 
235  template <typename Derived>
236  int write(const Eigen::DenseBase<Derived> &audioData) {
237  int retVal=NO_ERROR; // start assuming no error
238  if (out) { // if the output file has been opened...
239  if (out->signal.channels!=audioData.cols())
241  else {
242  int ch=out->signal.channels;
243  int len=audioData.rows();
244  int total=ch*len;
245  if (outputBuffer.size()<total)
246  outputBuffer.resize(total);
247  for (int i=0; i<audioData.cols(); i++) // stride the interleaved outputBuffer with each channel
248  for (int j=0; j<len; j++)
249  outputBuffer[j*ch+i]=(sox_sample_t)((double)audioData(j,i)*((double)numeric_limits<sox_sample_t>::max()/outputMaxVal));
250  size_t writeCount=sox_write(out, &outputBuffer[0], total);
251  retVal=writeCount;
252  }
253  } else
255  return retVal;
256  }
257 
263  template <typename Derived>
264  int writeTransposed(const Eigen::DenseBase<Derived> &audioData) {
265  int retVal=NO_ERROR; // start assuming no error
266  if (out) { // if the output file has been opened...
267  if (out->signal.channels!=audioData.rows())
269  else {
270  int ch=out->signal.channels;
271  int len=audioData.cols();
272  int total=ch*len;
273  if (outputBuffer.size()<total)
274  outputBuffer.resize(total);
275  for (int i=0; i<audioData.rows(); i++) // stride the interleaved outputBuffer with each channel
276  for (int j=0; j<len; j++)
277  outputBuffer[j*ch+i]=(sox_sample_t)((double)audioData(i,j)/outputMaxVal*(double)numeric_limits<sox_sample_t>::max());
278  size_t writeCount=sox_write(out, &outputBuffer[0], total);
279  retVal=writeCount;
280  }
281  } else
283  return retVal;
284  }
285 
289  int closeRead(void);
290 
294  int closeWrite(void);
295 
300  void setMaxVal(double newMax) {
301  maxVal=newMax;
302  }
303 
308  double getMaxVal(void) {
309  return maxVal;
310  }
311 
315  double getFSIn(void) {
316  if (in)
317  return in->signal.rate;
318  return 0.;
319  }
320 
324  double getFSOut(void) {
325  if (out)
326  return out->signal.rate;
327  return 0.;
328  }
329 
333  int getChCntIn(void) {
334  if (in)
335  return in->signal.channels;
337  }
338 
342  int getChCntOut(void) {
343  if (out)
344  return out->signal.channels;
346  }
347 
351  vector<string> availableFormats(void);
352 
355  void printFormats();
356 
357 #ifdef HAVE_EMSCRIPTEN
358 
364  FP_TYPE_ getSample(unsigned int r, unsigned int c);
365 
369  unsigned int getRows();
370 
374  unsigned int getCols();
375 
380  int readJS(unsigned int count=0);
381 
382 private:
383  Eigen::Matrix<FP_TYPE_, Eigen::Dynamic, Eigen::Dynamic> audio;
384 #endif // HAVE_EMSCRIPTEN
385 };
386 #endif // SOX_H_
#define SOX_READ_MAXSCALE_ERROR
Sox couldn&#39;t open the filename.max to read the rescale value for the audio file.
Definition: Sox.H:36
int getChCntOut(void)
Definition: Sox.H:342
virtual int openWrite(const string &fileName, double fs, int channels, double maxVal)
Definition: Sox.H:174
#define SOX_WRITE_SAMPLES_WRITTEN_MISMATCH_ERROR
Error when trying to write data and the incorrect amount of data is written.
Definition: Sox.H:40
sox_format_t * out
output file
Definition: Sox.H:98
sox_format_t * in
input file
Definition: Sox.H:96
double maxVal
maxVal stored in the file fileName.max
Definition: Sox.H:97
#define SOX_COL_BOUNDS_ERROR
Error when trying to access a col out of bounds (Emscripten case)
Definition: Sox.H:42
STL namespace.
int openMemWrite(void *buffer, size_t len, double fs, int channels, double maxVal)
Definition: Sox.H:202
#define SOX_ROW_BOUNDS_ERROR
Error when trying to access a row out of bounds (Emscripten case)
Definition: Sox.H:41
#define SOX_WRITE_FILE_OPEN_ERROR
Error when libsox couldn&#39;t open the output file.
Definition: Sox.H:37
double getMaxVal(void)
Definition: Sox.H:308
#define NO_ERROR
There is no error.
Definition: Debug.H:33
#define SOX_READ_FILE_OPEN_ERROR
Error when libsox couldn&#39;t open the input file.
Definition: Sox.H:32
Definition: Sox.H:95
#define SOX_WRITE_FILE_NOT_OPENED_ERROR
Error when the output file hasn&#39;t already been opened using Sox::openRead.
Definition: Sox.H:38
int writeTransposed(const Eigen::DenseBase< Derived > &audioData)
Definition: Sox.H:264
Definition: Sox.H:54
double getFSIn(void)
Definition: Sox.H:315
int getChCntIn(void)
Definition: Sox.H:333
void setMaxVal(double newMax)
Definition: Sox.H:300
double outputMaxVal
The maximum value passed to write.
Definition: Sox.H:100
SoxDebug()
Definition: Sox.H:58
vector< sox_sample_t > outputBuffer
The output buffer for interleaving output data before writing.
Definition: Sox.H:101
Definition: Debug.H:112
#define SOX_CLOSE_FILE_ERROR
Error when libsox couldn&#39;t close the file.
Definition: Sox.H:33
double getFSOut(void)
Definition: Sox.H:324
int write(const Eigen::DenseBase< Derived > &audioData)
Definition: Sox.H:236
#define SOX_WRITE_OUT_CHANNEL_MISMATCH
Error when trying to write data and the channel count doesn&#39;t match.
Definition: Sox.H:39
#define SOX_EOF_OR_ERROR
Sox returned from a read or write either at the end of the file or in error.
Definition: Sox.H:35
#define SOX_READ_FILE_NOT_OPENED_ERROR
Error when the input file hasn&#39;t already been opened using Sox::openRead.
Definition: Sox.H:34
int read(Eigen::DenseBase< Derived > &audioData, int count=0)
Definition: Sox.H:135
virtual ~SoxDebug()
Destructor.
Definition: Sox.H:75
gtkIOStream: /tmp/gtkiostream/include/Sox.H Source File
GTK+ IOStream  Beta