o
    xim                     @   s   d Z ddlmZmZmZmZmZ ddlmZ ddl	m
Z
mZmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ d
d Zddee
 fddZG dd dejZdS )z`
An IntervalTier is a tier containing an array of intervals -- data that spans a period of time
    )CallableListOptionalTupleSequence)Literal)IntervalINTERVAL_TIERCropCollision)errors)utils)my_math)	constants)textgrid_tierc                 C   s   dd | D }|   |S )z
    Enforces consistency in intervals

    - converts all entries to intervals
    - removes whitespace in labels
    - sorts values by time
    c                 S   s*   g | ]\}}}t t|t|| qS  )r   floatstrip.0startendlabelr   r   e/home/ubuntu/maya3_transcribe/venv/lib/python3.10/site-packages/praatio/data_classes/interval_tier.py
<listcomp>    s    z&_homogenizeEntries.<locals>.<listcomp>)sort)entriesprocessedEntriesr   r   r   _homogenizeEntries   s
   r   Nr   c                 C   sz   dd | D }dd | D }|d ur| t| |d ur$| t| zt|}t|}W ||fS  ty<   t w )Nc                 S      g | ]}|j qS r   r   r   intervalr   r   r   r   )       z+_calculateMinAndMaxTime.<locals>.<listcomp>c                 S   r   r   r   r    r   r   r   r   *   r"   )appendr   minmax
ValueErrorr   TimelessTextgridTierException)r   minTmaxTminTimeListmaxTimeListresolvedMinTresolvedMaxTr   r   r   _calculateMinAndMaxTime(   s   
r/   c                       s  e Zd ZeZeZ		dIdedee de	e
 de	e
 f fddZdd	 Zed
ee
 fddZde
de
ded ded
d f
ddZ	dJdejde
d
ejfddZded
dfddZdKddZ	dLd e
d!ed" d
d fd#d$Z	%	&dMd'e
d(e
d)ed* d+ed
d f
d,d-Zd.ed
eeeef  fd/d0Zd
ee fd1d2Z	%	dNded)ed3 d4ed5 d
dfd6d7Zd'e
d8e
d)ed9 d
d fd:d;ZdOdKd=d>Z	?dPdd d@ed
d fdAdBZ	dQdCd dDe	e egef  d
d fdEdFZ!	dLd!ed" d
efdGdHZ"  Z#S )RIntervalTierNnamer   r)   r*   c                    s:   t |}t|||\}}tt| |||| |   dS )a  An interval tier is for annotating events that have duration

        The entries is of the form:
        [(startTime1, endTime1, label1), (startTime2, endTime2, label2), ]

        The data stored in the labels can be anything but will
        be interpreted as text by praatio (the label could be descriptive
        text e.g. ('erase this region') or numerical data e.g. (average pitch
        values like '132'))
        N)r   r/   superr0   __init__	_validate)selfr1   r   r)   r*   calculatedMinTcalculatedMaxT	__class__r   r   r3   >   s   
zIntervalTier.__init__c                 C   s   | j D ]}|j|jkrtd|j d|j dqt| j dd | j dd D ](\}}|j|jkrQtd|j d|j d|j d	|j d|j d|j dq)dS )
zVAn interval tier is invalid if the entries are out of order or overlap with each otherzThe start time of an interval (z#) cannot occur after its end time ()r   N   z1Two intervals in the same tier overlap in time:
(, z) and ()r   r   r   r   TextgridStateErrorzipr   )r5   entry	nextEntryr   r   r   r4   W   s6   

&zIntervalTier._validatereturnc                 C   s(   dd | j D }tt|}|  |S )z'All unique timestamps used in this tierc                 S   s$   g | ]\}}}||fD ]}|qqS r   r   )r   r   stop_timer   r   r   r   k   s    z+IntervalTier.timestamps.<locals>.<listcomp>)r   listsetr   )r5   tmpTimestampsuniqueTimestampsr   r   r   
timestampsh   s   	zIntervalTier.timestamps	cropStartcropEndmode)strictlax	truncatedrebaseToZeroc           
         s   t d|t ||krtd| d| dt ||| j|}|du rC|d d }||k r1| n|  fdd|D }d	}|| }n|}|}t| j|||}	|	S )
a  Creates a new tier with all entries that fit inside the new interval

        Args:
            cropStart:
            cropEnd:
            mode: determines cropping behavior
                - 'strict', only intervals wholly contained by the crop
                    interval will be kept
                - 'lax', partially contained intervals will be kept
                - 'truncated', partially contained intervals will be
                    truncated to fit within the crop region.
            rebaseToZero: if True, the cropped textgrid values
                will be subtracted by the cropStart

        Returns:
            the modified version of the current tier
        rL   zCrop error: start time (z) must occur before end time (r:   Tr   c                    s&   g | ]\}}}t |  |  |qS r   )r   r   timeDiffr   r   r      s    z%IntervalTier.crop.<locals>.<listcomp>g        )	r   validateOptionr
   r   ArgumentErrorgetIntervalsInIntervalr   r0   r1   )
r5   rJ   rK   rL   rP   newEntryListnewSmallestValuer)   r*   croppedTierr   rQ   r   cropy   s,   


zIntervalTier.cropMbP?referenceTiermaxDifferencec                    s   |j }g }| jD ]9\ }t| fddd}t|fddd}tt | |r-| tt| |r9|| |f q| j|dS )aC  
        Set timestamps in this tier to be the same as values in the reference tier

        Timestamps will only be moved if they are less than maxDifference away from the
        reference time.

        This can be used to correct minor alignment errors between tiers, as made when
        annotating files manually, etc.

        Args:
            referenceTier: the IntervalTier or PointTier to use as a reference
            maxDifference: the maximum amount to allow timestamps to be moved by

        Returns:
            the modified version of the current tier
        c                       t |   S Nabsxr   r   r   <lambda>       z'IntervalTier.dejitter.<locals>.<lambda>)keyc                    r]   r^   r_   ra   )rB   r   r   rc      rd   r   )rI   r   r%   r   lessThanOrEqualr`   r$   new)r5   r[   r\   referenceTimestamps
newEntriesr   startComparestopComparer   )r   rB   r   dejitter   s   zIntervalTier.dejitterr?   c                 C   s   | j | j | dS )z!Removes an entry from the entriesN)_entriespopindex)r5   r?   r   r   r   deleteEntry   s   zIntervalTier.deleteEntrytierc                 C   s2   |   }|jD ]}|j|j|jtjjdd}q|S )aF  Takes the set difference of this tier and the given one

        Any overlapping portions of entries with entries in this textgrid
        will be removed from the returned tier.

        Args:
            tier: the tier to subtract from this one

        Returns:
            the modified version of the current tier
        F)collisionModedoShrink)rh   r   eraseRegionr   r   r   EraseCollisionTRUNCATE)r5   rr   retTierr?   r   r   r   
