mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-12-25 20:33:08 -05:00
Class to read and write WAV format files
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6337 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
92e1f70b8f
commit
58aacc590e
379
Audio/WavFile.cpp
Normal file
379
Audio/WavFile.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
#include "WavFile.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <numeric>
|
||||
|
||||
#include <qendian.h>
|
||||
#include <QAudioFormat>
|
||||
#include <QDebug>
|
||||
|
||||
#include "moc_WavFile.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Desc
|
||||
{
|
||||
Desc () = default;
|
||||
explicit Desc (char const * id, quint32 size = 0)
|
||||
: size_ {size}
|
||||
{
|
||||
set (id);
|
||||
}
|
||||
|
||||
void set (char const * id = nullptr)
|
||||
{
|
||||
if (id)
|
||||
{
|
||||
auto len = std::min (4u, strlen (id));
|
||||
memcpy (id_.data (), id, len);
|
||||
memset (id_.data () + len, ' ', 4u - len);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (id_.data (), "JUNK", 4);
|
||||
}
|
||||
}
|
||||
|
||||
void set (char const * id, quint32 size)
|
||||
{
|
||||
set (id);
|
||||
size_ = size;
|
||||
}
|
||||
|
||||
char * operator & () {return reinterpret_cast<char *> (this);}
|
||||
char const * operator & () const {return &*this;}
|
||||
|
||||
std::array<char, 4> id_;
|
||||
quint32 size_;
|
||||
};
|
||||
|
||||
struct FormatChunk
|
||||
{
|
||||
quint16 audio_format;
|
||||
quint16 num_channels;
|
||||
quint32 sample_rate;
|
||||
quint32 byte_rate;
|
||||
quint16 block_align;
|
||||
quint16 bits_per_sample;
|
||||
};
|
||||
}
|
||||
|
||||
WavFile::WavFile (QAudioFormat const& format, QObject * parent)
|
||||
: QIODevice {parent}
|
||||
, header_dirty_ {true}
|
||||
, format_ {format}
|
||||
, header_length_ {-1}
|
||||
{
|
||||
}
|
||||
|
||||
WavFile::WavFile (QAudioFormat const& format, QString const& name, QObject * parent)
|
||||
: QIODevice {parent}
|
||||
, header_dirty_ {true}
|
||||
, format_ {format}
|
||||
, file_ {name}
|
||||
, header_length_ {-1}
|
||||
{
|
||||
}
|
||||
|
||||
WavFile::WavFile (QAudioFormat const& format, QString const& name
|
||||
, InfoDictionary const& dictionay, QObject * parent)
|
||||
: QIODevice {parent}
|
||||
, header_dirty_ {true}
|
||||
, format_ {format}
|
||||
, file_ {name}
|
||||
, header_length_ {-1}
|
||||
, info_dictionary_ {dictionay}
|
||||
{
|
||||
}
|
||||
|
||||
WavFile::~WavFile ()
|
||||
{
|
||||
QIODevice::close ();
|
||||
if (header_dirty_) update_header ();
|
||||
file_.close ();
|
||||
}
|
||||
|
||||
bool WavFile::open (OpenMode mode)
|
||||
{
|
||||
bool result {false};
|
||||
if (!(mode & ReadOnly)) return result;
|
||||
if (!(mode & WriteOnly))
|
||||
{
|
||||
result = file_.open (mode & ~Text) && read_header ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((result = file_.open (mode & ~Text)))
|
||||
{
|
||||
if (!(result = read_header () || write_header (format_)))
|
||||
{
|
||||
file_.close ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result ? initialize (mode) : false;
|
||||
}
|
||||
|
||||
bool WavFile::open(FILE * fh, OpenMode mode, FileHandleFlags flags)
|
||||
{
|
||||
bool result {false};
|
||||
if (!(mode & ReadOnly)) return result;
|
||||
if (!mode & WriteOnly)
|
||||
{
|
||||
result = file_.open (fh, mode & ~Text, flags) && read_header ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((result = file_.open (fh, mode & ~Text, flags)))
|
||||
{
|
||||
if (!(result = read_header () || write_header (format_)))
|
||||
{
|
||||
file_.close ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result ? initialize (mode) : false;
|
||||
}
|
||||
|
||||
bool WavFile::open (int fd, OpenMode mode, FileHandleFlags flags)
|
||||
{
|
||||
bool result {false};
|
||||
if (!(mode & ReadOnly)) return result;
|
||||
if (!(mode & WriteOnly))
|
||||
{
|
||||
result = file_.open (fd, mode & ~Text, flags) && read_header ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((result = file_.open (fd, mode & ~Text, flags)))
|
||||
{
|
||||
if (!(result = read_header () || write_header (format_)))
|
||||
{
|
||||
file_.close ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result ? initialize (mode) : false;
|
||||
}
|
||||
|
||||
bool WavFile::initialize (OpenMode mode)
|
||||
{
|
||||
bool result {QIODevice::open (mode | Unbuffered)};
|
||||
if (result && (mode & Append))
|
||||
{
|
||||
result = file_.seek (file_.size ());
|
||||
if (result) result = seek (file_.size () - header_length_);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = seek (0);
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
file_.close ();
|
||||
close ();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WavFile::read_header ()
|
||||
{
|
||||
if (!file_.seek (0)) return false;
|
||||
Desc outer_desc;
|
||||
auto outer_offset = file_.pos ();
|
||||
quint32 outer_size {0};
|
||||
bool be {false};
|
||||
while (outer_offset < sizeof outer_desc + outer_desc.size_ - 1) // allow for uncounted pad
|
||||
{
|
||||
if (file_.read (&outer_desc, sizeof outer_desc) != sizeof outer_desc) return false;
|
||||
be = !memcmp (&outer_desc.id_, "RIFX", 4);
|
||||
outer_size = be ? qFromBigEndian<quint32> (outer_desc.size_) : qFromLittleEndian<quint32> (outer_desc.size_);
|
||||
if (!memcmp (&outer_desc.id_, "RIFF", 4) || be)
|
||||
{
|
||||
// RIFF or RIFX
|
||||
char riff_item[4];
|
||||
if (file_.read (riff_item, sizeof riff_item) != sizeof riff_item) return false;
|
||||
if (!memcmp (riff_item, "WAVE", 4))
|
||||
{
|
||||
// WAVE
|
||||
Desc wave_desc;
|
||||
auto wave_offset = file_.pos ();
|
||||
quint32 wave_size {0};
|
||||
while (wave_offset < outer_offset + sizeof outer_desc + outer_size - 1)
|
||||
{
|
||||
if (file_.read (&wave_desc, sizeof wave_desc) != sizeof wave_desc) return false;
|
||||
wave_size = be ? qFromBigEndian<quint32> (wave_desc.size_) : qFromLittleEndian<quint32> (wave_desc.size_);
|
||||
if (!memcmp (&wave_desc.id_, "fmt ", 4))
|
||||
{
|
||||
FormatChunk fmt;
|
||||
if (file_.read (reinterpret_cast<char *> (&fmt), sizeof fmt) != sizeof fmt) return false;
|
||||
auto audio_format = be ? qFromBigEndian<quint16> (fmt.audio_format) : qFromLittleEndian<quint16> (fmt.audio_format);
|
||||
if (audio_format != 0 && audio_format != 1) return false; // not PCM nor undefined
|
||||
format_.setByteOrder (be ? QAudioFormat::BigEndian : QAudioFormat::LittleEndian);
|
||||
format_.setChannelCount (be ? qFromBigEndian<quint16> (fmt.num_channels) : qFromLittleEndian<quint16> (fmt.num_channels));
|
||||
format_.setCodec ("audio/pcm");
|
||||
format_.setSampleRate (be ? qFromBigEndian<quint32> (fmt.sample_rate) : qFromLittleEndian<quint32> (fmt.sample_rate));
|
||||
int bits_per_sample {be ? qFromBigEndian<quint16> (fmt.bits_per_sample) : qFromLittleEndian<quint16> (fmt.bits_per_sample)};
|
||||
format_.setSampleSize (bits_per_sample);
|
||||
format_.setSampleType (8 == bits_per_sample ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
|
||||
}
|
||||
else if (!memcmp (&wave_desc.id_, "data", 4))
|
||||
{
|
||||
header_length_ = file_.pos ();
|
||||
return true; // done
|
||||
}
|
||||
else if (!memcmp (&wave_desc.id_, "LIST", 4))
|
||||
{
|
||||
char list_type[4];
|
||||
if (file_.read (list_type, sizeof list_type) != sizeof list_type) return false;
|
||||
if (!memcmp (list_type, "INFO", 4))
|
||||
{
|
||||
Desc info_desc;
|
||||
auto info_offset = file_.pos ();
|
||||
quint32 info_size {0};
|
||||
while (info_offset < wave_offset + sizeof wave_desc + wave_size - 1)
|
||||
{
|
||||
if (file_.read (&info_desc, sizeof info_desc) != sizeof info_desc) return false;
|
||||
info_size = be ? qFromBigEndian<quint32> (info_desc.size_) : qFromLittleEndian<quint32> (info_desc.size_);
|
||||
info_dictionary_[info_desc.id_] = file_.read (info_size);
|
||||
if (!file_.seek (info_offset + sizeof info_desc + (info_size + 1) / 2 * 2)) return false;;
|
||||
info_offset = file_.pos ();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file_.seek (wave_offset + sizeof wave_desc + (wave_size + 1) / 2 * 2)) return false;
|
||||
wave_offset = file_.pos ();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file_.seek (outer_offset + sizeof outer_desc + (outer_size + 1) / 2 * 2)) return false;
|
||||
outer_offset = file_.pos ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WavFile::write_header (QAudioFormat format)
|
||||
{
|
||||
if ("audio/pcm" != format.codec ()) return false;
|
||||
if (!file_.seek (0)) return false;
|
||||
header_length_ = 0;
|
||||
bool be {QAudioFormat::BigEndian == format_.byteOrder ()};
|
||||
Desc desc {be ? "RIFX" : "RIFF"};
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
header_dirty_ = true;
|
||||
if (file_.write ("WAVE", 4) != 4) return false;
|
||||
FormatChunk fmt;
|
||||
if (be)
|
||||
{
|
||||
fmt.audio_format = qToBigEndian<quint16> (1); // PCM
|
||||
fmt.num_channels = qToBigEndian<quint16> (format.channelCount ());
|
||||
fmt.sample_rate = qToBigEndian<quint32> (format.sampleRate ());
|
||||
fmt.byte_rate = qToBigEndian<quint32> (format.bytesForDuration (1000));
|
||||
fmt.block_align = qToBigEndian<quint16> (format.bytesPerFrame ());
|
||||
fmt.bits_per_sample = qToBigEndian<quint16> (format.sampleSize ());
|
||||
desc.set ("fmt", qToBigEndian<quint32> (sizeof fmt));
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt.audio_format = qToLittleEndian<quint16> (1); // PCM
|
||||
fmt.num_channels = qToLittleEndian<quint16> (format.channelCount ());
|
||||
fmt.sample_rate = qToLittleEndian<quint32> (format.sampleRate ());
|
||||
fmt.byte_rate = qToLittleEndian<quint32> (format.bytesForDuration (1000));
|
||||
fmt.block_align = qToLittleEndian<quint16> (format.bytesPerFrame ());
|
||||
fmt.bits_per_sample = qToLittleEndian<quint16> (format.sampleSize ());
|
||||
desc.set ("fmt", qToLittleEndian<quint32> (sizeof fmt));
|
||||
}
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
if (file_.write (reinterpret_cast<char const *> (&fmt), sizeof fmt) != sizeof fmt) return false;
|
||||
if (info_dictionary_.size ())
|
||||
{
|
||||
auto position = file_.pos ();
|
||||
desc.set ("LIST");
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
if (file_.write ("INFO", 4) != 4) return false;
|
||||
for (auto iter = info_dictionary_.constBegin ()
|
||||
; iter != info_dictionary_.constEnd (); ++iter)
|
||||
{
|
||||
auto value = iter.value ();
|
||||
auto len = value.size () + 1;
|
||||
auto padded_len = (len + 1) / 2 * 2;
|
||||
if (padded_len > value.size ()) value.append ('\0');
|
||||
desc.set (iter.key ().data (), be ? qToBigEndian<quint32> (len) : qToLittleEndian<quint32> (len));
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
if (file_.write (value.constData (), padded_len) != padded_len) return false;
|
||||
}
|
||||
auto end_position = file_.pos ();
|
||||
if (!file_.seek (position)) return false;
|
||||
if (file_.peek (&desc, sizeof desc) != sizeof desc) return false;
|
||||
Q_ASSERT (!memcmp (desc.id_.data (), "LIST", 4));
|
||||
auto size = end_position - position - sizeof desc;
|
||||
desc.size_ = be ? qToBigEndian<quint32> (size) : qToLittleEndian<quint32> (size);
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
if (!file_.seek (end_position)) return false;
|
||||
}
|
||||
auto size = file_.size () - file_.pos () - sizeof desc;
|
||||
desc.set ("data", be ? qToBigEndian<quint32> (size) : qToLittleEndian<quint32> (size));
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
header_length_ = file_.pos ();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WavFile::update_header ()
|
||||
{
|
||||
if (header_length_ < 0 || !(file_.openMode () & WriteOnly)) return false;
|
||||
auto position = file_.pos ();
|
||||
bool be {QAudioFormat::BigEndian == format_.byteOrder ()};
|
||||
Desc desc;
|
||||
if (!file_.seek (header_length_ - sizeof desc)) return false;
|
||||
if (file_.peek (&desc, sizeof desc) != sizeof desc) return false;
|
||||
Q_ASSERT (!memcmp (desc.id_.data (), "data", 4));
|
||||
auto size = file_.size () - header_length_;
|
||||
desc.size_ = be ? qToBigEndian<quint32> (size) : qToLittleEndian<quint32> (size);
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
if (!file_.seek (0)) return false;
|
||||
if (file_.peek (&desc, sizeof desc) != sizeof desc) return false;
|
||||
Q_ASSERT (!memcmp (desc.id_.data (), "RIFF", 4) || !memcmp (desc.id_.data (), "RIFX", 4));
|
||||
size = file_.size () - sizeof desc;
|
||||
desc.size_ = be ? qToBigEndian<quint32> (size) : qToLittleEndian<quint32> (size);
|
||||
if (file_.write (&desc, sizeof desc) != sizeof desc) return false;
|
||||
return file_.seek (position);
|
||||
}
|
||||
|
||||
bool WavFile::reset ()
|
||||
{
|
||||
file_.seek (header_length_);
|
||||
return QIODevice::reset ();
|
||||
}
|
||||
|
||||
bool WavFile::isSequential () const
|
||||
{
|
||||
return file_.isSequential ();
|
||||
}
|
||||
|
||||
void WavFile::close ()
|
||||
{
|
||||
QIODevice::close ();
|
||||
file_.close ();
|
||||
}
|
||||
|
||||
bool WavFile::seek (qint64 pos)
|
||||
{
|
||||
if (pos < 0) return false;
|
||||
QIODevice::seek (pos);
|
||||
return file_.seek (pos + header_length_);
|
||||
}
|
||||
|
||||
qint64 WavFile::readData (char * data, qint64 max_size)
|
||||
{
|
||||
return file_.read (data, max_size);
|
||||
}
|
||||
|
||||
qint64 WavFile::writeData (char const* data, qint64 max_size)
|
||||
{
|
||||
auto bytes = file_.write (data, max_size);
|
||||
if (bytes > 0 && atEnd ()) header_dirty_ = true;
|
||||
return bytes;
|
||||
}
|
83
Audio/WavFile.hpp
Normal file
83
Audio/WavFile.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
#ifndef WSV_FILE_HPP__
|
||||
#define WSV_FILE_HPP__
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <QFile>
|
||||
#include <QAudioFormat>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
|
||||
class QObject;
|
||||
class QString;
|
||||
|
||||
class WavFile final
|
||||
: public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using FileHandleFlags = QFile::FileHandleFlags;
|
||||
using Permissions = QFile::Permissions;
|
||||
using FileError = QFile::FileError;
|
||||
using MemoryMapFlags = QFile::MemoryMapFlags;
|
||||
using InfoDictionary = QMap<std::array<char, 4>, QByteArray>;
|
||||
|
||||
explicit WavFile (QAudioFormat const&, QObject * parent = nullptr);
|
||||
explicit WavFile (QAudioFormat const&, QString const& name, QObject * parent = nullptr);
|
||||
explicit WavFile (QAudioFormat const&, QString const& name, InfoDictionary const&, QObject * parent = nullptr);
|
||||
~WavFile ();
|
||||
QAudioFormat const& format () const {return format_;}
|
||||
qint64 header_length () const {return header_length_;}
|
||||
InfoDictionary const& info () const {return info_dictionary_;}
|
||||
|
||||
// Emulate QFile interface
|
||||
bool open (OpenMode) override;
|
||||
bool open (FILE *, OpenMode, FileHandleFlags = QFile::DontCloseHandle);
|
||||
bool open (int fd, OpenMode, FileHandleFlags = QFile::DontCloseHandle);
|
||||
bool copy (QString const& new_name);
|
||||
|
||||
// forward to QFile
|
||||
bool exists () const {return file_.exists ();}
|
||||
bool link (QString const& link_name) {return file_.link (link_name);}
|
||||
bool remove () {return file_.remove ();}
|
||||
bool rename (QString const& new_name) {return file_.rename (new_name);}
|
||||
void setFileName (QString const& name) {file_.setFileName (name);}
|
||||
QString symLinkTarget () const {return file_.symLinkTarget ();}
|
||||
QString fileName () const {return file_.fileName ();}
|
||||
Permissions permissions () const {return file_.permissions ();}
|
||||
bool resize (qint64 new_size) {return file_.resize (new_size + header_length_);}
|
||||
bool setPermissions (Permissions permissions) {return file_.setPermissions (permissions);}
|
||||
FileError error () const {return file_.error ();}
|
||||
bool flush () {return file_.flush ();}
|
||||
int handle () const {return file_.handle ();}
|
||||
uchar * map (qint64 offset, qint64 size, MemoryMapFlags flags = QFile::NoOptions)
|
||||
{
|
||||
return file_.map (offset, size, flags);
|
||||
}
|
||||
bool unmap (uchar * address) {return file_.unmap (address);}
|
||||
void unsetError () {file_.unsetError ();}
|
||||
|
||||
// QIODevice overrides
|
||||
bool isSequential () const override;
|
||||
bool reset () override;
|
||||
bool seek (qint64) override;
|
||||
void close () override;
|
||||
|
||||
protected:
|
||||
qint64 readData (char * data, qint64 max_size) override;
|
||||
qint64 writeData (char const* data, qint64 max_size) override;
|
||||
|
||||
private:
|
||||
bool initialize (OpenMode);
|
||||
bool read_header ();
|
||||
bool write_header (QAudioFormat);
|
||||
bool update_header ();
|
||||
|
||||
bool header_dirty_;
|
||||
QAudioFormat format_;
|
||||
QFile file_;
|
||||
qint64 header_length_;
|
||||
InfoDictionary info_dictionary_;
|
||||
};
|
||||
|
||||
#endif
|
@ -217,6 +217,10 @@ set (wsjt_qt_CXXSRCS
|
||||
SampleDownloader/RemoteFile.cpp
|
||||
)
|
||||
|
||||
set (wsjt_qtmm_CXXSRCS
|
||||
Audio/WavFile.cpp
|
||||
)
|
||||
|
||||
set (jt9_CXXSRCS
|
||||
lib/ipcomm.cpp
|
||||
)
|
||||
@ -486,6 +490,7 @@ set (UDPDaemon_CXXSRCS
|
||||
set (all_CXXSRCS
|
||||
${wsjt_CXXSRCS}
|
||||
${wsjt_qt_CXXSRCS}
|
||||
${wsjt_qtmm_CXXSRCS}
|
||||
${jt9_CXXSRCS}
|
||||
${wsjtx_CXXSRCS}
|
||||
${message_aggregator_CXXSRCS}
|
||||
@ -890,8 +895,10 @@ add_library (wsjt_cxx STATIC ${wsjt_CSRCS} ${wsjt_CXXSRCS})
|
||||
|
||||
# build an OpenMP variant of the Fortran library routines
|
||||
add_library (wsjt_fort STATIC ${wsjt_FSRCS})
|
||||
target_link_libraries (wsjt_fort ${FFTW3_LIBRARIES})
|
||||
if (${OPENMP_FOUND} OR APPLE)
|
||||
add_library (wsjt_fort_omp STATIC ${wsjt_FSRCS})
|
||||
target_link_libraries (wsjt_fort_omp ${FFTW3_LIBRARIES})
|
||||
set_target_properties (wsjt_fort_omp
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${OpenMP_C_FLAGS}"
|
||||
@ -917,11 +924,14 @@ if (WIN32)
|
||||
target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
|
||||
endif (WIN32)
|
||||
|
||||
add_library (wsjt_qtmm STATIC ${wsjt_qtmm_CXXSRCS} ${wsjt_qtmm_GENUISRCS})
|
||||
target_link_libraries (wsjt_qtmm Qt5::Multimedia)
|
||||
|
||||
add_executable (jt4sim lib/jt4sim.f90 wsjtx.rc)
|
||||
target_link_libraries (jt4sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (jt65sim lib/jt65sim.f90 wsjtx.rc)
|
||||
target_link_libraries (jt65sim wsjt_fort wsjt_cxx ${FFTW3_LIBRARIES})
|
||||
target_link_libraries (jt65sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (jt9sim lib/jt9sim.f90 wsjtx.rc)
|
||||
target_link_libraries (jt9sim wsjt_fort wsjt_cxx)
|
||||
@ -942,7 +952,7 @@ add_executable (jt4code lib/jt4code.f90 wsjtx.rc)
|
||||
target_link_libraries (jt4code wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (jt65 lib/jt65.f90 lib/jt65_test.f90 wsjtx.rc)
|
||||
target_link_libraries (jt65 wsjt_fort wsjt_cxx ${FFTW3_LIBRARIES})
|
||||
target_link_libraries (jt65 wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (jt9 lib/jt9.f90 lib/jt9a.f90 ${jt9_CXXSRCS} wsjtx.rc)
|
||||
if (${OPENMP_FOUND} OR APPLE)
|
||||
@ -964,9 +974,9 @@ if (${OPENMP_FOUND} OR APPLE)
|
||||
Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/fortran_modules_omp
|
||||
)
|
||||
endif (APPLE)
|
||||
target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx ${FFTW3_LIBRARIES} Qt5::Core)
|
||||
target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx Qt5::Core)
|
||||
else (${OPENMP_FOUND} OR APPLE)
|
||||
target_link_libraries (jt9 wsjt_fort wsjt_cxx ${FFTW3_LIBRARIES} Qt5::Core)
|
||||
target_link_libraries (jt9 wsjt_fort wsjt_cxx Qt5::Core)
|
||||
endif (${OPENMP_FOUND} OR APPLE)
|
||||
|
||||
# build the main application
|
||||
@ -993,7 +1003,7 @@ set_target_properties (wsjtx PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
)
|
||||
|
||||
target_link_libraries (wsjtx wsjt_fort wsjt_cxx wsjt_qt ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES} Qt5::Multimedia)
|
||||
target_link_libraries (wsjtx wsjt_fort wsjt_cxx wsjt_qt wsjt_qtmm ${hamlib_LIBRARIES} ${FFTW3_LIBRARIES})
|
||||
qt5_use_modules (wsjtx SerialPort) # not sure why the interface link library syntax above doesn't work
|
||||
|
||||
add_resources (message_aggregator_RESOURCES /qss ${message_aggregator_STYLESHEETS})
|
||||
|
Loading…
Reference in New Issue
Block a user