X-Git-Url: http://git.kpe.io/?a=blobdiff_plain;f=wdq2wav.cpp;h=fcc782cb8634d458696aa293e1f74e89efde723f;hb=9ccb27ac548ef8ff8f23cec5574d6d9fb8494779;hp=392a108d71835413badb9c84afa4f56a66cd6133;hpb=8dc8c510c13b8ff5692f497004c818f2b6dfeb41;p=wdq2wav.git diff --git a/wdq2wav.cpp b/wdq2wav.cpp index 392a108..fcc782c 100644 --- a/wdq2wav.cpp +++ b/wdq2wav.cpp @@ -8,7 +8,7 @@ ** ** Copyright (c) 2003 Kevin Rosenberg ** -** $Id: wdq2wav.cpp,v 1.15 2003/02/12 06:10:19 kevin Exp $ +** $Id$ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -26,17 +26,37 @@ #include -const char* g_szIdStr = "$Id: wdq2wav.cpp,v 1.15 2003/02/12 06:10:19 kevin Exp $"; +const char* g_szIdStr = "$Id$"; bool g_quiet = false; bool g_verbose = false; bool g_debug = false; +bool g_ignore_zero = false; +bool g_dont_demean = false; + +#ifdef WIN32 +#define lseek _lseek +#define close _close +#define open _open +#define read _read +#define write _write +#define O_BINARY _O_BINARY +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDRW +#define O_TRUNC _O_TRUNC +#define O_CREAT _O_CREAT +const int g_fileMode = _S_IWRITE | _S_IREAD; +struct fpos_t std::_Fpz = {0,0}; +#else +const int g_fileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // Define as NULL for non-Windows platforms #ifndef O_BINARY #define O_BINARY 0 #endif - +#endif + void error_msg (const char *msg) @@ -59,14 +79,21 @@ info_msg_sans_newline (const char* msg) const char* fileBasename (const char* filename) { - const char* p = strrchr (filename, '/'); - return (p ? p + 1 : filename); + const char* pslash = strrchr (filename, '/'); + const char* pbackslash = strrchr (filename, '\\'); + const char* p = filename; + if (pbackslash && (! pslash || pbackslash >= pslash)) + p = pbackslash+1; + else if (pslash && (! pbackslash || pslash >= pbackslash)) + p = pslash+1; + + return p; } char * str_rm_tail (char *str, const char* const charlist) { - int i; + size_t i; for (i = strlen(str) - 1; i >= 0; i--) if (strchr (charlist, str[i]) != NULL) @@ -89,12 +116,14 @@ usage (const char* progname) { std::cout << "usage: " << fileBasename (progname) << " [OPTIONS] \n"; std::cout << "OPTIONS\n"; - std::cout << " -p Play channel through audio system\n"; - std::cout << " -q Supress all messages\n"; - std::cout << " -v Verbose mode\n"; - std::cout << " -d Debug mode\n"; - std::cout << " -r Print program version\n"; - std::cout << " -h Print this help message\n"; + std::cout << " -p Play channel through audio system\n"; + std::cout << " -q Supress all messages\n"; + std::cout << " -z Scale output without preserving zero point\n"; + std::cout << " -m Do not demean the data (don't subtract the mean value from each sample)\n"; + std::cout << " -v Verbose mode\n"; + std::cout << " -d Debug mode\n"; + std::cout << " -r Print program version and exit\n"; + std::cout << " -h Print this help message\n"; } @@ -106,14 +135,21 @@ main (int argc, char *argv[]) const char* progname = argv[0]; - while ((c = getopt (argc, argv, "rqvdph")) != -1) { + while ((c = getopt (argc, argv, "rqvzmdph")) != -1) { switch (c) { case 'r': std::cout << "Version " << g_szIdStr << std::endl; + exit(0); break; case 'q': g_quiet = true; break; + case 'm': + g_dont_demean = true; + break; + case 'z': + g_ignore_zero = true; + break; case 'v': g_verbose = true; break; @@ -132,6 +168,10 @@ main (int argc, char *argv[]) return (1); } } + + if (g_verbose || g_debug) + std::cout << "Version " << g_szIdStr << std::endl; + argc -= optind; argv += optind; if (argc > 3) { @@ -199,8 +239,15 @@ wdq2wav (const char* wdq_fname, const int channel, const char *wav_fname, bool p } if (! g_quiet || g_verbose || g_debug) { std::ostringstream os1; - os1 << "File " << wdq_fname; + os1 << "File: " << wdq_fname; info_msg (os1.str().c_str()); + std::ostringstream os; + os << "Legacy Format: "; + if (wdq.m_bLegacy_format) + os << "Yes"; + else + os << "No"; + info_msg(os.str().c_str()); std::ostringstream os2; time_t time = wdq.m_time_acq_start; struct tm* tm = gmtime (&time); @@ -236,6 +283,7 @@ wdq2wav (const char* wdq_fname, const int channel, const char *wav_fname, bool p ", maximum: " << wdq_channel.m_max_raw_data; info_msg (os3.str().c_str()); } + if (g_debug) { std::ostringstream os4; os4 << " Scaled minimum: " << wdq_channel.m_min_scaled_data << @@ -267,7 +315,7 @@ wdq2wav (const char* wdq_fname, const int channel, const char *wav_fname, bool p WindaqFile::WindaqFile (const char* fname) - : m_fd(0), m_nChannels(0), m_nSamples(0), m_sample_rate(0), m_valid(false), + : m_valid(false), m_fd(0), m_nChannels(0), m_nSamples(0), m_sample_rate(0), m_strFile (fname) { } @@ -306,6 +354,25 @@ bool read_int4 (int fd, unsigned int& n) return true; } +bool read_float8 (int fd, double& f) +{ + unsigned char buf[8]; + if (read (fd, &buf, 8) != 8) + return false; + +#if WORDS_BIG_ENDIAN + unsigned char c; + c = buf[0]; buf[0] = buf[7]; buf[7] = c; + c = buf[1]; buf[1] = buf[6]; buf[6] = c; + c = buf[2]; buf[2] = buf[5]; buf[5] = c; + c = buf[3]; buf[3] = buf[4]; buf[4] = c; +#endif + + f = *(reinterpret_cast(buf)); + + return true; +} + bool WindaqFile::ReadHeader () { @@ -321,16 +388,19 @@ WindaqFile::ReadHeader () if (! read_int2 (m_fd, tmp2)) return false; - m_nChannels = tmp2 & 0x1f; m_sr_denom = (tmp2 & 0x7fff) >> 5; m_sr_numer = (tmp2 & 0x8000) << 1; - + short unsigned int byte1 = (tmp2 & 0xFF00) >> 8; + short unsigned int byte2 = tmp2 & 0xFF; + if (byte1 == 0 || byte1 == 1) { + m_bLegacy_format = false; + } else { + m_bLegacy_format = true; + } if (! read_int2 (m_fd, tmp2)) return false; m_sr_numer |= tmp2; - m_sample_rate = (double) m_sr_numer / (double) (m_sr_denom * m_nChannels); - if (! read_int2 (m_fd, tmp2)) return false; @@ -339,12 +409,27 @@ WindaqFile::ReadHeader () if (! read_int2 (m_fd, m_nHeader_bytes)) return false; - + + m_nMaxChannels = (m_nHeader_bytes - 112) / 36; + if (m_nMaxChannels >= 144) + m_nChannels = byte2 & 0xFF; + else + m_nChannels = byte2 & 0x1F; + if (! read_int4 (m_fd, m_nData_bytes)) return false; m_nSamples = (m_nData_bytes / m_nChannels) / 2; + lseek (m_fd, 28, SEEK_SET); + if (! read_float8 (m_fd, m_time_between_channel_samples)) + return false; + + if (m_bLegacy_format) + m_sample_rate = (double) m_sr_numer / (double) (m_sr_denom * m_nChannels); + else + m_sample_rate = (double) m_nChannels / m_time_between_channel_samples; + lseek (m_fd, 36, SEEK_SET); if (! read_int4 (m_fd, m_time_acq_start)) return false; @@ -366,7 +451,6 @@ WindaqFile::ReadHeader () m_valid = true; return true; } - WindaqChannel::WindaqChannel (WindaqFile& wdq, const int channel) : r_wdq(wdq), m_data(0), m_slope(0), m_intercept (0), m_channel(channel), @@ -391,31 +475,9 @@ WindaqChannel::~WindaqChannel () delete m_data; } -bool get_float8 (int fd, double& f) -{ - unsigned char buf[8]; - if (read (fd, &buf, 8) != 8) - return false; - -#if WORDS_BIG_ENDIAN - unsigned char c; - c = buf[0]; buf[0] = buf[7]; buf[7] = c; - c = buf[1]; buf[1] = buf[6]; buf[6] = c; - c = buf[2]; buf[2] = buf[5]; buf[5] = c; - c = buf[3]; buf[3] = buf[4]; buf[4] = c; -#endif - - f = *(reinterpret_cast(buf)); - - return true; -} - bool WindaqChannel::read_channel_data () { - unsigned short int tmp2; - unsigned int tmp4; - int fd = r_wdq.m_fd; m_data = new signed short int [r_wdq.m_nSamples * 2]; @@ -423,10 +485,10 @@ WindaqChannel::read_channel_data () lseek (fd, r_wdq.m_channel_offset + 8 + (m_channel - 1) * r_wdq.m_nBytes_channel_header, SEEK_SET); - if (! get_float8 (fd, m_slope)) + if (! read_float8 (fd, m_slope)) return false; - if (! get_float8 (fd, m_intercept)) + if (! read_float8 (fd, m_intercept)) return false; char units[7]; @@ -437,19 +499,22 @@ WindaqChannel::read_channel_data () } m_units = units; - unsigned int row_bytes = 2 * r_wdq.m_nChannels; - signed short int sample_row [row_bytes]; + long int row_bytes = 2 * r_wdq.m_nChannels; + + signed short int *sample_row = new signed short int [row_bytes]; signed short int* psample = &sample_row[m_channel - 1]; lseek (fd, r_wdq.m_nHeader_bytes, SEEK_SET); - long int i; - signed short int data_max, data_min; + unsigned long int i; + signed short int data_max = 0, data_min = 0; + double total_data = 0; for (i = 0; i < r_wdq.m_nSamples; i++) { if (read (fd, sample_row, row_bytes) != row_bytes) { std::ostringstream os; os << "Error reading file at " << i; error_msg (os.str().c_str()); + delete sample_row; return false; } signed short int v = *psample; @@ -461,6 +526,7 @@ WindaqChannel::read_channel_data () signed short int value = v >> 2; m_data[i] = value; + total_data += value; if (i == 0) { data_max = value; @@ -478,6 +544,17 @@ WindaqChannel::read_channel_data () m_max_scaled_data = (m_slope * data_max) + m_intercept; m_min_scaled_data = (m_slope * data_min) + m_intercept; + if (! g_dont_demean) { + double dmean = total_data / static_cast(r_wdq.m_nSamples); + int mean = nearest(dmean); + std::cout << "Removing mean: " << (dmean * m_slope) + m_intercept << + " " << m_units << std::endl; + + for (i = 0; i < r_wdq.m_nSamples; i++) + m_data[i] -= mean; + } + + delete sample_row; return true; } @@ -491,12 +568,20 @@ WavFile::WavFile (WindaqChannel& wdq_channel, const char* fname) m_nBitsPerSample = 16; m_nBytesPerSample = 2; m_rate = wdq_channel.r_wdq.m_sample_rate; - - double data_offset = -wdq_channel.m_min_scaled_data; - double data_scale = 0.; - if (wdq_channel.m_max_scaled_data != wdq_channel.m_min_scaled_data) - data_scale = 65535. / (wdq_channel.m_max_scaled_data - - wdq_channel.m_min_scaled_data); + + double data_offset = 0, data_scale = 0; + if (g_ignore_zero) { + data_offset = -wdq_channel.m_min_scaled_data; + if (wdq_channel.m_max_scaled_data != wdq_channel.m_min_scaled_data) + data_scale = 65535. / (wdq_channel.m_max_scaled_data - + wdq_channel.m_min_scaled_data); + } else { + double max_value = fabs(wdq_channel.m_max_scaled_data); + if (fabs (wdq_channel.m_min_scaled_data) > max_value) + max_value = fabs (wdq_channel.m_min_scaled_data); + if (max_value != 0.) + data_scale = 32767. / max_value; + } if (g_debug) { std::ostringstream os; @@ -519,12 +604,17 @@ WavFile::WavFile (WindaqChannel& wdq_channel, const char* fname) if (! fill_header ()) return; - long int i; + unsigned long int i; for (i = 0; i < m_nSamples; i++) { double value = input[i]; value = (slope * value) + intercept; - value = (value + data_offset) * data_scale; - value += 0.5 - 32768; + if (g_ignore_zero) { + value = (value + data_offset) * data_scale; + value += 0.5 - 32768; + } else { + value = value * data_scale; + } + signed short int v = static_cast(value); #if WORDS_BIG_ENDIAN unsigned char* p = reinterpret_cast(&v); @@ -606,15 +696,11 @@ WavFile::fill_header () bool WavFile::WriteFile () { - unsigned short int tmp2; - unsigned int tmp4; - if (! m_valid) return false; if (m_fd == 0) - if ((m_fd = open (m_strFile.c_str(), O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == 0) { + if ((m_fd = open (m_strFile.c_str(), O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, g_fileMode)) == 0) { std::ostringstream os; os << "Error opening output file " << m_strFile.c_str(); error_msg (os.str().c_str()); @@ -665,7 +751,7 @@ WavFile::Play () close(fd); return false; } - int channels = m_nChannels; + unsigned int channels = m_nChannels; if (ioctl (fd, SNDCTL_DSP_CHANNELS, &format) == -1) { error_msg ("Error setting number of channels"); close(fd); return false; @@ -675,7 +761,7 @@ WavFile::Play () close(fd); return false; } - int speed = static_cast(m_rate + 0.5); + unsigned int speed = static_cast(m_rate + 0.5); if (ioctl (fd, SNDCTL_DSP_SPEED, &speed) == -1) { error_msg ("Error setting sample rate"); close(fd); return false;