difference   s   
zIntervalTier.differencewarningoffsetreportingMode)silencerz   errorc           
      C   s   t d|tj t |}g }| jD ]1}||j }||j }t || j	| t 
|| j| |dkr3q|dk r9d}|t|||j qtdd |D }tdd |D }	|| j	kr^| j	}|	| jk rf| j}	t| j|||	S )aS  Modifies all timestamps by a constant amount

        Args:
            offset: the amount to shift all intervals
            reportingMode: Determines the behavior if an entries moves outside
                of minTimestamp or maxTimestamp after being edited

        Returns:
            the modified version of the current tier
        r|   r   c                 S   r   r   r   r    r   r   r   r     r"   z/IntervalTier.editTimestamps.<locals>.<listcomp>c                 S   r   r   r#   r    r   r   r   r     r"   )r   rS   r   ErrorReportingModegetErrorReporterr   r   r   checkIsUndershootminTimestampcheckIsOvershootmaxTimestampr$   r   r   r%   r&   r0   r1   )
r5   r{   r|   errorReporterrV   r!   newStartnewEndnewMinnewMaxr   r   r   editTimestamps   s,   





zIntervalTier.editTimestampsr~   Tr   r   rs   )truncatecategoricalr~   rt   c                 C   s  t d|tj | ||tjdj}|  }t	|dkrnW|tjj
kr/td| d| d|ddd D ]}|| q6|tjjkrt|d j|k r\t|d j||d j}|| |d j|krtt||d j|d j}|| |d	u r|| }	g }
|jD ]"}|j|kr|
| q|j|kr|
t|j|	 |j|	 |j qtdt	|
d
 D ]I}|
