@@ -187,7 +187,7 @@ def __init__(self, uri: Optional[str] = None, modality: Optional[str] = None):
187187 # key: label
188188 # value: timeline
189189 self ._labels : Dict [Label , Timeline ] = {}
190- self ._labelNeedsUpdate : [Label , bool ] = {}
190+ self ._labelNeedsUpdate : Dict [Label , bool ] = {}
191191
192192 # timeline meant to store all annotated segments
193193 self ._timeline : Timeline = None
@@ -364,19 +364,14 @@ def __contains__(self, included: Union[Segment, Timeline]):
364364 """
365365 return included in self .get_timeline (copy = False )
366366
367- def write_rttm (self , file : TextIO ):
368- """Dump annotation to file using RTTM format
369-
370- Parameters
371- ----------
372- file : file object
367+ def _iter_rttm (self ) -> Iterator [Text ]:
368+ """Generate lines for an RTTM file for this annotation
373369
374- Usage
375- -----
376- >>> with open('file.rttm', 'w') as file:
377- ... annotation.write_rttm(file)
370+ Returns
371+ -------
372+ iterator: Iterator[str]
373+ An iterator over RTTM text lines
378374 """
379-
380375 uri = self .uri if self .uri else "<NA>"
381376 if isinstance (uri , Text ) and " " in uri :
382377 msg = (
@@ -391,10 +386,76 @@ def write_rttm(self, file: TextIO):
391386 f'containing spaces (got: "{ label } ").'
392387 )
393388 raise ValueError (msg )
394- line = (
389+ yield (
395390 f"SPEAKER { uri } 1 { segment .start :.3f} { segment .duration :.3f} "
396391 f"<NA> <NA> { label } <NA> <NA>\n "
397392 )
393+
394+ def to_rttm (self ) -> Text :
395+ """Serialize annotation as a string using RTTM format
396+
397+ Returns
398+ -------
399+ serialized: str
400+ RTTM string
401+ """
402+ return "" .join ([line for line in self ._iter_rttm ()])
403+
404+ def write_rttm (self , file : TextIO ):
405+ """Dump annotation to file using RTTM format
406+
407+ Parameters
408+ ----------
409+ file : file object
410+
411+ Usage
412+ -----
413+ >>> with open('file.rttm', 'w') as file:
414+ ... annotation.write_rttm(file)
415+ """
416+ for line in self ._iter_rttm ():
417+ file .write (line )
418+
419+ def _iter_lab (self ) -> Iterator [Text ]:
420+ """Generate lines for a LAB file for this annotation
421+
422+ Returns
423+ -------
424+ iterator: Iterator[str]
425+ An iterator over LAB text lines
426+ """
427+ for segment , _ , label in self .itertracks (yield_label = True ):
428+ if isinstance (label , Text ) and " " in label :
429+ msg = (
430+ f"Space-separated LAB file format does not allow labels "
431+ f'containing spaces (got: "{ label } ").'
432+ )
433+ raise ValueError (msg )
434+ yield f"{ segment .start :.3f} { segment .start + segment .duration :.3f} { label } \n "
435+
436+ def to_lab (self ) -> Text :
437+ """Serialize annotation as a string using LAB format
438+
439+ Returns
440+ -------
441+ serialized: str
442+ LAB string
443+ """
444+ return "" .join ([line for line in self ._iter_lab ()])
445+
446+ def write_lab (self , file : TextIO ):
447+ """Dump annotation to file using LAB format
448+
449+ Parameters
450+ ----------
451+ file : file object
452+
453+ Usage
454+ -----
455+ >>> with open('file.lab', 'w') as file:
456+ ... annotation.write_lab(file)
457+ """
458+ for line in self ._iter_lab ():
398459 file .write (line )
399460
400461 def crop (self , support : Support , mode : CropMode = "intersection" ) -> "Annotation" :
0 commit comments