Spaces:
Sleeping
Sleeping
Moved functions and updated to use Annotations
Browse files- sonogram_utility.py +284 -1
sonogram_utility.py
CHANGED
|
@@ -193,4 +193,287 @@ def speakerListToDataFrame(speakerList):
|
|
| 193 |
dtEnd = dt.datetime.combine(dt.date.today(), time1)
|
| 194 |
dataList.append(dict(Task=f"Speaker {j}.{k}", Start=dtStart, Finish=dtEnd, Resource=f"Speaker {j+1}"))
|
| 195 |
df = pd.DataFrame(dataList)
|
| 196 |
-
return df
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
dtEnd = dt.datetime.combine(dt.date.today(), time1)
|
| 194 |
dataList.append(dict(Task=f"Speaker {j}.{k}", Start=dtStart, Finish=dtEnd, Resource=f"Speaker {j+1}"))
|
| 195 |
df = pd.DataFrame(dataList)
|
| 196 |
+
return df
|
| 197 |
+
|
| 198 |
+
def removeOverlap(timeSegment,overlap):
|
| 199 |
+
times = []
|
| 200 |
+
if timeSegment.start < overlap.start:
|
| 201 |
+
times.append(Segment(timeSegment.start,min(overlap.start,timeSegment.end)))
|
| 202 |
+
if timeSegment.end > overlap.end:
|
| 203 |
+
times.append(Segment(max(timeSegment.start,overlap.end),timeSegment.end))
|
| 204 |
+
return times
|
| 205 |
+
|
| 206 |
+
def checkForOverlap(time1, time2):
|
| 207 |
+
overlap = time1 & time2
|
| 208 |
+
if overlap:
|
| 209 |
+
return overlap
|
| 210 |
+
else:
|
| 211 |
+
return None
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def calcCategories(annotation,maxTime):
|
| 215 |
+
noVoice = [Segment(0,maxTime)]
|
| 216 |
+
oneVoice = []
|
| 217 |
+
multiVoice = []
|
| 218 |
+
# TBD Clean this up!!!
|
| 219 |
+
rawData = {}
|
| 220 |
+
for speakerName in annotation.labels():
|
| 221 |
+
if speakerName not in rawData.keys():
|
| 222 |
+
rawData[speakerName] = []
|
| 223 |
+
for segmentItem in annotation.label_support(speakerName):
|
| 224 |
+
rawData[speakerName].append(segmentItem)
|
| 225 |
+
for speaker in rawData.keys():
|
| 226 |
+
timesToProcess = []
|
| 227 |
+
for timeSlot in rawData[speaker]:
|
| 228 |
+
timesToProcess.append((speaker,timeSlot))
|
| 229 |
+
while len(timesToProcess) > 0:
|
| 230 |
+
currID, currTime = timesToProcess[0]
|
| 231 |
+
timesToProcess.remove(timesToProcess[0])
|
| 232 |
+
resetCheck = False
|
| 233 |
+
# Check in multi
|
| 234 |
+
for compareID,timeSlot in multiVoice:
|
| 235 |
+
overlapTime = checkForOverlap(currTime,timeSlot)
|
| 236 |
+
if overlapTime is None:
|
| 237 |
+
continue
|
| 238 |
+
else:
|
| 239 |
+
compareID.append(currID)
|
| 240 |
+
newTimes = removeOverlap(currTime,timeSlot)#+removeOverlap(timeSlot,currTime)
|
| 241 |
+
for i in range(len(newTimes)):
|
| 242 |
+
newTimes[i] = (currID,newTimes[i])
|
| 243 |
+
timesToProcess += newTimes
|
| 244 |
+
resetCheck = True
|
| 245 |
+
break
|
| 246 |
+
if resetCheck:
|
| 247 |
+
continue
|
| 248 |
+
# Check in one voice
|
| 249 |
+
for timeSlot in oneVoice:
|
| 250 |
+
tID = timeSlot[0]
|
| 251 |
+
tTime = timeSlot[1]
|
| 252 |
+
overlapTime = checkForOverlap(currTime,tTime)
|
| 253 |
+
if overlapTime is None:
|
| 254 |
+
continue
|
| 255 |
+
else:
|
| 256 |
+
oneVoice.remove(timeSlot)
|
| 257 |
+
# Add back non overlap
|
| 258 |
+
newTimes = removeOverlap(tTime,currTime)
|
| 259 |
+
for i in range(len(newTimes)):
|
| 260 |
+
newTimes[i] = (tID,newTimes[i])
|
| 261 |
+
oneVoice += newTimes
|
| 262 |
+
# Add overlap time to multivoice
|
| 263 |
+
multiVoice.append(([tID,currID],overlapTime))
|
| 264 |
+
# Add new times back to process
|
| 265 |
+
newTimes = removeOverlap(currTime,tTime)
|
| 266 |
+
for i in range(len(newTimes)):
|
| 267 |
+
newTimes[i] = (currID,newTimes[i])
|
| 268 |
+
timesToProcess += newTimes
|
| 269 |
+
resetCheck = True
|
| 270 |
+
break
|
| 271 |
+
if resetCheck:
|
| 272 |
+
continue
|
| 273 |
+
# Add to one voice
|
| 274 |
+
oneVoice.append((currID,currTime))
|
| 275 |
+
for _,timeSlot in multiVoice:
|
| 276 |
+
copyOfNo = copy.deepcopy(noVoice)
|
| 277 |
+
for emptySlot in noVoice:
|
| 278 |
+
if checkForOverlap(timeSlot,emptySlot) is None:
|
| 279 |
+
continue
|
| 280 |
+
else:
|
| 281 |
+
copyOfNo.remove(emptySlot)
|
| 282 |
+
copyOfNo += removeOverlap(emptySlot,timeSlot)
|
| 283 |
+
noVoice = copyOfNo
|
| 284 |
+
for _,timeSlot in oneVoice:
|
| 285 |
+
copyOfNo = copy.deepcopy(noVoice)
|
| 286 |
+
for emptySlot in noVoice:
|
| 287 |
+
if checkForOverlap(timeSlot,emptySlot) is None:
|
| 288 |
+
continue
|
| 289 |
+
else:
|
| 290 |
+
copyOfNo.remove(emptySlot)
|
| 291 |
+
copyOfNo += removeOverlap(emptySlot,timeSlot)
|
| 292 |
+
noVoice = copyOfNo
|
| 293 |
+
return noVoice, oneVoice, multiVoice, rawData
|
| 294 |
+
|
| 295 |
+
def sumTimes(annotation):
|
| 296 |
+
return annotation.get_timeline(False).duration()
|
| 297 |
+
|
| 298 |
+
def sumTimesPerSpeaker(timeSlotList):
|
| 299 |
+
speakerList = []
|
| 300 |
+
timeList = []
|
| 301 |
+
for speaker,timeSlot in timeSlotList:
|
| 302 |
+
if speaker not in speakerList:
|
| 303 |
+
speakerList.append(speaker)
|
| 304 |
+
timeList.append(0)
|
| 305 |
+
timeList[speakerList.index(speaker)] += timeSlot.duration
|
| 306 |
+
return speakerList, timeList
|
| 307 |
+
|
| 308 |
+
def sumMultiTimesPerSpeaker(timeSlotList):
|
| 309 |
+
speakerList = []
|
| 310 |
+
timeList = []
|
| 311 |
+
sList,tList = sumTimesPerSpeaker(timeSlotList)
|
| 312 |
+
for i,speakerGroup in enumerate(sList):
|
| 313 |
+
for speaker in speakerGroup:
|
| 314 |
+
if speaker not in speakerList:
|
| 315 |
+
speakerList.append(speaker)
|
| 316 |
+
timeList.append(0)
|
| 317 |
+
timeList[speakerList.index(speaker)] += tList[i]
|
| 318 |
+
return speakerList, timeList
|
| 319 |
+
|
| 320 |
+
def annotationToDataFrame(myAnnotation):
|
| 321 |
+
dataList = []
|
| 322 |
+
speakerDict = {}
|
| 323 |
+
for currSpeaker in myAnnotation.labels():
|
| 324 |
+
if currSpeaker not in speakerDict.keys():
|
| 325 |
+
speakerDict[currSpeaker] = []
|
| 326 |
+
for currSegment in myAnnotation.subset([speaker]).itersegments():
|
| 327 |
+
speakerDict[currSpeaker].append(currSegment)
|
| 328 |
+
|
| 329 |
+
timeSummary = {}
|
| 330 |
+
for key in speakerDict.keys():
|
| 331 |
+
if key not in timeSummary.keys():
|
| 332 |
+
timeSummary[key] = 0
|
| 333 |
+
for speakingSegment in speakerDict[key]:
|
| 334 |
+
timeSummary[key] += speakingSegment.duration
|
| 335 |
+
|
| 336 |
+
for key in speakerDict.keys():
|
| 337 |
+
for k, speakingSegment in enumerate(speakerDict[key]):
|
| 338 |
+
speakerName = key
|
| 339 |
+
startPoint = speakingSegment.start
|
| 340 |
+
endPoint = speakingSegment.end
|
| 341 |
+
h0 = int(startPoint//3600)
|
| 342 |
+
m0 = int(startPoint%3600//60)
|
| 343 |
+
s0 = int(startPoint%60)
|
| 344 |
+
ms0 = int(startPoint*1000000%1000000)
|
| 345 |
+
time0 = dt.time(h0,m0,s0,ms0)
|
| 346 |
+
dtStart = dt.datetime.combine(dt.date.today(), time0)
|
| 347 |
+
h1 = int(endPoint//3600)
|
| 348 |
+
m1 = int(endPoint%3600//60)
|
| 349 |
+
s1 = int(endPoint%60)
|
| 350 |
+
ms1 = int(endPoint*1000000%1000000)
|
| 351 |
+
time1 = dt.time(h1,m1,s1,ms1)
|
| 352 |
+
dtEnd = dt.datetime.combine(dt.date.today(), time1)
|
| 353 |
+
dataList.append(dict(Task=speakerName + f".{k}", Start=dtStart, Finish=dtEnd, Resource=speakerName))
|
| 354 |
+
df = pd.DataFrame(dataList)
|
| 355 |
+
return df, timeSummary
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
def calcCategories(rawData,categories):
|
| 360 |
+
categorySlots = []
|
| 361 |
+
extraCategories = []
|
| 362 |
+
for category in categories:
|
| 363 |
+
categorySlots.append([])
|
| 364 |
+
for speaker in rawData.keys():
|
| 365 |
+
targetCategory = None
|
| 366 |
+
for i, category in enumerate(categories):
|
| 367 |
+
if speaker in category:
|
| 368 |
+
targetCategory = i
|
| 369 |
+
if targetCategory is None:
|
| 370 |
+
targetCategory = len(categorySlots)
|
| 371 |
+
categorySlots.append([])
|
| 372 |
+
extraCategories.append(speaker)
|
| 373 |
+
|
| 374 |
+
for timeSlot in rawData[speaker]:
|
| 375 |
+
categorySlots[targetCategory].append((speaker,timeSlot))
|
| 376 |
+
# Clean up categories
|
| 377 |
+
cleanCategories = []
|
| 378 |
+
for category in categorySlots:
|
| 379 |
+
newCategory = []
|
| 380 |
+
catSorted = copy.deepcopy(sorted(category,key=lambda slot: slot[1][0]))
|
| 381 |
+
currID, currTime = None, None
|
| 382 |
+
if len(catSorted) > 0:
|
| 383 |
+
currID, currTime = catSorted[0]
|
| 384 |
+
for sp, timeSlot in catSorted[1:]:
|
| 385 |
+
overlapTime = checkForOverlap(currTime,timeSlot)
|
| 386 |
+
if overlapTime is None:
|
| 387 |
+
newCategory.append((currID,currTime))
|
| 388 |
+
currID = sp
|
| 389 |
+
currTime = timeSlot
|
| 390 |
+
else:
|
| 391 |
+
currID = currID + "+" + sp
|
| 392 |
+
currTime[1] = max(currTime[1],timeSlot[1])
|
| 393 |
+
if currTime is not None:
|
| 394 |
+
newCategory.append((currID,currTime))
|
| 395 |
+
cleanCategories.append(newCategory)
|
| 396 |
+
return cleanCategories,extraCategories
|
| 397 |
+
|
| 398 |
+
def calcSpeakingTypes(myAnnotation,maxTime):
|
| 399 |
+
noVoice = [[0,maxTime]]
|
| 400 |
+
oneVoice = []
|
| 401 |
+
multiVoice = []
|
| 402 |
+
for speaker in myAnnotation.labels():
|
| 403 |
+
timesToProcess = []
|
| 404 |
+
for timeSegment in myAnnotation.subset([speaker]).itersegments():
|
| 405 |
+
timesToProcess.append((speaker,timeSegment))
|
| 406 |
+
while len(timesToProcess) > 0:
|
| 407 |
+
currID, currSegment = timesToProcess[0]
|
| 408 |
+
timesToProcess.remove(timesToProcess[0])
|
| 409 |
+
resetCheck = False
|
| 410 |
+
# Check in multi
|
| 411 |
+
for compareID,timeSegment in multiVoice:
|
| 412 |
+
overlapTime = checkForOverlap(currSegment,timeSegment)
|
| 413 |
+
if overlapTime is None:
|
| 414 |
+
continue
|
| 415 |
+
else:
|
| 416 |
+
compareID.append(currID)
|
| 417 |
+
newTimes = removeOverlap(currSegment,timeSegment)
|
| 418 |
+
for i in range(len(newTimes)):
|
| 419 |
+
newTimes[i] = (currID,newTimes[i])
|
| 420 |
+
timesToProcess += newTimes
|
| 421 |
+
resetCheck = True
|
| 422 |
+
break
|
| 423 |
+
if resetCheck:
|
| 424 |
+
continue
|
| 425 |
+
# Check in one voice
|
| 426 |
+
for timeSlot in oneVoice:
|
| 427 |
+
tID = timeSlot[0]
|
| 428 |
+
tSegment = timeSlot[1]
|
| 429 |
+
overlapTime = checkForOverlap(currSegment,tSegment)
|
| 430 |
+
if overlapTime is None:
|
| 431 |
+
continue
|
| 432 |
+
else:
|
| 433 |
+
oneVoice.remove(timeSlot)
|
| 434 |
+
# Add back non overlap
|
| 435 |
+
newTimes = removeOverlap(tSegment,currSegment)
|
| 436 |
+
for i in range(len(newTimes)):
|
| 437 |
+
newTimes[i] = (tID,newTimes[i])
|
| 438 |
+
oneVoice += newTimes
|
| 439 |
+
# Add overlap time to multivoice
|
| 440 |
+
multiVoice.append(([tID,currID],overlapTime))
|
| 441 |
+
# Add new times back to process
|
| 442 |
+
newTimes = removeOverlap(currSegment,tSegment)
|
| 443 |
+
for i in range(len(newTimes)):
|
| 444 |
+
newTimes[i] = (currID,newTimes[i])
|
| 445 |
+
timesToProcess += newTimes
|
| 446 |
+
resetCheck = True
|
| 447 |
+
break
|
| 448 |
+
if resetCheck:
|
| 449 |
+
continue
|
| 450 |
+
# Add to one voice
|
| 451 |
+
oneVoice.append((currID,currSegment))
|
| 452 |
+
for _,timeSlot in multiVoice:
|
| 453 |
+
copyOfNo = copy.deepcopy(noVoice)
|
| 454 |
+
for emptySlot in noVoice:
|
| 455 |
+
if checkForOverlap(timeSlot,emptySlot) is None:
|
| 456 |
+
continue
|
| 457 |
+
else:
|
| 458 |
+
copyOfNo.remove(emptySlot)
|
| 459 |
+
copyOfNo += removeOverlap(emptySlot,timeSlot)
|
| 460 |
+
noVoice = copyOfNo
|
| 461 |
+
for _,timeSlot in oneVoice:
|
| 462 |
+
copyOfNo = copy.deepcopy(noVoice)
|
| 463 |
+
for emptySlot in noVoice:
|
| 464 |
+
if checkForOverlap(timeSlot,emptySlot) is None:
|
| 465 |
+
continue
|
| 466 |
+
else:
|
| 467 |
+
copyOfNo.remove(emptySlot)
|
| 468 |
+
copyOfNo += removeOverlap(emptySlot,timeSlot)
|
| 469 |
+
noVoice = copyOfNo
|
| 470 |
+
return noVoice, oneVoice, multiVoice
|
| 471 |
+
|
| 472 |
+
def timeToString(timeInSeconds):
|
| 473 |
+
if isinstance(timeInSeconds,list):
|
| 474 |
+
return [timeToString(t) for t in timeInSeconds]
|
| 475 |
+
else:
|
| 476 |
+
h = int(timeInSeconds//3600)
|
| 477 |
+
m = int(timeInSeconds%3600//60)
|
| 478 |
+
s = timeInSeconds%60
|
| 479 |
+
return f'{h:02d}::{m:02d}::{s:02.2f}'
|