Skip to content

Commit cf54625

Browse files
committed
API homologation
1 parent 46e1a10 commit cf54625

4 files changed

Lines changed: 45 additions & 31 deletions

File tree

docs/source/converters.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ Converters can be used from the command line after ``pip install sigmf``:
2424

2525
.. code-block:: bash
2626
27-
sigmf_convert_blue input.cdif
28-
sigmf_convert_wav input.wav
27+
sigmf_convert_blue recording.cdif
28+
sigmf_convert_wav recording.wav
2929
3030
or by using module syntax:
3131

3232
.. code-block:: bash
3333
34-
python3 -m sigmf.convert.blue input.cdif
35-
python3 -m sigmf.convert.wav input.wav
34+
python3 -m sigmf.convert.blue recording.cdif
35+
python3 -m sigmf.convert.wav recording.wav
3636
3737
3838
BLUE Converter

sigmf/convert/blue.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def read_extended_header(file_path, h_fixed):
322322
return entries
323323

324324

325-
def write_data(blue_path: Path, out_path: Path, h_fixed: dict) -> np.ndarray:
325+
def data_loopback(blue_path: Path, out_path: Path, h_fixed: dict) -> np.ndarray:
326326
"""
327327
Write SigMF data file from BLUE file samples.
328328
@@ -342,12 +342,17 @@ def write_data(blue_path: Path, out_path: Path, h_fixed: dict) -> np.ndarray:
342342
"""
343343
log.debug("parsing BLUE file data values")
344344

345-
file_size_bytes = os.path.getsize(blue_path)
346-
extended_header_data_size = h_fixed.get("ext_size")
345+
# use header data_size field instead of file size calculation
346+
data_size_bytes = int(h_fixed.get("data_size", 0))
347347
fmt = h_fixed.get("format")
348348

349+
log.debug(f"format: {fmt}, data_size from header: {data_size_bytes} bytes")
350+
349351
# Determine destination path for SigMF data file
350352
dest_path = out_path.with_suffix(".sigmf-data")
353+
print("#" * 80)
354+
print("Writing SigMF data to:", dest_path)
355+
print("#" * 80)
351356

352357
config = DATA_TYPE_CONFIGS[fmt]
353358
np_dtype = config["dtype"]
@@ -356,7 +361,9 @@ def write_data(blue_path: Path, out_path: Path, h_fixed: dict) -> np.ndarray:
356361

357362
# calculate element size and count
358363
elem_size = np.dtype(np_dtype).itemsize
359-
elem_count = (file_size_bytes - extended_header_data_size) // elem_size
364+
elem_count = data_size_bytes // elem_size
365+
366+
log.debug(f"elem_size: {elem_size}, elem_count: {elem_count}, is_complex: {is_complex}")
360367

361368
# read raw samples
362369
raw_samples = np.fromfile(blue_path, dtype=np_dtype, offset=HEADER_SIZE_BYTES, count=elem_count)
@@ -369,6 +376,7 @@ def write_data(blue_path: Path, out_path: Path, h_fixed: dict) -> np.ndarray:
369376
else:
370377
# reassemble interleaved IQ samples
371378
samples = raw_samples[::2] + 1j * raw_samples[1::2]
379+
log.debug(f"Deinterleaved {len(raw_samples)} samples into {len(samples)} complex samples")
372380
else:
373381
# scalar data
374382
samples = raw_samples
@@ -470,21 +478,27 @@ def get_tag(tag):
470478
blue_start_time = float(h_fixed.get("timecode", 0))
471479
blue_start_time += h_adjunct.get("xstart", 0)
472480
blue_start_time += float(h_keywords.get("TC_PREC", 0))
473-
# timecode uses 1950-01-01 as epoch, datetime uses 1970-01-01
474-
blue_epoch = blue_start_time - 631152000 # seconds between 1950 and 1970
475-
# FIXME: I am unsure if the timezone is always UTC in these files
476-
blue_datetime = datetime.fromtimestamp(blue_epoch, tz=timezone.utc)
477481

478-
capture_info = {
479-
SigMFFile.DATETIME_KEY: blue_datetime.strftime(SIGMF_DATETIME_ISO8601_FMT),
480-
}
482+
if blue_start_time == 0:
483+
log.warning("BLUE timecode is zero or missing; datetime metadata will be absent.")
484+
capture_info = {}
485+
else:
486+
# timecode uses 1950-01-01 as epoch, datetime uses 1970-01-01
487+
blue_epoch = blue_start_time - 631152000 # seconds between 1950 and 1970
488+
# FIXME: I am unsure if the timezone is always UTC in these files
489+
blue_datetime = datetime.fromtimestamp(blue_epoch, tz=timezone.utc)
490+
491+
capture_info = {
492+
SigMFFile.DATETIME_KEY: blue_datetime.strftime(SIGMF_DATETIME_ISO8601_FMT),
493+
}
481494

482495
if get_tag("RF_FREQ") is not None:
483496
# FIXME: I believe there are many possible keys related to tune frequency
484497
capture_info[SigMFFile.FREQUENCY_KEY] = float(get_tag("RF_FREQ"))
485498