| j|k}|
|d
  j|k}|
| j|
|d
  jk}|r|r|rt|
| j|
|d
  j|
| j}|
|d
  |
| |
||  nq|j|	 }|j|
|d}|S )aI  Makes a region in a tier blank (removes all contained entries)

        Args:
            start:
            end:
            collisionMode: Determines the behavior when the region to erase
                overlaps with existing intervals.
                - 'truncate' partially contained entries will have the portion
                    removed that overlaps with the target entry
                - 'categorical' all entries that overlap, even partially, with
                    the target entry will be completely removed
                - None or any other value throws IntervalCollision
            doShrink: If True, moves leftward by (/end/ - /start/)
                amount, each item that occurs after /end/

        Returns:
            The modified version of the current tier

        Raises:
            CollisionError
        rs   Fr   zErase region (r<   zV)overlapped with an interval. If this was expected, consider setting the collisionModeNTr;   r   r   )r   rS   r   rv   rY   r
   LAXr   rh   lenERRORr   CollisionErrorrq   rw   r   r   r   insertEntryr   r$   rangero   insertr   )r5   r   r   rs   rt   	matchListnewTierr!   newEntrydiffrV   i	rightEdgeleftEdge	sameLabelnewIntervalr   r   r   r   ru      sb   







zIntervalTier.eraseRegiondataTupleListc                 C   s4   g }| j D ]}t||j|j}|||f q|S )a  Returns data from dataTupleList contained in labeled intervals

        Each labeled interval will get its own list of data values.

        dataTupleList should be of the form:
        [(time1, value1a, value1b,...), (time2, value2a, value2b...), ...]
        )r   r   getValuesInIntervalr   r   r$   )r5   r   
returnListr!   intervalDataListr   r   r   getValuesInIntervals  s   	

z!IntervalTier.getValuesInIntervalsc                    s   | j   fddtt d D }dd |D } d jdkr-|dtd d jd  d j| jk rB|t d j| jd dd |D }|S )	zReturns the regions of the textgrid without labels

        This can include unlabeled segments and regions marked as silent.
        c                    s(   g | ]}t  | j |d   jdqS )r;    )r   r   r   )r   r   rf   r   r   r     s    z.IntervalTier.getNonEntries.<locals>.<listcomp>r;   c                 S   s   g | ]
}|j |jk r|qS r   )r   r   r    r   r   r   r     s    r   r   r   c                 S   s"   g | ]}t |tr|nt| qS r   )
isinstancer   r    r   r   r   r     s    )	r   r   r   r   r   r   r   r   r$   )r5   invertedEntryListr   rf   r   getNonEntries  s   
zIntervalTier.getNonEntries)replacemerger~   collisionReportingMode)r}   rz   c           	      C   s  t d|tj t d|tj t |}t|tst| }n|}| |j	|j
tjdj}t|dkr:| j| nq|tjjkrQ|D ]}| | qB| j| nZ|tjjkr|D ]}| | qY|| |  ttdd |D tdd |D dd	d |D }| j| ntd
|j	 d|j
 d|j d| j ddd |D  d|   | jd d | jk r| jd d | _| jd d | jkr| jd d | _t|dkr|tjd| d| d| j d dS dS )ai  Inserts an interval into the tier

        Args:
            entry: the Interval to insert
            collisionMode: determines the behavior in the event that intervals
                exist in the insertion area.
                - 'replace' will remove existing items
                - 'merge' will fuse the inserting item with existing items
                - None or any other value will throw a CollisionError
            collisionReportingMode: Determines the behavior if the new entry
                overlaps with an existing one

        Returns:
            the modified version of the current tier
        rs   r   Fr   c                 S   r   r   r   r   tmpIntervalr   r   r   r     r"   z,IntervalTier.insertEntry.<locals>.<listcomp>c                 S   r   r   r#   r   r   r   r   r     r"   -c                 S   r   r   r   r   r   r   r   r     r"   zAttempted to insert interval (r<   z, 'z') into tier z% of textgrid but overlapping entries c                 S   s   g | ]}t |qS r   )tupler    r   r   r   r     s    z already existr   r;   zCollision warning for (z) with items (z) of tier ''N)r   rS   r   IntervalCollisionr   r   r   r   rY   r   r   r
   r   rn   r   r$   REPLACErq   MERGEr   r%   r&   joinr   r   r   r1   r   r   )	r5   r?   rs   r   collisionReporterr!   r   
