2021-10-23 19:24:57 +02:00
|
|
|
#include "wav.h"
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <cstring>
|
2023-09-08 00:21:38 -04:00
|
|
|
#include <inttypes.h>
|
2022-12-10 22:40:07 +01:00
|
|
|
#include "common/utils.h"
|
2021-10-23 19:24:57 +02:00
|
|
|
|
|
|
|
|
namespace wav
|
|
|
|
|
{
|
|
|
|
|
WavHeader parseHeaderFromFileWav(std::string file)
|
|
|
|
|
{
|
|
|
|
|
WavHeader header;
|
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
|
|
|
|
|
|
if (std::filesystem::exists(file))
|
|
|
|
|
{
|
|
|
|
|
std::ifstream file_stream(file, std::ios::binary);
|
|
|
|
|
file_stream.read((char *)&header, sizeof(header));
|
|
|
|
|
file_stream.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return header;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RF64Header parseHeaderFromFileRF64(std::string file)
|
|
|
|
|
{
|
|
|
|
|
RF64Header header;
|
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
|
|
|
|
|
|
|
|
if (std::filesystem::exists(file))
|
|
|
|
|
{
|
|
|
|
|
std::ifstream file_stream(file, std::ios::binary);
|
|
|
|
|
file_stream.read((char *)&header, sizeof(header));
|
|
|
|
|
file_stream.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return header;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isValidWav(WavHeader header)
|
|
|
|
|
{
|
|
|
|
|
return std::string(&header.RIFF[0], &header.RIFF[4]) == "RIFF";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isValidRF64(WavHeader header)
|
|
|
|
|
{
|
|
|
|
|
return std::string(&header.RIFF[0], &header.RIFF[4]) == "RF64";
|
|
|
|
|
}
|
2022-12-10 22:40:07 +01:00
|
|
|
|
|
|
|
|
FileMetadata tryParseFilenameMetadata(std::string filepath, bool audio)
|
|
|
|
|
{
|
|
|
|
|
FileMetadata md;
|
|
|
|
|
|
|
|
|
|
std::string filename = std::filesystem::path(filepath).stem().string();
|
2024-01-08 15:59:05 -05:00
|
|
|
char month_str[4];
|
|
|
|
|
double freq_mhz;
|
2022-12-10 22:40:07 +01:00
|
|
|
uint64_t freq;
|
2023-12-01 22:41:32 +01:00
|
|
|
uint64_t samp;
|
2022-12-10 22:40:07 +01:00
|
|
|
std::tm timeS;
|
|
|
|
|
memset(&timeS, 0, sizeof(std::tm));
|
|
|
|
|
|
|
|
|
|
if (audio)
|
|
|
|
|
{
|
|
|
|
|
// SDR++ Audio filename
|
|
|
|
|
if (sscanf(filename.c_str(),
|
2023-09-08 00:21:38 -04:00
|
|
|
"audio_%" PRIu64 "Hz_%d-%d-%d_%d-%d-%d",
|
2022-12-10 22:40:07 +01:00
|
|
|
&freq,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&timeS.tm_mday, &timeS.tm_mon, &timeS.tm_year) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2023-11-07 14:40:39 +01:00
|
|
|
timeS.tm_isdst = -1;
|
2022-12-10 22:40:07 +01:00
|
|
|
md.frequency = freq;
|
2023-11-07 14:40:39 +01:00
|
|
|
md.timestamp = mktime(&timeS);
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// HDSDR Audio filename
|
|
|
|
|
if (sscanf(filename.c_str(),
|
2023-09-08 00:21:38 -04:00
|
|
|
"HDSDR_%4d%2d%2d_%2d%2d%2dZ_%" PRIu64 "kHz_AF",
|
2022-12-10 22:40:07 +01:00
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&freq) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
|
|
|
|
md.frequency = freq * 1e3;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SDRSharp Audio filename
|
|
|
|
|
if (sscanf(filename.c_str(),
|
2023-09-08 00:21:38 -04:00
|
|
|
"SDRSharp_%4d%2d%2d_%2d%2d%2dZ_%" PRIu64 "Hz_AF",
|
2022-12-10 22:40:07 +01:00
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&freq) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
|
|
|
|
md.frequency = freq;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SDRUno Audio filename
|
|
|
|
|
if (sscanf(filename.c_str(),
|
2023-09-08 00:21:38 -04:00
|
|
|
"SDRUno_%4d%2d%2d_%2d%2d%2d_%" PRIu64 "Hz",
|
2022-12-10 22:40:07 +01:00
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&freq) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2023-11-07 14:40:39 +01:00
|
|
|
timeS.tm_isdst = -1;
|
2022-12-10 22:40:07 +01:00
|
|
|
md.frequency = freq;
|
|
|
|
|
md.timestamp = mktime(&timeS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AltiWx Audio UTC timestamp
|
|
|
|
|
if (sscanf(filename.c_str(),
|
|
|
|
|
"%4d%2d%2dT%2d%2d%2dZ",
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec) == 6)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-26 11:59:22 +02:00
|
|
|
// GQRX Audio filename (UTC)
|
|
|
|
|
if (sscanf(filename.c_str(),
|
2023-09-08 00:21:38 -04:00
|
|
|
"gqrx_%4d%2d%2d_%2d%2d%2d_%" PRIu64,
|
2023-06-26 11:59:22 +02:00
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&freq) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
|
|
|
|
md.frequency = freq;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2023-06-26 11:59:22 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-10 22:40:07 +01:00
|
|
|
// Simple UTC timestamp (WXtoImg)
|
|
|
|
|
if (sscanf(filename.c_str(),
|
|
|
|
|
"%4d%2d%2d%2d%2d%2d",
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec) == 6)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
2023-01-11 22:10:08 +01:00
|
|
|
|
|
|
|
|
// Other filename (NOAA-APT-v2?)
|
|
|
|
|
int satnum = 0;
|
|
|
|
|
if (sscanf(filename.c_str(),
|
|
|
|
|
"NOAA%2d%4d%2d%2d-%2d%2d%2d",
|
|
|
|
|
&satnum,
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2023-11-07 14:40:39 +01:00
|
|
|
timeS.tm_isdst = -1;
|
2023-01-11 22:10:08 +01:00
|
|
|
md.timestamp = mktime(&timeS);
|
|
|
|
|
}
|
2023-08-03 23:22:44 +02:00
|
|
|
|
|
|
|
|
// Other filename (NOAA-APT-v2?)
|
2023-08-03 23:38:09 +02:00
|
|
|
// satnum = 0;
|
2023-08-03 23:22:44 +02:00
|
|
|
if (sscanf(filename.c_str(),
|
|
|
|
|
"NOAA%2d-%4d%2d%2d-%2d%2d%2d",
|
|
|
|
|
&satnum,
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2023-11-07 14:40:39 +01:00
|
|
|
timeS.tm_isdst = -1;
|
2023-08-03 23:22:44 +02:00
|
|
|
md.timestamp = mktime(&timeS);
|
|
|
|
|
}
|
2023-09-12 14:33:51 +02:00
|
|
|
|
|
|
|
|
// Other filename (NOAA-APT-v2?)
|
|
|
|
|
// satnum = 0;
|
|
|
|
|
if (sscanf(filename.c_str(),
|
|
|
|
|
"NOAA-%2d-%4d%2d%2d-%2d%2d%2d",
|
|
|
|
|
&satnum,
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2023-11-07 14:40:39 +01:00
|
|
|
timeS.tm_isdst = -1;
|
2023-09-12 14:33:51 +02:00
|
|
|
md.timestamp = mktime(&timeS);
|
|
|
|
|
}
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// SDR++ Baseband filename
|
|
|
|
|
if (sscanf(filename.c_str(),
|
2023-09-08 00:21:38 -04:00
|
|
|
"baseband_%" PRIu64 "Hz_%d-%d-%d_%d-%d-%d",
|
2022-12-10 22:40:07 +01:00
|
|
|
&freq,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&timeS.tm_mday, &timeS.tm_mon, &timeS.tm_year) == 7)
|
|
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
2023-11-07 14:40:39 +01:00
|
|
|
timeS.tm_isdst = -1;
|
2022-12-10 22:40:07 +01:00
|
|
|
md.frequency = freq;
|
|
|
|
|
md.timestamp = mktime(&timeS);
|
|
|
|
|
}
|
2023-12-01 22:41:32 +01:00
|
|
|
|
2024-01-08 15:59:05 -05:00
|
|
|
// SDR Console File names
|
2024-01-10 20:44:23 -05:00
|
|
|
else if (sscanf(filename.c_str(),
|
2024-05-15 17:53:20 +02:00
|
|
|
"%d-%3s-%d %2d%2d%2d.%*d %lfMHz",
|
|
|
|
|
&timeS.tm_mday, month_str, &timeS.tm_year,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&freq_mhz) == 7)
|
2024-01-08 15:59:05 -05:00
|
|
|
{
|
|
|
|
|
month_str[3] = '\0';
|
|
|
|
|
if (strcmp(month_str, "Jan") == 0)
|
|
|
|
|
timeS.tm_mon = 0;
|
|
|
|
|
else if (strcmp(month_str, "Feb") == 0)
|
|
|
|
|
timeS.tm_mon = 1;
|
|
|
|
|
else if (strcmp(month_str, "Mar") == 0)
|
|
|
|
|
timeS.tm_mon = 2;
|
|
|
|
|
else if (strcmp(month_str, "Apr") == 0)
|
|
|
|
|
timeS.tm_mon = 3;
|
|
|
|
|
else if (strcmp(month_str, "May") == 0)
|
|
|
|
|
timeS.tm_mon = 4;
|
|
|
|
|
else if (strcmp(month_str, "Jun") == 0)
|
|
|
|
|
timeS.tm_mon = 5;
|
|
|
|
|
else if (strcmp(month_str, "Jul") == 0)
|
|
|
|
|
timeS.tm_mon = 6;
|
|
|
|
|
else if (strcmp(month_str, "Aug") == 0)
|
|
|
|
|
timeS.tm_mon = 7;
|
|
|
|
|
else if (strcmp(month_str, "Sep") == 0)
|
|
|
|
|
timeS.tm_mon = 8;
|
|
|
|
|
else if (strcmp(month_str, "Oct") == 0)
|
|
|
|
|
timeS.tm_mon = 9;
|
|
|
|
|
else if (strcmp(month_str, "Nov") == 0)
|
|
|
|
|
timeS.tm_mon = 10;
|
|
|
|
|
else if (strcmp(month_str, "Dec") == 0)
|
|
|
|
|
timeS.tm_mon = 11;
|
|
|
|
|
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_isdst = -1;
|
|
|
|
|
md.frequency = freq_mhz * 1e6;
|
|
|
|
|
md.timestamp = mktime(&timeS);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-10 20:44:23 -05:00
|
|
|
// SatDump Baseband
|
|
|
|
|
else if (sscanf(filename.c_str(),
|
2024-05-15 17:53:20 +02:00
|
|
|
"%d-%d-%d_%d-%d-%d_%" PRIu64 "SPS_%" PRIu64 "Hz",
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&samp, &freq) == 8)
|
2023-12-01 22:41:32 +01:00
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
|
|
|
|
md.frequency = freq;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2024-01-10 20:44:23 -05:00
|
|
|
|
|
|
|
|
std::string ext = std::filesystem::path(filepath).extension().string();
|
2024-11-27 17:27:12 -05:00
|
|
|
if (ext == ".cf32" || ext == ".cs32" || ext == ".cs16" || ext == ".cs8")
|
2024-01-10 20:44:23 -05:00
|
|
|
md.baseband_format = ext.substr(1);
|
2024-11-27 17:27:12 -05:00
|
|
|
else if (ext == ".f32" || ext == ".s32" || ext == ".s16" || ext == ".s8") // Later, this should input REAL and not complex!
|
2024-05-15 17:53:20 +02:00
|
|
|
md.baseband_format = "c" + ext.substr(1);
|
|
|
|
|
if (ext != ".wav")
|
2024-01-10 20:44:23 -05:00
|
|
|
md.samplerate = samp;
|
2023-12-01 22:41:32 +01:00
|
|
|
}
|
2024-01-10 20:44:23 -05:00
|
|
|
|
|
|
|
|
// SatDump Baseband with milliseconds
|
2023-12-01 22:41:32 +01:00
|
|
|
else if (sscanf(filename.c_str(),
|
2024-05-15 17:53:20 +02:00
|
|
|
"%d-%d-%d_%d-%d-%d-%*d_%" PRIu64 "SPS_%" PRIu64 "Hz",
|
|
|
|
|
&timeS.tm_year, &timeS.tm_mon, &timeS.tm_mday,
|
|
|
|
|
&timeS.tm_hour, &timeS.tm_min, &timeS.tm_sec,
|
|
|
|
|
&samp, &freq) == 8)
|
2023-12-01 22:41:32 +01:00
|
|
|
{
|
|
|
|
|
timeS.tm_year -= 1900;
|
|
|
|
|
timeS.tm_mon -= 1;
|
|
|
|
|
md.frequency = freq;
|
2024-07-24 11:13:35 -04:00
|
|
|
md.timestamp = timegm(&timeS);
|
2024-01-10 20:44:23 -05:00
|
|
|
|
|
|
|
|
std::string ext = std::filesystem::path(filepath).extension().string();
|
2024-05-15 17:53:20 +02:00
|
|
|
if (ext == ".cf32" || ext == ".cs16" || ext == ".cs8")
|
2024-01-10 20:44:23 -05:00
|
|
|
md.baseband_format = ext.substr(1);
|
2024-05-15 17:53:20 +02:00
|
|
|
else if (ext == ".f32" || ext == ".s16" || ext == ".s8") // Later, this should input REAL and not complex!
|
|
|
|
|
md.baseband_format = "c" + ext.substr(1);
|
2024-01-10 20:44:23 -05:00
|
|
|
if (ext != ".wav")
|
|
|
|
|
md.samplerate = samp;
|
2023-12-01 22:41:32 +01:00
|
|
|
}
|
2022-12-10 22:40:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return md;
|
|
|
|
|
}
|
2023-09-08 00:21:38 -04:00
|
|
|
};
|