From 760badbe051b46ce9e2ee82a2e941027fc57ed24 Mon Sep 17 00:00:00 2001 From: "Kevin M. Rosenberg" Date: Tue, 21 Jan 2003 01:58:32 +0000 Subject: [PATCH] r3816: *** empty log message *** --- wdq2wav.cpp | 443 ++++++++++++++++++++++++++++++++++++++++++++++++++++ wdq2wav.h | 66 ++++++++ 2 files changed, 509 insertions(+) create mode 100644 wdq2wav.cpp create mode 100644 wdq2wav.h diff --git a/wdq2wav.cpp b/wdq2wav.cpp new file mode 100644 index 0000000..bc0ae3b --- /dev/null +++ b/wdq2wav.cpp @@ -0,0 +1,443 @@ +/***************************************************************************** +** FILE IDENTIFICATION +** +** Name: wdq2wav.cpp +** Purpose: Converts a channel of WinDAQ file to .WAV format +** Programmer: Kevin Rosenberg +** Date Started: Jan 2003 +** +** Copyright (c) 2003 Kevin Rosenberg +** +** NOTES +** Quick & Dirty hack, but efficient and good error checking +** Allocates memory equal to the size of channel (2 * number of samples) +** +** BUGS +** Need to abstract error checking so it is not so redundant +** Need command line options for verbose and debug output +** Should comment the reading and writing of files to document the file formats +** +** $Id: wdq2wav.cpp,v 1.1 2003/01/21 01:58:32 kevin Exp $ +** +** 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 +** published by the Free Software Foundation. +** +** This program 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 should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +******************************************************************************/ + +#include + +static bool g_verbose = true; +static bool g_debug = true; + +void +error_msg (char *msg) +{ + fprintf (stderr, "%s\n",msg); +} + +void +usage () +{ + fprintf (stderr, "usage: wdq2wav \n"); +} + +bool wdq2wav (const char* wdq_fname, const int channel, const char *wav_fname); + +int +main (int argc, char *argv[]) +{ + if (argc != 4) { + usage(); + exit(1); + } + + char *wdq_fname = argv[1]; + char *channel_endptr; + int channel = (int) strtol (argv[2], &channel_endptr, 10); + char *wav_fname = argv[3]; + + if (*channel_endptr != 0) { + fprintf (stderr, "Error: Channel %s is not an integer\n", argv[2]); + usage(); + return(1); + } + + if (! wdq2wav (wdq_fname, channel, wav_fname)) + return 1; + + return 0; +} + +bool wdq2wav (const char* wdq_fname, const int channel, const char *wav_fname) +{ + WindaqFile wdq (wdq_fname); + + if (! wdq.ReadHeader()) { + fprintf (stderr, "Error reading header %s\n", wdq_fname); + return false; + } + if (g_verbose) { + printf ("Number of channels: %d\n", wdq.m_nChannels); + printf ("Number of Samples: %d\n", wdq.m_nSamples); + printf ("Sample Rate: %.1f\n", wdq.m_sample_rate); + } + + WindaqChannel wdq_channel (wdq, channel); + if (! wdq_channel.m_valid) { + error_msg ("Error reading data from channel"); + return false; + } + + if (g_verbose) { + printf ("Data Min: %f, Data Max: %f\n", + wdq_channel.m_min_raw_data, wdq_channel.m_max_raw_data); + } + + WavFile wav (wdq_channel, wav_fname); + + if (! wav.m_valid) { + error_msg ("Error extracting wav from channel"); + return false; + } + + if (! wav.WriteFile ()) { + error_msg ("Error writing file"); + return false; + } + + return true; +} + + +WindaqFile::WindaqFile (const char* fname) + : m_fd(0), m_nChannels(0), m_nSamples(0), m_sample_rate(0), m_valid(false), + m_strFile (fname) +{ +} + +WindaqFile::~WindaqFile () +{ + if (m_fd != 0) + close (m_fd); +} + +bool +WindaqFile::ReadHeader () +{ + unsigned short int tmp2; + unsigned int tmp4; + + m_valid = false; + if ((m_fd = open (m_strFile.c_str(), O_RDONLY)) == 0) + return false; + + lseek (0, 0, SEEK_SET); + if (read (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error reading file"); + return false; + } + m_nChannels = tmp2 & 0x1f; + m_sr_denom = (tmp2 & 0x7fff) >> 5; + m_sr_numer = (tmp2 & 0x8000) << 1; + + if (read (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error reading file"); + return false; + } + m_sr_numer |= tmp2; + m_sample_rate = (double) m_sr_numer / (double) (m_sr_denom * m_nChannels); + + if (read (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error reading file"); + return false; + } + m_channel_offset = tmp2 & 0xFF; + m_nBytes_channel_header = tmp2 >> 8; + + if (read (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error reading file"); + return false; + } + m_nHeader_bytes = tmp2; + + if (read (m_fd, &tmp4, sizeof(tmp4)) != sizeof(tmp4)) { + error_msg ("Error reading file"); + return false; + } + m_nData_bytes = tmp4; + m_nSamples = (m_nData_bytes / m_nChannels) / 2; + + // Verify Windaq signature + lseek (m_fd, m_nHeader_bytes - 2, SEEK_SET); + if (read (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error reading file"); + return false; + } + if (tmp2 != 0x8001) { + fprintf (stderr, "%s is not a WinDAQ file\n", m_strFile.c_str()); + return false; + } + + 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), + m_valid(false) +{ + if (wdq.m_valid) { + if (channel >= 1 && channel <= wdq.m_nChannels) { + m_valid = true; + read_channel_data(); + } else + fprintf (stderr, "Channel %d is invalid, valid range 1-%d\n", + channel, wdq.m_nChannels); + } +} + +WindaqChannel::~WindaqChannel () +{ + if (m_data) + delete m_data; +} + +bool +WindaqChannel::read_channel_data () +{ + unsigned short int tmp2; + unsigned int tmp4; + double float8; + + int fd = r_wdq.m_fd; + + if (! m_valid) + return false; + + m_data = new signed short int [r_wdq.m_nSamples * 2]; + + lseek (fd, r_wdq.m_channel_offset + 8 + + (m_channel - 1) * r_wdq.m_nBytes_channel_header, + SEEK_SET); + if (read (fd, &float8, sizeof(float8)) != sizeof(float8)) { + error_msg ("Error reading file"); + return false; + } + m_slope = float8; + if (read (fd, &float8, sizeof(float8)) != sizeof(float8)) { + error_msg ("Error reading file"); + return false; + } + m_intercept = float8; + + if (g_verbose) + printf ("Slope: %f, Intercept: %f\n", m_slope, m_intercept); + + char units[7]; + units[6] = 0; + if (read (fd, units, 6) != 6) { + error_msg ("Error reading file"); + return false; + } + m_units = units; + if (g_verbose) + printf ("Units: %s\n", units); + + unsigned int row_bytes = 2 * r_wdq.m_nChannels; + signed short int sample_row [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; + for (i = 0; i < r_wdq.m_nSamples; i++) { + if (read (fd, sample_row, row_bytes) != row_bytes) { + fprintf (stderr, "Error reading file at %d\n", i); + return false; + } + + signed short int value = *psample >> 2; + m_data[i] = value; + + if (i == 0) { + data_max = value; + data_min = value; + } else { + if (value > data_max) + data_max = value; + else if (value < data_min) + data_min = value; + } + } + + m_max_raw_data = data_max; + m_min_raw_data = data_min; + m_max_scaled_data = (m_slope * data_max) + m_intercept; + m_min_scaled_data = (m_slope * data_min) + m_intercept; + + return true; +} + + +WavFile::WavFile (WindaqChannel& wdq_channel, const char* fname) + : m_valid(false), m_data(0), m_nSamples(0), m_strFile(fname), m_fd(0) +{ + if (wdq_channel.m_valid) { + m_nSamples = wdq_channel.r_wdq.m_nSamples; + m_nChannels = 1; + m_nBitsPerSample = 16; + m_nBytesPerSample = 2; + m_rate = wdq_channel.r_wdq.m_sample_rate; + m_data = new signed short int [m_nSamples]; + + 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); + + if (g_debug) + printf ("data_scale: %f, data_offset: %f\n", data_scale, data_offset); + + signed short int* input = wdq_channel.m_data; + double slope = wdq_channel.m_slope; + double intercept = wdq_channel.m_intercept; + + 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; + m_data[i] = static_cast(value); + } + } + + m_valid = true; +} + + +WavFile::~WavFile () +{ + if (m_fd != 0) + close (m_fd); + + if (m_data != NULL) + delete m_data; +} + +bool +WavFile::WriteFile () +{ + unsigned short int tmp2; + unsigned int tmp4; + unsigned long data_bytes = m_nSamples * 2; + + if (! m_valid) + return false; + + if (m_fd == 0) + if ((m_fd = open (m_strFile.c_str(), O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == 0) { + fprintf (stderr, "Error opening output file %s\n", m_strFile.c_str()); + return false; + } + + lseek (m_fd, 0, SEEK_SET); + if (write (m_fd, "RIFF", 4) != 4) { + error_msg ("Error writing file"); + return false; + } + + /* Length of file post 8 byte header */ + tmp4 = 36 + data_bytes; + if (write (m_fd, &tmp4, sizeof(tmp4)) != sizeof(tmp4)) { + error_msg ("Error writing file"); + return false; + } + + if (write (m_fd, "WAVEfmt ", 8) != 8) { + error_msg ("Error writing file"); + return false; + } + tmp4 = 0x10; + if (write (m_fd, &tmp4, sizeof(tmp4)) != sizeof(tmp4)) { + error_msg ("Error writing file"); + + } + tmp2 = 1; + if (write (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error writing file"); + return false; + } + /* Number of channels */ + tmp2 = m_nChannels; + if (write (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error writing file"); + return false; + } + tmp4 = static_cast (m_rate + 0.5); + /* Sample rate */ + if (write (m_fd, &tmp4, sizeof(tmp4)) != sizeof(tmp4)) { + error_msg ("Error writing file"); + return false; + } + tmp4 = static_cast (m_rate * m_nBytesPerSample + 0.5); + /* Bytes per second */ + if (write (m_fd, &tmp4, sizeof(tmp4)) != sizeof(tmp4)) { + error_msg ("Error writing file"); + return false; + } + tmp2 = m_nBytesPerSample * m_nChannels; + /* Bytes per sample */ + if (write (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error writing file"); + return false; + } + tmp2 = m_nBitsPerSample; + /* Bits per sample */ + if (write (m_fd, &tmp2, sizeof(tmp2)) != sizeof(tmp2)) { + error_msg ("Error writing file"); + return false; + } + if (write (m_fd, "data", 4) != 4) { + error_msg ("Error writing file"); + return false; + } + tmp4 = data_bytes; + /* Data length */ + if (write (m_fd, &tmp4, sizeof(tmp4)) != sizeof(tmp4)) { + error_msg ("Error writing file"); + return false; + } + + long int i; + for (i = 0; i < m_nSamples; i++) { + signed short int stmp2 = m_data[i]; + if (write (m_fd, &stmp2, sizeof(stmp2)) != sizeof(stmp2)) { + error_msg ("Error writing file"); + return false; + } + } + + if (close (m_fd) < 0) + error_msg ("Error closing output file"); + + m_fd = 0; + return true; +} + + + + diff --git a/wdq2wav.h b/wdq2wav.h new file mode 100644 index 0000000..0c35164 --- /dev/null +++ b/wdq2wav.h @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include + +class WindaqFile +{ +public: + WindaqFile (const char* fname); + ~WindaqFile (); + bool ReadHeader(); + + std::string m_strFile; + bool m_valid; + int m_fd; + unsigned int m_nChannels; + unsigned int m_nSamples; + double m_sample_rate; + unsigned int m_sr_denom, m_sr_numer; + unsigned int m_nHeader_bytes, m_channel_offset, m_nBytes_channel_header; + unsigned int m_nData_bytes; +}; + +class WindaqChannel +{ +public: + bool m_valid; + unsigned int m_channel; + std::string m_units; + double m_slope; + double m_intercept; + signed short int *m_data; + WindaqFile& r_wdq; + signed short int m_min_raw_data; + signed short int m_max_raw_data; + double m_max_scaled_data; + double m_min_scaled_data; + + WindaqChannel (WindaqFile& wdq, const int channel); + ~WindaqChannel (); + + private: + bool read_channel_data(); +}; + + +class WavFile +{ + public: + std::string m_strFile; + int m_fd; + bool m_valid; + unsigned long int m_nSamples; + double m_rate; + unsigned int m_nChannels; + unsigned int m_nBitsPerSample; + unsigned int m_nBytesPerSample; + signed short int* m_data; + + WavFile (WindaqChannel& wdq_channel, const char* fname); + ~WavFile (); + + bool WriteFile (); +}; -- 2.34.1