matchEntryr   r   r   r   r     s|   



zIntervalTier.insertEntryduration)stretchsplit	no_changer~   c              
   C   s:  t d|tj g }| jD ]}|j|kr|| q|j|kr0|t|j| |j| |j	 q|j|kr|j|kr|tjj
krO|t|j|j| |j	 q|tjjkrs|t|j||j	 ||| || |j|  |j	f q|tjjkr|| qtd| d| d||  dq| j|| j| d}|S )a  Inserts a blank region into the tier

        Args:
            start:
            duration:
            collisionMode: Determines the behavior that occurs if
                an interval stradles the starting point
                - 'stretch' stretches the interval by /duration/ amount
                - 'split' splits the interval into two--everything to the
                    right of 'start' will be advanced by 'duration' seconds
                - 'no change' leaves the interval as is with no change
                - 'error' will stop execution and raise an error

        Returns:
            the modified version of the current tier
        rs   z5Collision occured during insertSpace() for interval 'z,' and given white space insertion interval (r<   r:   r   )r   rS   r   WhitespaceCollisionr   r   r$   r   r   r   STRETCHSPLIT	NO_CHANGEr   rT   rh   r   )r5   r   r   rs   rV   r!   r   r   r   r   insertSpace  sX   



zIntervalTier.insertSpacer   c                    sh   g }|j D ]| jjtjd} fdd|j D }|| q| j d|j }| ||}|S )a  Takes the set intersection of this tier and the given one

        - The output will contain one interval for each overlapping pair
          e.g. [(1, 2, 'foo')] and [(1, 1.3, 'bang'), (1.7, 2, 'wizz')]
                -> [(1, 1.3, 'foo-bang'), (1.7, 2, 'foo-wizz')]
        - Only intervals that exist in both tiers will remain in the returned tier.
          e.g. [(1, 2, 'foo'), (3, 4, 'bar')] and [(1, 2, 'bang'), (2, 3, 'wizz')]
                -> [(1, 2, 'foo-bang')]
        - If intervals partially overlap, only the overlapping portion will be returned.
          e.g. [(1, 2, 'foo')] and [(0.5, 1.5, 'bang')]
                -> [(1, 1.5, 'foo-bang')]

        Compare with IntervalTier.mergeLabels

        Args:
            tier: the tier to intersect with
            demarcator: the character to separate the labels of the overlapping intervals

        Returns:
            IntervalTier: the modified version of the current tier
        Fc                    s*   g | ]}|j |j|j   j fqS r   )r   r   r   )r   subInterval
demarcatorr!   r   r   r   q  s    z-IntervalTier.intersection.<locals>.<listcomp>r   )	r   rY   r   r   r
   	TRUNCATEDextendr1   rh   )r5   rr   r   retEntryListsubTiersubEntryListnewNamerx   r   r   r   intersectionT  s   
	zIntervalTier.intersection,r   c                 C   s   g }| j D ]G}||j|jtjd}t|jdkrq|dd |j D }|j	 d| d}t
