mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04:00 
			
		
		
		
	AM Modulator: added file input (basic)
This commit is contained in:
		
							parent
							
								
									4398a7426a
								
							
						
					
					
						commit
						7c1b1032c9
					
				| @ -37,7 +37,7 @@ Transmission or signal generation support for eligible devices (BladeRF and Hack | |||||||
|   - Phase 1: version 2.2.0: generation to file (File Sink) with AM modulator with simple sine modulation. Fixed sample rate of 48 kS/s (no effective interpolation) |   - Phase 1: version 2.2.0: generation to file (File Sink) with AM modulator with simple sine modulation. Fixed sample rate of 48 kS/s (no effective interpolation) | ||||||
|   - Phase 2: version 2.2.x: full baseband interpolation chain: in AM modulator and Up Channelizer. |   - Phase 2: version 2.2.x: full baseband interpolation chain: in AM modulator and Up Channelizer. | ||||||
|   - 2.3.0: SDRplay came into play ... |   - 2.3.0: SDRplay came into play ... | ||||||
|   - Phase 3a: version 2.3.x: Improve AM modulator with audio file input |   - Phase 3a: version 2.3.1: Improve AM modulator with audio file input | ||||||
|   - Phase 3b: version 2.3.x: Improve AM modulator with audio input (Mic) support |   - Phase 3b: version 2.3.x: Improve AM modulator with audio input (Mic) support | ||||||
|   - Phase 4a: version 2.4.0: FM modulator |   - Phase 4a: version 2.4.0: FM modulator | ||||||
|   - Phase 4b: version 2.4.x: WFM modulator |   - Phase 4b: version 2.4.x: WFM modulator | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,9 @@ | |||||||
|  | sdrangel (2.3.1-1) unstable; urgency=medium | ||||||
|  | 
 | ||||||
|  |   * AM Modulator: support file input | ||||||
|  | 
 | ||||||
|  |  -- Edouard Griffiths, F4EXB <f4exb06@gmail.com>  Sun, 27 Nov 2016 23:14:18 +0100 | ||||||
|  | 
 | ||||||
| sdrangel (2.3.0-1) unstable; urgency=medium | sdrangel (2.3.0-1) unstable; urgency=medium | ||||||
| 
 | 
 | ||||||
|   * SDRplay support: new input source plugin |   * SDRplay support: new input source plugin | ||||||
|  | |||||||
| @ -26,6 +26,13 @@ | |||||||
| #include "dsp/pidcontroller.h" | #include "dsp/pidcontroller.h" | ||||||
| 
 | 
 | ||||||
| MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureAMMod, Message) | MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureAMMod, Message) | ||||||
|  | MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureFileSourceName, Message) | ||||||
|  | MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureFileSourceSeek, Message) | ||||||
|  | MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureAFInput, Message) | ||||||
|  | MESSAGE_CLASS_DEFINITION(AMMod::MsgConfigureFileSourceStreamTiming, Message) | ||||||
|  | MESSAGE_CLASS_DEFINITION(AMMod::MsgReportFileSourceStreamData, Message) | ||||||
|  | MESSAGE_CLASS_DEFINITION(AMMod::MsgReportFileSourceStreamTiming, Message) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| AMMod::AMMod() : | AMMod::AMMod() : | ||||||
| 	m_settingsMutex(QMutex::Recursive) | 	m_settingsMutex(QMutex::Recursive) | ||||||
| @ -49,6 +56,8 @@ AMMod::AMMod() : | |||||||
| 	m_magsq = 0.0; | 	m_magsq = 0.0; | ||||||
| 
 | 
 | ||||||
| 	m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate); | 	m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate); | ||||||
|  | 
 | ||||||