486499
# actually write to SigMF
487-
filenames = get_sigmf_filenames(out_path)
500+
filenames = get_sigmf_filenames(out_path.stem)
501+
print("dbug", filenames)
488502

489503
meta = SigMFFile(
490504
data_file=filenames["data_fn"],
@@ -582,12 +596,12 @@ def validate_extended_header(entries: list) -> None:
582596
raise SigMFConversionError(f"Invalid SAMPLE_RATE in extended header: {sample_rate}")
583597

584598

585-
def convert_blue(
599+
def blue_to_sigmf(
586600
blue_path: str,
587601
out_path: Optional[str] = None,
588-
) -> np.ndarray:
602+
) -> SigMFFile:
589603
"""
590-
Convert a MIDIS Bluefile to SigMF metadata and data.
604+
Read a MIDAS Bluefile, write to SigMF, return SigMFFile object.
591605
592606
Parameters
593607
----------
@@ -625,7 +639,7 @@ def convert_blue(
625639
h_extended = read_extended_header(blue_path, h_fixed)
626640

627641
# write to SigMF data file
628-
_ = write_data(blue_path, out_path, h_fixed)
642+
_ = data_loopback(blue_path, out_path, h_fixed)
629643

630644
log.debug(">>>>>>>>> Fixed Header")
631645
for key, _, _, _, desc in FIXED_LAYOUT:
@@ -652,7 +666,8 @@ def main() -> None:
652666
Entry-point for sigmf_convert_blue
653667
"""
654668
parser = argparse.ArgumentParser(description=__doc__)
655-
parser.add_argument("input", type=str, help="Blue (cdif) file path")
669+
parser.add_argument("-i", "--input", type=str, required=True, help="BLUE file path")
670+
parser.add_argument("-o", "--output", type=str, default=None, help="SigMF path")
656671
parser.add_argument("-v", "--verbose", action="count", default=0)
657672
parser.add_argument("--version", action="version", version=f"%(prog)s v{toolversion}")
658673
args = parser.parse_args()
@@ -664,4 +679,8 @@ def main() -> None:
664679
}
665680
logging.basicConfig(level=level_lut[min(args.verbose, 2)])
666681

667-
convert_blue(args.input)
682+
_ = blue_to_sigmf(blue_path=args.input, out_path=args.output)
683+
684+
685+
if __name__ == "__main__":
686+
main()

sigmf/convert/wav.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def wav_to_sigmf(
2929
wav_path: str,
3030
out_path: Optional[str] = None,
3131
to_archive: bool = True,
32-
author: Optional[str] = None,
3332
) -> SigMFFile:
3433
"""
3534
Read a wav, write a sigmf, return SigMFFile object.
@@ -47,7 +46,6 @@ def wav_to_sigmf(
4746
np_dtype = f"int{samp_width * 8}"
4847
wav_data = np.frombuffer(raw_data, dtype=np_dtype).reshape(-1, n_channels)
4948
global_info = {
50-
SigMFFile.AUTHOR_KEY: getpass.getuser() if author is None else author,
5149
SigMFFile.DATATYPE_KEY: get_data_type_str(wav_data),
5250
SigMFFile.DESCRIPTION_KEY: f"converted from {wav_path.name}",
5351
SigMFFile.NUM_CHANNELS_KEY: 1 if len(wav_data.shape) < 2 else wav_data.shape[1],
@@ -88,8 +86,8 @@ def main() -> None:
8886
Entry-point for sigmf_convert_wav
8987
"""
9088
parser = argparse.ArgumentParser(description=__doc__)
91-
parser.add_argument("input", type=str, help="wav path")
92-
parser.add_argument("--author", type=str, default=None, help=f"set {SigMFFile.AUTHOR_KEY} metadata")
89+
parser.add_argument("-i", "--input", type=str, required=True, help="WAV path")
90+
parser.add_argument("-o", "--output", type=str, default=None, help="SigMF path")
9391
parser.add_argument("-v", "--verbose", action="count", default=0)
9492
parser.add_argument("--version", action="version", version=f"%(prog)s v{toolversion}")
9593
args = parser.parse_args()
@@ -101,10 +99,7 @@ def main() -> None:
10199
}
102100
logging.basicConfig(level=level_lut[min(args.verbose, 2)])
103101

104-
_ = wav_to_sigmf(
105-
wav_path=args.input,
106-
author=args.author,
107-
)
102+
_ = wav_to_sigmf(wav_path=args.input, out_path=args.output)
108103

109104

110105
if __name__ == "__main__":

tests/test_convert.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def test_wav_to_sigmf(self):
5454
sigmf_path = self.tmp_path / "bar"
5555
meta = wav_to_sigmf(wav_path=self.wav_path, out_path=sigmf_path)
5656
data = meta.read_samples()
57-
# allow numerical differences due to PCM conversion
57+
# allow numerical differences due to PCM quantization
5858
self.assertTrue(np.allclose(self.audio_data, data, atol=1e-4))
5959

6060

0 commit comments

Comments
 (0)