|j|jd j}t|j|jd j}	||	|f}
||
 q| j d|j }| ||}|S )	a@  Merges labels of overlapping tiers into this tier

        - All intervals in this tier will appear in the output; for the given tier, only intervals
          that overlap with content in this tier will appear in the output
          e.g. [(1, 2, 'foo'), (3, 4, 'bar')] and [(1, 2, 'bang'), (2, 3, 'wizz')]
                -> [(1, 2, 'foo(bang)'), (3, 4, 'bar()')]
        - If multiple entries exist in a subinterval, their labels will be concatenated
          e.g. [(1, 2, 'hi')] and [(1, 1.5, 'h'), (1.5, 2, 'ai')] -> [(1, 2, 'hi(h,ai)')]

        compare with IntervalTier.intersection

        Args:
            tier: the tier to intersect with
            demarcator: the string to separate items that fall in the same subinterval

        Returns:
            IntervalTier: the modified version of the current tier
        Fr   c                 S   r   r   r   )r   r?   r   r   r   r     r"   z,IntervalTier.mergeLabels.<locals>.<listcomp>(r:   r   r   )r   rY   r   r   r
   r   r   rn   r   r   r%   r&   r$   r1   rh   )r5   rr   r   r   r!   r   subLabelr   r   r   intersectedIntervalr   rx   r   r   r   mergeLabels  s&   
zIntervalTier.mergeLabels
targetTier
filterFuncc                 C   s   d}g }| j |j g}t|dD ]7\}}|j| }|j|j }	|du s(||jr9|j|j }
||
|	 7 }||
 }n||	 }|t|||j q| j}|d j| j d j }| j	| }t
| j|||S )a  Morphs the duration of segments in this tier to those in another

        This preserves the labels and the duration of silence in
        this tier while changing the duration of labeled segments.

        Args:
            targetTier:
            filterFunc: if specified, filters entries. The
                functor takes one argument, an Interval. It returns true
                if the Interval should be modified and false if not.

        Returns:
            The modified version of the current tier
        r   TNr   )r   r   safeZipr   r   r   r$   r   r   r   r0   r1   )r5   r   r   cumulativeAdjustAmountrV   allIntervalssourceIntervaltargetIntervalr   currIntervalDurationnewIntervalDurationr   r   cumulativeDifferencer   r   r   r   morph  s    


zIntervalTier.morphc                 C   s   t d|tj t |}d}d}| jD ]C}|j|jkr(d}|tj	d| d |r?|j|jkr?d}|tj	d| d| d	 t 
|j| j|rJd}t |j| j|rUd}|}q|S )
zValidate this tier

        Args:
            reportingMode (str): Determines the behavior if validation fails.

        Returns:
            True if the tier is valid; False if not
        r|   TNFz>Invalid interval. End time occurs before or on the start time(z).z$Intervals are not sorted in time: [(z), (z)])r   rS   r   r   r   r   r   r   r   r=   r   r   r   r   )r5   r|   r   isValidpreviousIntervalr!   r   r   r   validate  s>   



zIntervalTier.validateNN)rZ   )rr   r0   rA   r0   )rz   )r~   T)r~   rz   )r   )r   r^   )$__name__
__module____qualname__r	   tierTyper   	entryTypestrr   r   r   r3   r4   propertyrI   r   boolrY   r   TextgridTierrm   rq   ry   r   ru   r   r   r   r   r   r   r   r   r   r   __classcell__r   r   r8   r   r0   :   s    
;
$

3
e!
U
I/
4
,r0   r   )__doc__typingr   r   r   r   r   typing_extensionsr   praatio.utilities.constantsr   r	   r
   praatio.utilitiesr   r   r   r   praatio.data_classesr   r   r/   r   r0   r   r   r   r   <module>   s    