|  | 	m_afInput = AMModInputNone; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AMMod::~AMMod() | AMMod::~AMMod() | ||||||
| @ -64,18 +73,19 @@ void AMMod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandw | |||||||
| void AMMod::pull(Sample& sample) | void AMMod::pull(Sample& sample) | ||||||
| { | { | ||||||
| 	Complex ci; | 	Complex ci; | ||||||
|  | 	Real t; | ||||||
| 
 | 
 | ||||||
| 	m_settingsMutex.lock(); | 	m_settingsMutex.lock(); | ||||||
| 
 | 
 | ||||||
|     if (m_interpolatorDistance > 1.0f) // decimate
 |     if (m_interpolatorDistance > 1.0f) // decimate
 | ||||||
|     { |     { | ||||||
|         Real t = m_toneNco.next(); |         pullAF(t); | ||||||
|         m_modSample.real(((t+1.0f) * m_running.m_modFactor * 16384.0f)); // modulate and scale zero frequency carrier
 |         m_modSample.real(((t+1.0f) * m_running.m_modFactor * 16384.0f)); // modulate and scale zero frequency carrier
 | ||||||
|         m_modSample.imag(0.0f); |         m_modSample.imag(0.0f); | ||||||
| 
 | 
 | ||||||
|         while (!m_interpolator.decimate(&m_interpolatorDistanceRemain, m_modSample, &ci)) |         while (!m_interpolator.decimate(&m_interpolatorDistanceRemain, m_modSample, &ci)) | ||||||
|         { |         { | ||||||
|             Real t = m_toneNco.next(); |             pullAF(t); | ||||||
|             m_modSample.real(((t+1.0f) * m_running.m_modFactor * 16384.0f)); // modulate and scale zero frequency carrier
 |             m_modSample.real(((t+1.0f) * m_running.m_modFactor * 16384.0f)); // modulate and scale zero frequency carrier
 | ||||||
|             m_modSample.imag(0.0f); |             m_modSample.imag(0.0f); | ||||||
|         } |         } | ||||||
| @ -84,7 +94,7 @@ void AMMod::pull(Sample& sample) | |||||||
|     { |     { | ||||||
|         if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, m_modSample, &ci)) |         if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, m_modSample, &ci)) | ||||||
|         { |         { | ||||||
|             Real t = m_toneNco.next(); |             pullAF(t); | ||||||
|             m_modSample.real(((t+1.0f) * m_running.m_modFactor * 16384.0f)); // modulate and scale zero frequency carrier
 |             m_modSample.real(((t+1.0f) * m_running.m_modFactor * 16384.0f)); // modulate and scale zero frequency carrier
 | ||||||
|             m_modSample.imag(0.0f); |             m_modSample.imag(0.0f); | ||||||
|         } |         } | ||||||
| @ -105,6 +115,41 @@ void AMMod::pull(Sample& sample) | |||||||
| 	sample.m_imag = (FixReal) ci.imag(); | 	sample.m_imag = (FixReal) ci.imag(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AMMod::pullAF(Real& sample) | ||||||
|  | { | ||||||
|  |     switch (m_afInput) | ||||||
|  |     { | ||||||
|  |     case AMModInputTone: | ||||||
|  |         sample = m_toneNco.next(); | ||||||
|  |         break; | ||||||
|  |     case AMModInputFile: | ||||||
|  |         // sox f4exb_call.wav --encoding float --endian little f4exb_call.raw
 | ||||||
|  |         // ffplay -f f32le -ar 48k -ac 1 f4exb_call.raw
 | ||||||
|  |         if (m_ifstream.is_open()) | ||||||
|  |         { | ||||||
|  |             if (m_ifstream.eof()) // TODO: handle loop playback situation
 | ||||||
|  |             { | ||||||
|  |                 m_ifstream.clear(); | ||||||
|  |                 m_ifstream.seekg(0, std::ios::beg); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             m_ifstream.read(reinterpret_cast<char*>(&sample), sizeof(Real)); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             sample = 0.0f; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case AMModInputAudio: | ||||||
|  |         sample = 0.0f; // TODO
 | ||||||
|  |         break; | ||||||
|  |     case AMModInputNone: | ||||||
|  |     default: | ||||||
|  |         sample = 0.0f; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AMMod::start() | void AMMod::start() | ||||||
| { | { | ||||||
| 	qDebug() << "AMMod::start: m_outputSampleRate: " << m_config.m_outputSampleRate | 	qDebug() << "AMMod::start: m_outputSampleRate: " << m_config.m_outputSampleRate | ||||||
| @ -155,6 +200,37 @@ bool AMMod::handleMessage(const Message& cmd) | |||||||
| 
 | 
 | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  | 	else if (MsgConfigureFileSourceName::match(cmd)) | ||||||
|  |     { | ||||||
|  |         MsgConfigureFileSourceName& conf = (MsgConfigureFileSourceName&) cmd; | ||||||
|  |         m_fileName = conf.getFileName(); | ||||||
|  |         openFileStream(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     else if (MsgConfigureFileSourceSeek::match(cmd)) | ||||||
|  |     { | ||||||
|  |         MsgConfigureFileSourceSeek& conf = (MsgConfigureFileSourceSeek&) cmd; | ||||||
|  |         int seekPercentage = conf.getPercentage(); | ||||||
|  |         seekFileStream(seekPercentage); | ||||||
|  | 
 | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     else if (MsgConfigureAFInput::match(cmd)) | ||||||
|  |     { | ||||||
|  |         MsgConfigureAFInput& conf = (MsgConfigureAFInput&) cmd; | ||||||
|  |         m_afInput = conf.getAFInput(); | ||||||
|  | 
 | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     else if (MsgConfigureFileSourceStreamTiming::match(cmd)) | ||||||
|  |     { | ||||||
|  |         std::size_t samplesCount = m_ifstream.tellg() / sizeof(Real); | ||||||
|  |         MsgReportFileSourceStreamTiming *report; | ||||||
|  |         report = MsgReportFileSourceStreamTiming::create(samplesCount); | ||||||
|  |         getOutputMessageQueue()->push(report); | ||||||
|  | 
 | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		return false; | 		return false; | ||||||
| @ -200,3 +276,37 @@ void AMMod::apply() | |||||||
| 	m_running.m_audioMute = m_config.m_audioMute; | 	m_running.m_audioMute = m_config.m_audioMute; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AMMod::openFileStream() | ||||||
|  | { | ||||||
|  |     if (m_ifstream.is_open()) { | ||||||
|  |         m_ifstream.close(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     m_ifstream.open(m_fileName.toStdString().c_str(), std::ios::binary | std::ios::ate); | ||||||
|  |     quint64 fileSize = m_ifstream.tellg(); | ||||||
|  |     m_ifstream.seekg(0,std::ios_base::beg); | ||||||
|  | 
 | ||||||
|  |     m_sampleRate = 48000; // fixed rate
 | ||||||
|  |     m_recordLength = fileSize / (sizeof(Real) * m_sampleRate); | ||||||
|  | 
 | ||||||
|  |     qDebug() << "AMMod::openFileStream: " << m_fileName.toStdString().c_str() | ||||||
|  |             << " fileSize: " << fileSize << "bytes" | ||||||
|  |             << " length: " << m_recordLength << " seconds"; | ||||||
|  | 
 | ||||||
|  |     MsgReportFileSourceStreamData *report; | ||||||
|  |     report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); | ||||||
|  |     getOutputMessageQueue()->push(report); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMMod::seekFileStream(int seekPercentage) | ||||||
|  | { | ||||||
|  |     QMutexLocker mutexLocker(&m_settingsMutex); | ||||||
|  | 
 | ||||||
|  |     if (m_ifstream.is_open()) | ||||||
|  |     { | ||||||
|  |         int seekPoint = ((m_recordLength * seekPercentage) / 100) * m_sampleRate; | ||||||
|  |         seekPoint *= sizeof(Real); | ||||||
|  |         m_ifstream.clear(); | ||||||
|  |         m_ifstream.seekg(seekPoint, std::ios::beg); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -19,6 +19,9 @@ | |||||||
| 
 | 
 | ||||||
| #include <QMutex> | #include <QMutex> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <iostream> | ||||||
|  | #include <fstream> | ||||||
|  | 
 | ||||||
| #include "dsp/basebandsamplesource.h" | #include "dsp/basebandsamplesource.h" | ||||||
| #include "dsp/nco.h" | #include "dsp/nco.h" | ||||||
| #include "dsp/interpolator.h" | #include "dsp/interpolator.h" | ||||||
| @ -32,6 +35,142 @@ class AMMod : public BasebandSampleSource { | |||||||
|     Q_OBJECT |     Q_OBJECT | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  |     typedef enum | ||||||
|  |     { | ||||||
|  |         AMModInputNone, | ||||||
|  |         AMModInputTone, | ||||||
|  |         AMModInputFile, | ||||||
|  |         AMModInputAudio | ||||||
|  |     } AMModInputAF; | ||||||
|  | 
 | ||||||
|  |     class MsgConfigureFileSourceName : public Message | ||||||
|  |     { | ||||||
|  |         MESSAGE_CLASS_DECLARATION | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         const QString& getFileName() const { return m_fileName; } | ||||||
|  | 
 | ||||||
|  |         static MsgConfigureFileSourceName* create(const QString& fileName) | ||||||
|  |         { | ||||||
|  |             return new MsgConfigureFileSourceName(fileName); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         QString m_fileName; | ||||||
|  | 
 | ||||||
|  |         MsgConfigureFileSourceName(const QString& fileName) : | ||||||
|  |             Message(), | ||||||
|  |             m_fileName(fileName) | ||||||
|  |         { } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class MsgConfigureFileSourceSeek : public Message | ||||||
|  |     { | ||||||
|  |         MESSAGE_CLASS_DECLARATION | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         int getPercentage() const { return m_seekPercentage; } | ||||||
|  | 
 | ||||||
|  |         static MsgConfigureFileSourceSeek* create(int seekPercentage) | ||||||
|  |         { | ||||||
|  |             return new MsgConfigureFileSourceSeek(seekPercentage); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     protected: | ||||||
|  |         int m_seekPercentage; //!< percentage of seek position from the beginning 0..100
 | ||||||
|  | 
 | ||||||
|  |         MsgConfigureFileSourceSeek(int seekPercentage) : | ||||||
|  |             Message(), | ||||||
|  |             m_seekPercentage(seekPercentage) | ||||||
|  |         { } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class MsgConfigureFileSourceStreamTiming : public Message { | ||||||
|  |         MESSAGE_CLASS_DECLARATION | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         static MsgConfigureFileSourceStreamTiming* create() | ||||||
|  |         { | ||||||
|  |             return new MsgConfigureFileSourceStreamTiming(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  | 
 | ||||||
|  |         MsgConfigureFileSourceStreamTiming() : | ||||||
|  |             Message() | ||||||
|  |         { } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class MsgConfigureAFInput : public Message | ||||||
|  |     { | ||||||
|  |         MESSAGE_CLASS_DECLARATION | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         AMModInputAF getAFInput() const { return m_afInput; } | ||||||
|  | 
 | ||||||
|  |         static MsgConfigureAFInput* create(AMModInputAF afInput) | ||||||
|  |         { | ||||||
|  |             return new MsgConfigureAFInput(afInput); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         AMModInputAF m_afInput; | ||||||
|  | 
 | ||||||
|  |         MsgConfigureAFInput(AMModInputAF afInput) : | ||||||
|  |             Message(), | ||||||
|  |             m_afInput(afInput) | ||||||
|  |         { } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class MsgReportFileSourceStreamTiming : public Message | ||||||
|  |     { | ||||||
|  |         MESSAGE_CLASS_DECLARATION | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         std::size_t getSamplesCount() const { return m_samplesCount; } | ||||||
|  | 
 | ||||||
|  |         static MsgReportFileSourceStreamTiming* create(std::size_t samplesCount) | ||||||
|  |         { | ||||||
|  |             return new MsgReportFileSourceStreamTiming(samplesCount); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     protected: | ||||||
|  |         std::size_t m_samplesCount; | ||||||
|  | 
 | ||||||
|  |         MsgReportFileSourceStreamTiming(std::size_t samplesCount) : | ||||||
|  |             Message(), | ||||||
|  |             m_samplesCount(samplesCount) | ||||||
|  |         { } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     class MsgReportFileSourceStreamData : public Message { | ||||||
|  |         MESSAGE_CLASS_DECLARATION | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  |         int getSampleRate() const { return m_sampleRate; } | ||||||
|  |         quint32 getRecordLength() const { return m_recordLength; } | ||||||
|  | 
 | ||||||
|  |         static MsgReportFileSourceStreamData* create(int sampleRate, | ||||||
|  |                 quint32 recordLength) | ||||||
|  |         { | ||||||
|  |             return new MsgReportFileSourceStreamData(sampleRate, recordLength); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     protected: | ||||||
|  |         int m_sampleRate; | ||||||
|  |         quint32 m_recordLength; | ||||||
|  | 
 | ||||||
|  |         MsgReportFileSourceStreamData(int sampleRate, | ||||||
|  |                 quint32 recordLength) : | ||||||
|  |             Message(), | ||||||
|  |             m_sampleRate(sampleRate), | ||||||
|  |             m_recordLength(recordLength) | ||||||
|  |         { } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     //=================================================================
 | ||||||
|  | 
 | ||||||
|     AMMod(); |     AMMod(); | ||||||
|     ~AMMod(); |     ~AMMod(); | ||||||
| 
 | 
 | ||||||
| @ -45,7 +184,8 @@ public: | |||||||
|     Real getMagSq() const { return m_magsq; } |     Real getMagSq() const { return m_magsq; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     class MsgConfigureAMMod : public Message { |     class MsgConfigureAMMod : public Message | ||||||
|  |     { | ||||||
|         MESSAGE_CLASS_DECLARATION |         MESSAGE_CLASS_DECLARATION | ||||||
| 
 | 
 | ||||||
|     public: |     public: | ||||||
| @ -74,6 +214,8 @@ private: | |||||||
|         { } |         { } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     //=================================================================
 | ||||||
|  | 
 | ||||||
|     struct AudioSample { |     struct AudioSample { | ||||||
|         qint16 l; |         qint16 l; | ||||||
|         qint16 r; |         qint16 r; | ||||||
| @ -105,6 +247,8 @@ private: | |||||||
|         { } |         { } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     //=================================================================
 | ||||||
|  | 
 | ||||||
|     Config m_config; |     Config m_config; | ||||||
|     Config m_running; |     Config m_running; | ||||||
| 
 | 
 | ||||||
| @ -128,7 +272,17 @@ private: | |||||||
|     SampleVector m_sampleBuffer; |     SampleVector m_sampleBuffer; | ||||||
|     QMutex m_settingsMutex; |     QMutex m_settingsMutex; | ||||||
| 
 | 
 | ||||||
|  |     std::ifstream m_ifstream; | ||||||
|  |     QString m_fileName; | ||||||
|  |     quint32 m_recordLength; //!< record length in seconds computed from file size
 | ||||||
|  |     int m_sampleRate; | ||||||
|  | 
 | ||||||
|  |     AMModInputAF m_afInput; | ||||||
|  | 
 | ||||||
|     void apply(); |     void apply(); | ||||||
|  |     void pullAF(Real& sample); | ||||||
|  |     void openFileStream(); | ||||||
|  |     void seekFileStream(int seekPercentage); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,6 +16,9 @@ | |||||||
| 
 | 
 | ||||||
| #include <QDockWidget> | #include <QDockWidget> | ||||||
| #include <QMainWindow> | #include <QMainWindow> | ||||||
|  | #include <QFileDialog> | ||||||
|  | #include <QTime> | ||||||
|  | #include <QDebug> | ||||||
| 
 | 
 | ||||||
| #include "ammodgui.h" | #include "ammodgui.h" | ||||||
| 
 | 
 | ||||||
| @ -31,8 +34,6 @@ | |||||||
| #include "dsp/dspengine.h" | #include "dsp/dspengine.h" | ||||||
| #include "mainwindow.h" | #include "mainwindow.h" | ||||||
| 
 | 
 | ||||||
| #include "ammod.h" |  | ||||||
| 
 |  | ||||||
| const QString AMModGUI::m_channelID = "sdrangel.channeltx.modam"; | const QString AMModGUI::m_channelID = "sdrangel.channeltx.modam"; | ||||||
| 
 | 
 | ||||||
| const int AMModGUI::m_rfBW[] = { | const int AMModGUI::m_rfBW[] = { | ||||||
| @ -141,7 +142,24 @@ bool AMModGUI::deserialize(const QByteArray& data) | |||||||
| 
 | 
 | ||||||
| bool AMModGUI::handleMessage(const Message& message) | bool AMModGUI::handleMessage(const Message& message) | ||||||
| { | { | ||||||
| 	return false; |     if (AMMod::MsgReportFileSourceStreamData::match(message)) | ||||||
|  |     { | ||||||
|  |         m_recordSampleRate = ((AMMod::MsgReportFileSourceStreamData&)message).getSampleRate(); | ||||||
|  |         m_recordLength = ((AMMod::MsgReportFileSourceStreamData&)message).getRecordLength(); | ||||||
|  |         m_samplesCount = 0; | ||||||
|  |         updateWithStreamData(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     else if (AMMod::MsgReportFileSourceStreamTiming::match(message)) | ||||||
|  |     { | ||||||
|  |         m_samplesCount = ((AMMod::MsgReportFileSourceStreamTiming&)message).getSamplesCount(); | ||||||
|  |         updateWithStreamTime(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AMModGUI::viewChanged() | void AMModGUI::viewChanged() | ||||||
| @ -149,6 +167,19 @@ void AMModGUI::viewChanged() | |||||||
| 	applySettings(); | 	applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AMModGUI::handleSourceMessages() | ||||||
|  | { | ||||||
|  |     Message* message; | ||||||
|  | 
 | ||||||
|  |     while ((message = m_amMod->getOutputMessageQueue()->pop()) != 0) | ||||||
|  |     { | ||||||
|  |         if (handleMessage(*message)) | ||||||
|  |         { | ||||||
|  |             delete message; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AMModGUI::on_deltaMinus_toggled(bool minus) | void AMModGUI::on_deltaMinus_toggled(bool minus) | ||||||
| { | { | ||||||
| 	int deltaFrequency = m_channelMarker.getCenterFrequency(); | 	int deltaFrequency = m_channelMarker.getCenterFrequency(); | ||||||
| @ -193,6 +224,74 @@ void AMModGUI::on_audioMute_toggled(bool checked) | |||||||
| 	applySettings(); | 	applySettings(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AMModGUI::on_playLoop_toggled(bool checked) | ||||||
|  | { | ||||||
|  |     // TODO: do something about it!
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::on_play_toggled(bool checked) | ||||||
|  | { | ||||||
|  |     ui->tone->setEnabled(!checked); // release other source inputs
 | ||||||
|  |     ui->mic->setEnabled(!checked); | ||||||
|  |     m_modAFInput = checked ? AMMod::AMModInputFile : AMMod::AMModInputNone; | ||||||
|  |     AMMod::MsgConfigureAFInput* message = AMMod::MsgConfigureAFInput::create(m_modAFInput); | ||||||
|  |     m_amMod->getInputMessageQueue()->push(message); | ||||||
|  |     ui->navTimeSlider->setEnabled(!checked); | ||||||
|  |     m_enableNavTime = !checked; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::on_tone_toggled(bool checked) | ||||||
|  | { | ||||||
|  |     ui->play->setEnabled(!checked); // release other source inputs
 | ||||||
|  |     ui->mic->setEnabled(!checked); | ||||||
|  |     m_modAFInput = checked ? AMMod::AMModInputTone : AMMod::AMModInputNone; | ||||||
|  |     AMMod::MsgConfigureAFInput* message = AMMod::MsgConfigureAFInput::create(m_modAFInput); | ||||||
|  |     m_amMod->getInputMessageQueue()->push(message); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::on_mic_toggled(bool checked) | ||||||
|  | { | ||||||
|  |     ui->play->setEnabled(!checked); // release other source inputs
 | ||||||
|  |     ui->tone->setEnabled(!checked); // release other source inputs
 | ||||||
|  |     m_modAFInput = checked ? AMMod::AMModInputAudio : AMMod::AMModInputNone; | ||||||
|  |     AMMod::MsgConfigureAFInput* message = AMMod::MsgConfigureAFInput::create(m_modAFInput); | ||||||
|  |     m_amMod->getInputMessageQueue()->push(message); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::on_navTimeSlider_valueChanged(int value) | ||||||
|  | { | ||||||
|  |     if (m_enableNavTime && ((value >= 0) && (value <= 100))) | ||||||
|  |     { | ||||||
|  |         int t_sec = (m_recordLength * value) / 100; | ||||||
|  |         QTime t(0, 0, 0, 0); | ||||||
|  |         t = t.addSecs(t_sec); | ||||||
|  | 
 | ||||||
|  |         AMMod::MsgConfigureFileSourceSeek* message = AMMod::MsgConfigureFileSourceSeek::create(value); | ||||||
|  |         m_amMod->getInputMessageQueue()->push(message); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::on_showFileDialog_clicked(bool checked) | ||||||
|  | { | ||||||
|  |     QString fileName = QFileDialog::getOpenFileName(this, | ||||||
|  |         tr("Open raw audio file"), ".", tr("Raw audio Files (*.raw)")); | ||||||
|  | 
 | ||||||
|  |     if (fileName != "") | ||||||
|  |     { | ||||||
|  |         m_fileName = fileName; | ||||||
|  |         ui->recordFileText->setText(m_fileName); | ||||||
|  |         ui->play->setEnabled(true); | ||||||
|  |         configureFileName(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::configureFileName() | ||||||
|  | { | ||||||
|  |     qDebug() << "FileSourceGui::configureFileName: " << m_fileName.toStdString().c_str(); | ||||||
|  |     AMMod::MsgConfigureFileSourceName* message = AMMod::MsgConfigureFileSourceName::create(m_fileName); | ||||||
|  |     m_amMod->getInputMessageQueue()->push(message); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void AMModGUI::onWidgetRolled(QWidget* widget, bool rollDown) | void AMModGUI::onWidgetRolled(QWidget* widget, bool rollDown) | ||||||
| { | { | ||||||
| } | } | ||||||
| @ -214,7 +313,13 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare | |||||||
| 	m_channelMarker(this), | 	m_channelMarker(this), | ||||||
| 	m_basicSettingsShown(false), | 	m_basicSettingsShown(false), | ||||||
| 	m_doApplySettings(true), | 	m_doApplySettings(true), | ||||||
| 	m_channelPowerDbAvg(20,0) | 	m_channelPowerDbAvg(20,0), | ||||||
|  |     m_recordLength(0), | ||||||
|  |     m_recordSampleRate(48000), | ||||||
|  |     m_samplesCount(0), | ||||||
|  |     m_tickCount(0), | ||||||
|  |     m_enableNavTime(false), | ||||||
|  |     m_modAFInput(AMMod::AMModInputNone) | ||||||
| { | { | ||||||
| 	ui->setupUi(this); | 	ui->setupUi(this); | ||||||
| 	setAttribute(Qt::WA_DeleteOnClose, true); | 	setAttribute(Qt::WA_DeleteOnClose, true); | ||||||
| @ -243,7 +348,14 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare | |||||||
|     m_deviceAPI->addChannelMarker(&m_channelMarker); |     m_deviceAPI->addChannelMarker(&m_channelMarker); | ||||||
|     m_deviceAPI->addRollupWidget(this); |     m_deviceAPI->addRollupWidget(this); | ||||||
| 
 | 
 | ||||||
|  |     ui->play->setEnabled(false); | ||||||
|  |     ui->play->setChecked(false); | ||||||
|  |     ui->tone->setChecked(false); | ||||||
|  |     ui->mic->setChecked(false); | ||||||
|  | 
 | ||||||
| 	applySettings(); | 	applySettings(); | ||||||
|  | 
 | ||||||
|  | 	connect(m_amMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AMModGUI::~AMModGUI() | AMModGUI::~AMModGUI() | ||||||
| @ -302,5 +414,44 @@ void AMModGUI::tick() | |||||||
| 	Real powDb = CalcDb::dbPower(m_amMod->getMagSq()); | 	Real powDb = CalcDb::dbPower(m_amMod->getMagSq()); | ||||||
| 	m_channelPowerDbAvg.feed(powDb); | 	m_channelPowerDbAvg.feed(powDb); | ||||||
| 	ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); | 	ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); | ||||||
|  | 
 | ||||||
|  |     if (((++m_tickCount & 0xf) == 0) && (m_modAFInput == AMMod::AMModInputFile)) | ||||||
|  |     { | ||||||
|  |         AMMod::MsgConfigureFileSourceStreamTiming* message = AMMod::MsgConfigureFileSourceStreamTiming::create(); | ||||||
|  |         m_amMod->getInputMessageQueue()->push(message); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void AMModGUI::updateWithStreamData() | ||||||
|  | { | ||||||
|  |     QTime recordLength(0, 0, 0, 0); | ||||||
|  |     recordLength = recordLength.addSecs(m_recordLength); | ||||||
|  |     QString s_time = recordLength.toString("hh:mm:ss"); | ||||||
|  |     ui->recordLengthText->setText(s_time); | ||||||
|  |     updateWithStreamTime(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void AMModGUI::updateWithStreamTime() | ||||||
|  | { | ||||||
|  |     int t_sec = 0; | ||||||
|  |     int t_msec = 0; | ||||||
|  | 
 | ||||||
|  |     if (m_recordSampleRate > 0) | ||||||
|  |     { | ||||||
|  |         t_msec = ((m_samplesCount * 1000) / m_recordSampleRate) % 1000; | ||||||
|  |         t_sec = m_samplesCount / m_recordSampleRate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     QTime t(0, 0, 0, 0); | ||||||
|  |     t = t.addSecs(t_sec); | ||||||
|  |     t = t.addMSecs(t_msec); | ||||||
|  |     QString s_timems = t.toString("hh:mm:ss.zzz"); | ||||||
|  |     QString s_time = t.toString("hh:mm:ss"); | ||||||
|  |     ui->relTimeText->setText(s_timems); | ||||||
|  | 
 | ||||||
|  |     if (!m_enableNavTime) | ||||||
|  |     { | ||||||
|  |         float posRatio = (float) t_sec / (float) m_recordLength; | ||||||
|  |         ui->navTimeSlider->setValue((int) (posRatio * 100.0)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ | |||||||
| #include "plugin/plugingui.h" | #include "plugin/plugingui.h" | ||||||
| #include "dsp/channelmarker.h" | #include "dsp/channelmarker.h" | ||||||
| #include "dsp/movingaverage.h" | #include "dsp/movingaverage.h" | ||||||
|  | #include "ammod.h" | ||||||
| 
 | 
 | ||||||
| class PluginAPI; | class PluginAPI; | ||||||
| class DeviceSinkAPI; | class DeviceSinkAPI; | ||||||
| @ -55,14 +56,26 @@ public: | |||||||
| 
 | 
 | ||||||
| private slots: | private slots: | ||||||
|     void viewChanged(); |     void viewChanged(); | ||||||
|  |     void handleSourceMessages(); | ||||||
|  | 
 | ||||||
|     void on_deltaFrequency_changed(quint64 value); |     void on_deltaFrequency_changed(quint64 value); | ||||||
|     void on_deltaMinus_toggled(bool minus); |     void on_deltaMinus_toggled(bool minus); | ||||||
|     void on_rfBW_valueChanged(int value); |     void on_rfBW_valueChanged(int value); | ||||||
|     void on_afBW_valueChanged(int value); |     void on_afBW_valueChanged(int value); | ||||||
|     void on_modPercent_valueChanged(int value); |     void on_modPercent_valueChanged(int value); | ||||||
|     void on_audioMute_toggled(bool checked); |     void on_audioMute_toggled(bool checked); | ||||||
|  |     void on_tone_toggled(bool checked); | ||||||
|  |     void on_mic_toggled(bool checked); | ||||||
|  |     void on_play_toggled(bool checked); | ||||||
|  | 
 | ||||||
|  |     void on_playLoop_toggled(bool checked); | ||||||
|  |     void on_navTimeSlider_valueChanged(int value); | ||||||
|  |     void on_showFileDialog_clicked(bool checked); | ||||||
|  | 
 | ||||||
|     void onWidgetRolled(QWidget* widget, bool rollDown); |     void onWidgetRolled(QWidget* widget, bool rollDown); | ||||||
|     void onMenuDoubleClicked(); |     void onMenuDoubleClicked(); | ||||||
|  | 
 | ||||||
|  |     void configureFileName(); | ||||||
|     void tick(); |     void tick(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| @ -78,6 +91,14 @@ private: | |||||||
|     AMMod* m_amMod; |     AMMod* m_amMod; | ||||||
|     MovingAverage<Real> m_channelPowerDbAvg; |     MovingAverage<Real> m_channelPowerDbAvg; | ||||||
| 
 | 
 | ||||||
|  |     QString m_fileName; | ||||||
|  |     quint32 m_recordLength; | ||||||
|  |     int m_recordSampleRate; | ||||||
|  |     int m_samplesCount; | ||||||
|  |     std::size_t m_tickCount; | ||||||
|  |     bool m_enableNavTime; | ||||||
|  |     AMMod::AMModInputAF m_modAFInput; | ||||||
|  | 
 | ||||||
|     static const int m_rfBW[]; |     static const int m_rfBW[]; | ||||||
| 
 | 
 | ||||||
|     explicit AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* parent = NULL); |     explicit AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* parent = NULL); | ||||||
| @ -85,6 +106,8 @@ private: | |||||||
| 
 | 
 | ||||||
|     void blockApplySettings(bool block); |     void blockApplySettings(bool block); | ||||||
|     void applySettings(); |     void applySettings(); | ||||||
|  |     void updateWithStreamData(); | ||||||
|  |     void updateWithStreamTime(); | ||||||
| 
 | 
 | ||||||
|     void leaveEvent(QEvent*); |     void leaveEvent(QEvent*); | ||||||
|     void enterEvent(QEvent*); |     void enterEvent(QEvent*); | ||||||
|  | |||||||
| @ -6,8 +6,8 @@ | |||||||
|    <rect> |    <rect> | ||||||
|     <x>0</x> |     <x>0</x> | ||||||
|     <y>0</y> |     <y>0</y> | ||||||
|     <width>257</width> |     <width>261</width> | ||||||
|     <height>143</height> |     <height>180</height> | ||||||
|    </rect> |    </rect> | ||||||
|   </property> |   </property> | ||||||
|   <property name="font"> |   <property name="font"> | ||||||
| @ -27,8 +27,8 @@ | |||||||
|     <rect> |     <rect> | ||||||
|      <x>10</x> |      <x>10</x> | ||||||
|      <y>10</y> |      <y>10</y> | ||||||
|      <width>235</width> |      <width>241</width> | ||||||
|      <height>121</height> |      <height>161</height> | ||||||
|     </rect> |     </rect> | ||||||
|    </property> |    </property> | ||||||
|    <property name="windowTitle"> |    <property name="windowTitle"> | ||||||
| @ -302,22 +302,221 @@ | |||||||
|       </item> |       </item> | ||||||
|      </layout> |      </layout> | ||||||
|     </item> |     </item> | ||||||
|  |     <item> | ||||||
|  |      <layout class="QHBoxLayout" name="recordFileSelectLayout"> | ||||||
|  |       <item> | ||||||
|  |        <widget class="ButtonSwitch" name="tone"> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Tone modulation (1 kHz)</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>...</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="icon"> | ||||||
|  |          <iconset resource="../../../sdrbase/resources/res.qrc"> | ||||||
|  |           <normaloff>:/carrier.png</normaloff>:/carrier.png</iconset> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="ButtonSwitch" name="mic"> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Audio input</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>...</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="icon"> | ||||||
|  |          <iconset resource="../../../sdrbase/resources/res.qrc"> | ||||||
|  |           <normaloff>:/microphone.png</normaloff>:/microphone.png</iconset> | ||||||
|  |         </property> | ||||||
|  |         <property name="checkable"> | ||||||
|  |          <bool>true</bool> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QPushButton" name="showFileDialog"> | ||||||
|  |         <property name="minimumSize"> | ||||||
|  |          <size> | ||||||
|  |           <width>24</width> | ||||||
|  |           <height>24</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |         <property name="maximumSize"> | ||||||
|  |          <size> | ||||||
|  |           <width>24</width> | ||||||
|  |           <height>24</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Open record file (48 kHz 32 bit float LE mono)</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string/> | ||||||
|  |         </property> | ||||||
|  |         <property name="icon"> | ||||||
|  |          <iconset resource="../../../sdrbase/resources/res.qrc"> | ||||||
|  |           <normaloff>:/preset-load.png</normaloff>:/preset-load.png</iconset> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QLabel" name="recordFileText"> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>...</string> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |      </layout> | ||||||
|  |     </item> | ||||||
|  |     <item> | ||||||
|  |      <layout class="QHBoxLayout" name="playControllLayout"> | ||||||
|  |       <item> | ||||||
|  |        <widget class="ButtonSwitch" name="playLoop"> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Play record file in a loop</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>...</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="icon"> | ||||||
|  |          <iconset resource="../../../sdrbase/resources/res.qrc"> | ||||||
|  |           <normaloff>:/playloop.png</normaloff>:/playloop.png</iconset> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="ButtonSwitch" name="play"> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Record file play/pause</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>...</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="icon"> | ||||||
|  |          <iconset resource="../../../sdrbase/resources/res.qrc"> | ||||||
|  |           <normaloff>:/play.png</normaloff> | ||||||
|  |           <normalon>:/pause.png</normalon> | ||||||
|  |           <disabledoff>:/play.png</disabledoff> | ||||||
|  |           <disabledon>:/play.png</disabledon>:/play.png</iconset> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <spacer name="horizontalSpacer_2"> | ||||||
|  |         <property name="orientation"> | ||||||
|  |          <enum>Qt::Horizontal</enum> | ||||||
|  |         </property> | ||||||
|  |         <property name="sizeHint" stdset="0"> | ||||||
|  |          <size> | ||||||
|  |           <width>40</width> | ||||||
|  |           <height>20</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |        </spacer> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="Line" name="linePlay1"> | ||||||
|  |         <property name="orientation"> | ||||||
|  |          <enum>Qt::Vertical</enum> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QLabel" name="relTimeText"> | ||||||
|  |         <property name="enabled"> | ||||||
|  |          <bool>false</bool> | ||||||
|  |         </property> | ||||||
|  |         <property name="minimumSize"> | ||||||
|  |          <size> | ||||||
|  |           <width>90</width> | ||||||
|  |           <height>0</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Record time from start</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>00:00:00.000</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="alignment"> | ||||||
|  |          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="Line" name="linePlay2"> | ||||||
|  |         <property name="orientation"> | ||||||
|  |          <enum>Qt::Vertical</enum> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QLabel" name="recordLengthText"> | ||||||
|  |         <property name="enabled"> | ||||||
|  |          <bool>false</bool> | ||||||
|  |         </property> | ||||||
|  |         <property name="minimumSize"> | ||||||
|  |          <size> | ||||||
|  |           <width>60</width> | ||||||
|  |           <height>0</height> | ||||||
|  |          </size> | ||||||
|  |         </property> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Total record time</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>00:00:00</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="alignment"> | ||||||
|  |          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |      </layout> | ||||||
|  |     </item> | ||||||
|  |     <item> | ||||||
|  |      <layout class="QHBoxLayout" name="horizontalLayout_nav"> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QSlider" name="navTimeSlider"> | ||||||
|  |         <property name="toolTip"> | ||||||
|  |          <string>Record file time navigator</string> | ||||||
|  |         </property> | ||||||
|  |         <property name="maximum"> | ||||||
|  |          <number>100</number> | ||||||
|  |         </property> | ||||||
|  |         <property name="pageStep"> | ||||||
|  |          <number>1</number> | ||||||
|  |         </property> | ||||||
|  |         <property name="orientation"> | ||||||
|  |          <enum>Qt::Horizontal</enum> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|  |      </layout> | ||||||
|  |     </item> | ||||||
|    </layout> |    </layout> | ||||||
|   </widget> |   </widget> | ||||||
|  </widget> |  </widget> | ||||||
|  <customwidgets> |  <customwidgets> | ||||||
|   <customwidget> |  | ||||||
|    <class>RollupWidget</class> |  | ||||||
|    <extends>QWidget</extends> |  | ||||||
|    <header>gui/rollupwidget.h</header> |  | ||||||
|    <container>1</container> |  | ||||||
|   </customwidget> |  | ||||||
|   <customwidget> |   <customwidget> | ||||||
|    <class>ValueDial</class> |    <class>ValueDial</class> | ||||||
|    <extends>QWidget</extends> |    <extends>QWidget</extends> | ||||||
|    <header>gui/valuedial.h</header> |    <header>gui/valuedial.h</header> | ||||||
|    <container>1</container> |    <container>1</container> | ||||||
|   </customwidget> |   </customwidget> | ||||||
|  |   <customwidget> | ||||||
|  |    <class>ButtonSwitch</class> | ||||||
|  |    <extends>QToolButton</extends> | ||||||
|  |    <header>gui/buttonswitch.h</header> | ||||||
|  |   </customwidget> | ||||||
|  |   <customwidget> | ||||||
|  |    <class>RollupWidget</class> | ||||||
|  |    <extends>QWidget</extends> | ||||||
|  |    <header>gui/rollupwidget.h</header> | ||||||
|  |    <container>1</container> | ||||||
|  |   </customwidget> | ||||||
|  </customwidgets> |  </customwidgets> | ||||||
|  <resources> |  <resources> | ||||||
|   <include location="../../../sdrbase/resources/res.qrc"/> |   <include location="../../../sdrbase/resources/res.qrc"/> | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
| 
 | 
 | ||||||
| const PluginDescriptor AMModPlugin::m_pluginDescriptor = { | const PluginDescriptor AMModPlugin::m_pluginDescriptor = { | ||||||
|     QString("AM Modulator"), |     QString("AM Modulator"), | ||||||
|     QString("2.2.1"), |     QString("2.3.1"), | ||||||
|     QString("(c) Edouard Griffiths, F4EXB"), |     QString("(c) Edouard Griffiths, F4EXB"), | ||||||
|     QString("https://github.com/f4exb/sdrangel"), |     QString("https://github.com/f4exb/sdrangel"), | ||||||
|     true, |     true, | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ else (BUILD_DEBIAN) | |||||||
| include_directories( | include_directories( | ||||||
|     . |     . | ||||||
|     ${CMAKE_CURRENT_BINARY_DIR} |     ${CMAKE_CURRENT_BINARY_DIR} | ||||||
|     ${LIBRTLSDRSRC}/include |     ${LIBRTLSDR_INCLUDE_DIR} | ||||||
| ) | ) | ||||||
| endif (BUILD_DEBIAN) | endif (BUILD_DEBIAN) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -84,7 +84,7 @@ | |||||||
|    <item> |    <item> | ||||||
|     <widget class="QLabel" name="label_2"> |     <widget class="QLabel" name="label_2"> | ||||||
|      <property name="text"> |      <property name="text"> | ||||||
|       <string><html><head/><body><p>Version 2.3.0 - Copyright (C) 2015-2016 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a> This is a complete redesign from RTL-SDRangelove at <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/hexameron/rtl-sdrangelove</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in RTL-SDRangelove</p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html></string> |       <string><html><head/><body><p>Version 2.3.1 - Copyright (C) 2015-2016 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a> This is a complete redesign from RTL-SDRangelove at <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/hexameron/rtl-sdrangelove</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in RTL-SDRangelove</p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html></string> | ||||||
|      </property> |      </property> | ||||||
|      <property name="wordWrap"> |      <property name="wordWrap"> | ||||||
|       <bool>true</bool> |       <bool>true</bool> | ||||||
|  | |||||||
| @ -450,7 +450,7 @@ void MainWindow::savePresetSettings(Preset* preset, int tabIndex) | |||||||
| void MainWindow::createStatusBar() | void MainWindow::createStatusBar() | ||||||
| { | { | ||||||
|     QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR); |     QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR); | ||||||
|     m_showSystemWidget = new QLabel("SDRangel v2.3.0 " + qtVersionStr + QSysInfo::prettyProductName(), this); |     m_showSystemWidget = new QLabel("SDRangel v2.3.1 " + qtVersionStr + QSysInfo::prettyProductName(), this); | ||||||
|     statusBar()->addPermanentWidget(m_showSystemWidget); |     statusBar()->addPermanentWidget(m_showSystemWidget); | ||||||
| 
 | 
 | ||||||
| 	m_dateTimeWidget = new QLabel(tr("Date"), this); | 	m_dateTimeWidget = new QLabel(tr("Date"), this); | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								sdrbase/resources/microphone.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sdrbase/resources/microphone.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.1 KiB | 
| @ -1,5 +1,6 @@ | |||||||
| <RCC> | <RCC> | ||||||
|   <qresource prefix="/"> |   <qresource prefix="/"> | ||||||
|  |     <file>microphone.png</file> | ||||||
|     <file>checkmark.png</file> |     <file>checkmark.png</file> | ||||||
|     <file>questionmark.png</file> |     <file>questionmark.png</file> | ||||||
|     <file>res.qrc</file> |     <file>res.qrc</file> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user