| import cv2 |
| import random |
| import copy |
| from pyannote.core import Annotation, Segment |
| import numpy as np |
| import soundfile as sf |
| import torch |
| import torchaudio |
| import pandas as pd |
| import datetime as dt |
|
|
| def colors(n): |
| ''' |
| Creates a list size n of distinctive colors |
| |
| Creates an arbitrary amount of distinctive colors in RGB format, evenly divided among hues (see HSV). |
| In practice, this proves to be fairly resistant to colorblindness as well. |
| |
| Parameters |
| ---------- |
| n : int |
| Number of distinctive colors required |
| |
| Returns |
| ------- |
| ret : list |
| List of colors in (BGR) format |
| ''' |
| if n == 0: |
| return [] |
| ret = [] |
| |
| h = int(random.random() * 180) |
| |
| step = 180 / n |
| |
| for i in range(n): |
| h += step |
| h = int(h) % 180 |
| hsv = np.uint8([[[h,200,200]]]) |
| bgr = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR) |
| ret.append((bgr[0][0][0].item()/255,bgr[0][0][1].item()/255,bgr[0][0][2].item()/255)) |
| return ret |
|
|
| def colorsCSS(n): |
| ''' |
| Creates a list size n of distinctive colors |
| |
| Creates an arbitrary amount of distinctive colors in CSS format, evenly divided among hues (see HSV). |
| In practice, this proves to be fairly resistant to colorblindness as well. |
| |
| Parameters |
| ---------- |
| n : int |
| Number of distinctive colors required |
| |
| Returns |
| ------- |
| ret : list |
| List of colors in CSS format |
| ''' |
| if n == 0: |
| return [] |
| ret = [] |
| |
| h = int(random.random() * 180) |
| |
| step = 180 / n |
| |
| for i in range(n): |
| h += step |
| h = int(h) % 180 |
| hsv = np.uint8([[[h,200,200]]]) |
| bgr = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR) |
| b = f'{bgr[0][0][0].item():02x}' |
| g = f'{bgr[0][0][1].item():02x}' |
| r = f'{bgr[0][0][2].item():02x}' |
| ret.append('#'+b+g+r) |
| return ret |
| |
| def extendSpeakers(mySpeakerList, fileLabel = 'NONE', maximumSecondDifference = 1, minimumSecondDuration = 0): |
| ''' |
| (DEPRECATED) |
| Extends speaker Segments for Instructor/Audience split data stored as a list |
| ''' |
| mySpeakerAnnotations = Annotation(uri=fileLabel) |
| newSpeakerList = [[],[]] |
| |
| for i, speaker in enumerate(mySpeakerList): |
| |
| speaker.sort() |
| lastEnd = -1 |
| tempSection = None |
| |
| for section in speaker: |
| if lastEnd == -1: |
| tempSection = copy.deepcopy(section) |
| lastEnd = section[0] + section[1] |
| else: |
| if section[0] - lastEnd <= maximumSecondDifference: |
| tempSection = (tempSection[0],max(section[0] + section[1] - tempSection[0],tempSection[1])) |
| lastEnd = tempSection[0] + tempSection[1] |
| else: |
| if tempSection[1] >= minimumSecondDuration: |
| newSpeakerList[i].append(tempSection) |
| mySpeakerAnnotations[Segment(tempSection[0],lastEnd)] = i |
| tempSection = copy.deepcopy(section) |
| lastEnd = section[0] + section[1] |
| if tempSection is not None: |
| |
| if tempSection[1] >= minimumSecondDuration: |
| newSpeakerList[i].append(tempSection) |
| mySpeakerAnnotations[Segment(tempSection[0],lastEnd)] = i |
| return newSpeakerList,mySpeakerAnnotations |
|
|
| def twoClassExtendAnnotation(myAnnotation,maximumSecondDifference = 1, minimumSecondDuration = 0): |
| ''' |
| (DEPRECATED) |
| Extends speaker Segments for Instructor/Audience split data stored as an Annotation |
| ''' |
| lecturerID = None |
| lecturerLen = 0 |
| |
| |
| for speakerName in myAnnotation.labels(): |
| tempLen = len(myAnnotation.label_support(speakerName)) |
| if tempLen > lecturerLen: |
| lecturerLen = tempLen |
| lecturerID = speakerName |
|
|
| tempSpeakerList = [[],[]] |
| |
| for speakerName in myAnnotation.labels(): |
| if speakerName != lecturerID: |
| for segmentItem in myAnnotation.label_support(speakerName): |
| tempSpeakerList[1].append((segmentItem.start,segmentItem.duration)) |
| else: |
| for segmentItem in myAnnotation.label_support(speakerName): |
| tempSpeakerList[0].append((segmentItem.start,segmentItem.duration)) |
| |
| newList, newAnnotation = extendSpeakers(tempSpeakerList, fileLabel = myAnnotation.uri, maximumSecondDifference = maximumSecondDifference, minimumSecondDuration = minimumSecondDuration) |
|
|
| return newList, newAnnotation |
|
|
| def loadAudioRTTM(sampleRTTM): |
| ''' |
| Loads RTTM file in as list of (speaker times) and as Annotation |
| |
| ... |
| |
| Parameters |
| ---------- |
| sampleRTTM : str |
| Full path to RTTM file to read |
| |
| Returns |
| ------- |
| speakerList : list |
| List of speakers as (List of times). Outer list represents speakers, inner list contains (start time, duration) speech segments |
| prediction : pyannote.core.Annotation |
| Annotation object containing RTTM data |
| ''' |
| |
| |
| speakerList = [] |
| |
| prediction = Annotation(uri=sampleRTTM) |
| with open(sampleRTTM, "r") as rttm: |
| |
| for line in rttm: |
| |
| speakerResult = line.split(' ') |
| |
| index = int(speakerResult[7][-2:]) |
| |
| start = float(speakerResult[3]) |
| end = start + float(speakerResult[4]) |
| |
| while len(speakerList) < index + 1: |
| speakerList.append([]) |
| |
| speakerList[index].append((float(speakerResult[3]),float(speakerResult[4]))) |
| prediction[Segment(start,end)] = speakerResult[7] |
|
|
| return speakerList, prediction |
|
|
| def loadAudioTXT(sampleTXT): |
| ''' |
| Loads specially formatted TXT file in as list of (speaker times) and as Annotation |
| |
| File to be read should be formatted with rows as: |
| (start time in seconds)\t(end time in seconds)\t(speaker ID) |
| |
| Parameters |
| ---------- |
| sampleTXT : str |
| Full path to specially formatted TXT file to read |
| |
| Returns |
| ------- |
| [] : list (DEPRECATED) |
| Empty list placeholder |
| prediction : pyannote.core.Annotation |
| Annotation object containing RTTM data |
| ''' |
| prediction = Annotation(uri=sampleTXT) |
| with open(sampleTXT, "r") as txt: |
| |
| for line in txt: |
| |
| speakerResult = line.split('\t') |
| |
| print(speakerResult) |
| |
| if len(speakerResult) < 3: |
| continue |
| start = float(speakerResult[0]) |
| end = float(speakerResult[1]) |
| prediction[Segment(start,end)] = speakerResult[2] |
|
|
| return [], prediction |
|
|
| def loadAudioCSV(sampleCSV): |
| ''' |
| Loads specially formatted CSV file in as list of (speaker times) and as Annotation |
| |
| File to be read should be formatted with first row containing: |
| Start,Finish,Resource |
| These headers represent start time, end time, and speaker ID. |
| |
| Parameters |
| ---------- |
| sampleCSV : str |
| Full path to specially formatted CSV file to read |
| |
| Returns |
| ------- |
| [] : list (DEPRECATED) |
| Empty list placeholder |
| prediction : pyannote.core.Annotation |
| Annotation object containing RTTM data |
| ''' |
| |
| df = pd.read_csv(sampleCSV) |
| |
| df = df.reset_index() |
| |
| |
| prediction = Annotation(uri=sampleCSV) |
| |
| for i, row in df.iterrows(): |
| index = row['Resource'] |
| start = row['Start'] |
| end = row['Finish'] |
| prediction[Segment(start,end)] = index |
|
|
| return [], prediction |
| |
| def splitIntoTimeSegments(testFile,maxDurationInSeconds=60): |
| ''' |
| Read audio file and split into specified chunks of time |
| |
| Reads in audio file and batches audio waveform based on time provided. Useful if the entire audio cannot be loaded simultaneously, as it can be processed in batches. |
| |
| Parameters |
| ---------- |
| testFile : str |
| Full path to audio file |
| maxDurationInSeconds : float or int |
| The max length of time for each chunk. Keep in mind that the final chunk will usually be smaller |
| |
| Returns |
| ------- |
| audioSegments : list |
| List of waveform values, chunked to time specified |
| sample_rate : int |
| Sample rate of the audio file |
| ''' |
| |
| data, sample_rate = sf.read(testFile, dtype="float32", always_2d=True) |
| |
| waveform = torch.from_numpy(data.T) |
| |
| audioSegments = [] |
| outOfBoundsIndex = waveform.shape[-1] |
| currentStart = 0 |
| |
| currentEnd = min(maxDurationInSeconds * sample_rate,outOfBoundsIndex) |
| done = False |
| while(not done): |
| |
| waveformSegment = waveform[:,currentStart:currentEnd] |
| audioSegments.append(waveformSegment) |
| |
| if currentEnd >= outOfBoundsIndex: |
| done = True |
| break |
| else: |
| |
| currentStart = currentEnd |
| currentEnd = min(currentStart + maxDurationInSeconds * sample_rate,outOfBoundsIndex) |
| return audioSegments, sample_rate |
|
|
| def audioNormalize(waveform,sampleRate,stepSizeInSeconds = 2,dbThreshold = -50,dbTarget = -5): |
| ''' |
| Normalize audio loudness based on decibels |
| |
| ... |
| |
| Parameters |
| ---------- |
| waveform : np.array |
| Audio waveform |
| sampleRate : int |
| Sample rate of source audio file |
| stepSizeInSeconds : float or int |
| Window to apply normalization to |
| dbThreshold : int |
| Minimum decibel level to consider below 80 |
| dbTarget : int |
| Maximum decibel level for normalization below 80 |
| |
| Returns |
| ------- |
| copyWaveform : np.array |
| Normalized audio waveform |
| ''' |
| print("In audioNormalize") |
| |
| copyWaveform = waveform.clone().detach() |
| print("Waveform copy made") |
| |
| transform = torchaudio.transforms.AmplitudeToDB(stype="amplitude", top_db=80) |
| |
| currStart = 0 |
| currEnd = int(min(currStart + stepSizeInSeconds * sampleRate, len(copyWaveform[0])-1)) |
| done = False |
| while(not done): |
| |
| copyWaveform_db = waveform[:,currStart:currEnd].clone().detach() |
| copyWaveform_db = transform(copyWaveform_db) |
| if currStart == 0: |
| print("First DB level calculated") |
| |
| |
| if torch.max(copyWaveform_db[0]).item() > dbThreshold: |
| |
| gain = torch.min(dbTarget - copyWaveform_db[0]) |
| adjustGain = torchaudio.transforms.Vol(gain,'db') |
| |
| copyWaveform[0][currStart:currEnd] = adjustGain(copyWaveform[0][currStart:currEnd]) |
| |
| if len(copyWaveform_db) > 1: |
| if torch.max(copyWaveform_db[1]).item() > dbThreshold: |
| |
| gain = torch.min(dbTarget - copyWaveform_db[1]) |
| adjustGain = torchaudio.transforms.Vol(gain,'db') |
| |
| copyWaveform[1][currStart:currEnd] = adjustGain(copyWaveform[1][currStart:currEnd]) |
| |
| currStart += int(stepSizeInSeconds * sampleRate) |
| if currStart > currEnd: |
| done = True |
| else: |
| currEnd = int(min(currStart + stepSizeInSeconds * sampleRate, len(copyWaveform[0])-1)) |
| print("Waveform enhanced") |
| return copyWaveform |
|
|
| class equalizeVolume(torch.nn.Module): |
| ''' |
| Torch Module wrapper for equalization |
| ''' |
| def forward(self, waveform,sampleRate,stepSizeInSeconds,dbThreshold,dbTarget): |
| print("In equalizeVolume") |
| waveformDifference = audioNormalize(waveform,sampleRate,stepSizeInSeconds,dbThreshold,dbTarget) |
| return waveformDifference |
|
|
| def combineWaveforms(waveformList): |
| ''' |
| Combines waveform that has been split into batches (see splitIntoTimeSegments()) |
| |
| Parameters |
| ---------- |
| waveformList : list |
| List of waveform segments to merge |
| |
| Returns |
| ------- |
| : np.array |
| Concatenated waveform |
| ''' |
| return torch.cat(waveformList,1) |
|
|
| def annotationToSpeakerList(myAnnotation): |
| ''' |
| Converts pyannote.core.Annotation object into List of speakers with times for easy processing of matplotlib charts. |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Diarization object |
| |
| Returns |
| ------- |
| tempSpeakerList : list |
| List of speakers with (list of (start time, duration)). Outer list represents speakers, inner list contains time start and end. |
| ''' |
| tempSpeakerList = [] |
| tempSpeakerNames = [] |
| |
| for speakerName in myAnnotation.labels(): |
| speakerIndex = None |
| |
| if speakerName not in tempSpeakerNames: |
| |
| speakerIndex = len(tempSpeakerNames) |
| tempSpeakerNames.append(speakerName) |
| tempSpeakerList.append([]) |
| else: |
| |
| speakerIndex = tempSpeakerNames.index(speakerName) |
|
|
| |
| for segmentItem in myAnnotation.label_support(speakerName): |
| tempSpeakerList[speakerIndex].append((segmentItem.start,segmentItem.duration)) |
| return tempSpeakerList |
|
|
| def speakerListToDataFrame(speakerList): |
| ''' |
| Convert speaker list to pandas.DataFrame object |
| |
| ... |
| |
| Parameters |
| ---------- |
| speakerList : list |
| List of speakers with (list of (start time, duration)). Outer list represents speakers, inner list contains time start and end. |
| |
| Returns |
| ------- |
| df : pandas.DataFrame |
| DataFrame representation of input |
| ''' |
| dataList = [] |
| |
| for j, row in enumerate(speakerList): |
| |
| for k, speakingPoint in enumerate(row): |
| |
| h0 = int(speakingPoint[0]//3600) |
| m0 = int(speakingPoint[0]%3600//60) |
| s0 = int(speakingPoint[0]%60) |
| ms0 = int(speakingPoint[0]*1000000%1000000) |
| time0 = dt.time(h0,m0,s0,ms0) |
| |
| dtStart = dt.datetime.combine(dt.date.today(), time0) |
| |
| endPoint = speakingPoint[0] + speakingPoint[1] |
| h1 = int(endPoint//3600) |
| m1 = int(endPoint%3600//60) |
| s1 = int(endPoint%60) |
| ms1 = int(endPoint*1000000%1000000) |
| time1 = dt.time(h1,m1,s1,ms1) |
| |
| dtEnd = dt.datetime.combine(dt.date.today(), time1) |
| |
| dataList.append(dict(Task=f"Speaker {j}.{k}", Start=dtStart, Finish=dtEnd, Resource=f"Speaker {j+1}")) |
| df = pd.DataFrame(dataList) |
| return df |
|
|
| def removeOverlap(timeSegment,overlap): |
| ''' |
| Removes overlap (if any) from two segments of time |
| |
| ... |
| |
| Parameters |
| ---------- |
| timeSegment : pyannote.core.Segment |
| Segment to remove overlap from |
| overlap : pyannote.core.Segment |
| Segment to apply as overlap mask |
| |
| Returns |
| ------- |
| times : list |
| List of up to two Segments |
| ''' |
| times = [] |
| |
| if timeSegment.start < overlap.start: |
| |
| |
| |
| |
| |
| times.append(Segment(timeSegment.start,min(overlap.start,timeSegment.end))) |
| |
| if timeSegment.end > overlap.end: |
| |
| |
| |
| |
| |
| times.append(Segment(max(timeSegment.start,overlap.end),timeSegment.end)) |
| return times |
|
|
| def checkForOverlap(time1, time2): |
| ''' |
| Checks for overlap of two pyannote.core.Segments |
| |
| ... |
| |
| Parameters |
| ---------- |
| time1 : pyannote.core.Segment |
| First Segment to check |
| time2 : pyannote.core.Segment |
| Second Segment to check |
| |
| Returns |
| ------- |
| overlap : Segment |
| Overlapping Segment, or None if none exists |
| ''' |
| overlap = time1 & time2 |
| if overlap: |
| return overlap |
| else: |
| return None |
| |
| def sumSegments(segmentList): |
| ''' |
| Adds up all durations of provided Segments in list |
| |
| ... |
| |
| Parameters |
| ---------- |
| segmentList : list |
| List of pyannote.core.Segment |
| |
| Returns |
| ------- |
| total : float or int |
| Total duration of all Segments |
| ''' |
| total = 0 |
| for s in segmentList: |
| total += s.duration |
| return total |
|
|
| def sumTimes(myAnnotation): |
| ''' |
| Calculates duration of pyannote.core.Annotation |
| |
| ... |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Target Annotation |
| |
| Returns |
| ------- |
| : float |
| Duration in seconds of Annotation |
| ''' |
| return myAnnotation.get_timeline(False).duration() |
| |
| def sumTimesPerSpeaker(myAnnotation): |
| ''' |
| Calculates duration of each speaker in pyannote.core.Annotation |
| |
| ... |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Target Annotation |
| |
| Returns |
| ------- |
| speakerList : list |
| List of speakers |
| timeList : list |
| List of times matching speakerList |
| ''' |
| speakerList = [] |
| timeList = [] |
| |
| for speaker in myAnnotation.labels(): |
| |
| if speaker not in speakerList: |
| speakerList.append(speaker) |
| timeList.append(0) |
| |
| timeList[speakerList.index(speaker)] += sumTimes(myAnnotation.subset([speaker])) |
| return speakerList, timeList |
| |
| def sumMultiTimesPerSpeaker(myAnnotation): |
| ''' |
| Calculates duration of each speaker in pyannote.core.Annotation, including multi-speaker labels |
| |
| Multi-speaker labels can be identified as a str delimited with '+' for each speaker |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Target Annotation |
| |
| Returns |
| ------- |
| speakerList : list |
| List of speakers |
| timeList : list |
| List of times matching speakerList |
| ''' |
| speakerList = [] |
| timeList = [] |
| |
| sList,tList = sumTimesPerSpeaker(myAnnotation) |
| |
| for i,speakerGroup in enumerate(sList): |
| |
| speakerSplit = speakerGroup.split('+') |
| |
| for speaker in speakerSplit: |
| |
| if speaker not in speakerList: |
| speakerList.append(speaker) |
| timeList.append(0) |
| |
| timeList[speakerList.index(speaker)] += tList[i] |
| return speakerList, timeList |
|
|
| def annotationToDataFrame(myAnnotation): |
| ''' |
| Convert pyannote.core.Annotation to specially formatted pandas.DataFrame object |
| |
| ... |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Diarization representation |
| |
| Returns |
| ------- |
| df : pandas.DataFrame |
| DataFrame representation of input |
| timeSummary : dict |
| Maps speakers to duration spoken |
| ''' |
| dataList = [] |
| speakerDict = {} |
| |
| for currSpeaker in myAnnotation.labels(): |
| |
| if currSpeaker not in speakerDict.keys(): |
| speakerDict[currSpeaker] = [] |
| |
| for currSegment in myAnnotation.subset([currSpeaker]).itersegments(): |
| speakerDict[currSpeaker].append(currSegment) |
|
|
| timeSummary = {} |
| |
| for key in speakerDict.keys(): |
| |
| if key not in timeSummary.keys(): |
| timeSummary[key] = 0 |
| |
| for speakingSegment in speakerDict[key]: |
| timeSummary[key] += speakingSegment.duration |
|
|
| |
| for key in speakerDict.keys(): |
| |
| for k, speakingSegment in enumerate(speakerDict[key]): |
| |
| speakerName = key |
| startPoint = speakingSegment.start |
| endPoint = speakingSegment.end |
| |
| h0 = int(startPoint//3600) |
| m0 = int(startPoint%3600//60) |
| s0 = int(startPoint%60) |
| ms0 = int(startPoint*1000000%1000000) |
| time0 = dt.time(h0,m0,s0,ms0) |
| |
| dtStart = dt.datetime.combine(dt.date.today(), time0) |
| |
| h1 = int(endPoint//3600) |
| m1 = int(endPoint%3600//60) |
| s1 = int(endPoint%60) |
| ms1 = int(endPoint*1000000%1000000) |
| time1 = dt.time(h1,m1,s1,ms1) |
| |
| dtEnd = dt.datetime.combine(dt.date.today(), time1) |
| dataList.append(dict(Task=speakerName + f".{k}", Start=dtStart, Finish=dtEnd, Resource=speakerName)) |
| df = pd.DataFrame(dataList) |
| return df, timeSummary |
| |
| def annotationToSimpleDataFrame(myAnnotation): |
| ''' |
| Convert pyannote.core.Annotation directly to pandas.DataFrame object |
| |
| ... |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Diarization representation |
| |
| Returns |
| ------- |
| df : pandas.DataFrame |
| DataFrame representation of input |
| timeSummary : dict |
| Maps speakers to duration spoken |
| ''' |
| dataList = [] |
| speakerDict = {} |
| |
| for currSpeaker in myAnnotation.labels(): |
| |
| if currSpeaker not in speakerDict.keys(): |
| speakerDict[currSpeaker] = [] |
| |
| for currSegment in myAnnotation.subset([currSpeaker]).itersegments(): |
| speakerDict[currSpeaker].append(currSegment) |
|
|
| timeSummary = {} |
| |
| for key in speakerDict.keys(): |
| |
| if key not in timeSummary.keys(): |
| timeSummary[key] = 0 |
| |
| for speakingSegment in speakerDict[key]: |
| timeSummary[key] += speakingSegment.duration |
|
|
| |
| for key in speakerDict.keys(): |
| |
| for k, speakingSegment in enumerate(speakerDict[key]): |
| |
| speakerName = key |
| startPoint = speakingSegment.start |
| endPoint = speakingSegment.end |
| dataList.append(dict(Task=speakerName + f".{k}", Start=startPoint, Finish=endPoint, Resource=speakerName)) |
| df = pd.DataFrame(dataList) |
| return df, timeSummary |
|
|
| def calcCategories(myAnnotation,categories): |
| ''' |
| Combines speakers based on categories |
| |
| ... |
| |
| Parameters |
| ---------- |
| myAnnotation : pyannote.core.Annotation |
| Target Annotation |
| categories : list |
| List of known categories, which contain a list of speakers. List(List(speaker)) |
| |
| Returns |
| ------- |
| cleanCategories : List |
| List of all categories, which contains a list of (speaker,pyannote.core.Segment) pairs. List(List(speaker,Segment)). |
| Outer list length = categories + len(extraCategories) |
| extraCategories : List |
| List of speakers which fit in no category |
| ''' |
| categorySlots = [] |
| extraCategories = [] |
| |
| for category in categories: |
| categorySlots.append([]) |
| |
| for speaker in myAnnotation.labels(): |
| |
| targetCategory = None |
| for i, category in enumerate(categories): |
| if speaker in category: |
| targetCategory = i |
| |
| if targetCategory is None: |
| targetCategory = len(categorySlots) |
| categorySlots.append([]) |
| extraCategories.append(speaker) |
| |
| for timeSegment in myAnnotation.subset([speaker]).itersegments(): |
| categorySlots[targetCategory].append((speaker,timeSegment)) |
| |
| |
| cleanCategories = [] |
| |
| for category in categorySlots: |
| newCategory = [] |
| |
| catSorted = copy.deepcopy(sorted(category,key=lambda cSegment: cSegment[1].start)) |
| currID, currSegment = None, None |
| |
| if len(catSorted) > 0: |
| currID, currSegment = catSorted[0] |
| |
| for sp, segmentSlot in catSorted[1:]: |
| |
| overlapTime = checkForOverlap(currSegment,segmentSlot) |
| |
| if overlapTime is None: |
| newCategory.append((currID,currSegment)) |
| currID = sp |
| currTime = segmentSlot |
| |
| else: |
| |
| currID = currID + "+" + sp |
| |
| currTime[1] = currSegment | segmentSlot |
| |
| if currSegment is not None: |
| newCategory.append((currID,currSegment)) |
| cleanCategories.append(newCategory) |
| return cleanCategories,extraCategories |
|
|
| def calcSpeakingTypes(pipeline,myAnnotation,maxTime): |
| ''' |
| Calculates no voice, one voice, and multi voice for a given Annotation |
| |
| ... |
| |
| Parameters |
| ---------- |
| pipeline : sonogram.Sonogram |
| Model object to use for analysis call |
| myAnnotation : pyannote.core.Annotation |
| Target Annotation |
| maxTime : float |
| The duration of the audio file. Note that Annotation does NOT strictly provide this. |
| |
| Returns |
| ------- |
| nvAnnotation : pyannote.core.Annotation |
| Annotation containing only 'no voice' labels |
| ovAnnotation : pyannote.core.Annotation |
| Annotation containing only 'one voice' labels |
| mvAnnotation : pyannote.core.Annotation |
| Annotation containing only 'multi voice' labels |
| ''' |
| |
| nvAnnotation = Annotation() |
| ovAnnotation = Annotation() |
| mvAnnotation = Annotation() |
|
|
| |
| categorySegmentList, timeSteps = pipeline.annotationToNoiseList(myAnnotation,maxTime) |
| |
| print("MultiVoice") |
| |
| for seg in categorySegmentList[0]: |
| |
| if 'group' in seg[0] or seg[0] is None: |
| print(f'unclear : {seg[1]}') |
| mvAnnotation[seg[1]] = 'unclear' |
| else: |
| print(f'{seg[0]} : {seg[1]}') |
| mvAnnotation[seg[1]] = seg[0] |
| print("OneVoice") |
| |
| for seg in categorySegmentList[1]: |
| print(f'{seg[0]} : {seg[1]}') |
| ovAnnotation[seg[1]] = seg[0] |
| print("NoVoice") |
| |
| for seg in categorySegmentList[2]: |
| print(f'{seg[0]} : {seg[1]}') |
| |
| nvAnnotation[seg[1]] = 'silence' |
| return nvAnnotation, ovAnnotation, mvAnnotation |
|
|
| def timeToString(timeInSeconds): |
| ''' |
| Convert time(s) into HH:MM:SS.MS format |
| |
| ... |
| |
| Parameters |
| ---------- |
| timeInSeconds : float or int or list |
| Time to convert (in seconds). May contain a list of times to convert recursively |
| ''' |
| |
| if isinstance(timeInSeconds,list): |
| return [timeToString(t) for t in timeInSeconds] |
| else: |
| |
| h = int(timeInSeconds//3600) |
| m = int(timeInSeconds%3600//60) |
| s = timeInSeconds%60 |
| return f'{h:02d}::{m:02d}::{s:02.2f}' |