Identify Duplicate Dual Channel Files

In this guide, you’ll learn how to identify Dual Channel (Stereo) files that contain the same content on each channel. With AssemblyAI’s API, we support Dual Channel files by transcribing each channel individually, then intelligently combining the results into one transcript. If a file contains the same content on both channels, then you may end up with duplicate content in your transcript.

To programmatically identify duplicate channels, you can hash the audio content found on each channel and compare the hashes to quickly determine whether you should remove a channel and then submit the file for more accurate results.

Getting Started

To get started, you’ll need to install a few prerequisites:

$pip install -U pydub numpy audioop-lts assemblyai

Helper Functions

Now we’ll need to define a few helper functions before we set up our full workflow. The first one, load_audio will load any audio file, regardless of format, and return each channel as a NumPy array.

1from pydub import AudioSegment
2import numpy as np
3
4def load_audio(file_path):
5 # Load the audio file.
6 audio = AudioSegment.from_file(file_path)
7
8 # Ensure audio is stereo.
9 if audio.channels != 2:
10 raise ValueError("This function only supports stereo audio files.")
11
12 # Convert audio data to raw samples.
13 samples = np.array(audio.get_array_of_samples())
14
15 # Reshape samples to separate channels.
16 samples = samples.reshape((-1, audio.channels))
17
18 # Extract left and right channels.
19 left_channel = samples[:, 0]
20 right_channel = samples[:, 1]
21
22 return left_channel, right_channel

Our next function, hash_audio_data hashes each channel to return a SHA-256 hash.

1import hashlib
2
3def hash_audio_data(data):
4 hasher = hashlib.sha256()
5 hasher.update(data.tobytes())
6 return hasher.hexdigest()

Our next function, compare_audio_channels lets us know via a flag if the audio channels are the same, with 1 meaning that they are the same, and 0 meaning they’re not.

1def compare_audio_channels(file_path):
2 try:
3 left_channel, right_channel = load_audio(file_path)
4
5 # Compute hashes for both channels.
6 left_hash = hash_audio_data(left_channel)
7 right_hash = hash_audio_data(right_channel)
8
9 # Compare hashes.
10 if left_hash == right_hash:
11 return True
12 else:
13 return False
14
15 except Exception as e:
16 print(f"An error occurred: {e}")

Based on the result of this function, we now need a way to remove the duplicate content to avoid duplicate transcription results. To do this, we’ll define one final function, convert_to_mono_if_duplicate that removes one of the audio channels and creates a new mono file that we can submit to AssemblyAI, returning the path to it. If the file contains different content on each channel, however, this function will instead return the original file path.

1import os
2
3def convert_to_mono_if_duplicate(file_path):
4 if compare_audio_channels(file_path):
5 print("The audio content for this file is identical on both channels. Converting to mono...")
6
7 # Load the audio file again with pydub.
8 audio = AudioSegment.from_file(file_path)
9
10 # Convert to mono by selecting one channel (since both are identical).
11 mono_audio = audio.set_channels(1)
12
13 # Save the new mono file.
14 output_path = os.path.splitext(file_path)[0] + "_mono" + os.path.splitext(file_path)[1]
15 mono_audio.export(output_path, format=os.path.splitext(file_path)[1][1:])
16
17 print("File converted.\n")
18
19 return output_path
20 else:
21 return file_path

Combining with AssemblyAI

Now we can combine this workflow with AssemblyAI to programmatically catch files that could cause duplicate results and modify them before submitting them to AssemblyAI. To get started, you’ll need an AssemblyAI account and an API key. You can sign up for a free account and get your API key from your dashboard.

Now we’ll create a workflow that checks if we should convert a file before using AssemblyAI’s SDK to transcribe it.

1import assemblyai as aai
2
3aai.settings.api_key = "API_KEY"
4
5original_path = "FILE_PATH"
6
7updated_path = convert_to_mono_if_duplicate(original_path)
8
9# Check if we modified the file and thus appended _mono to it.
10if updated_path != original_path:
11 # Use the default configuration, which will treat the file as mono, which it now is.
12 transcriber = aai.Transcriber()
13
14 # Transcribe our new mono file.
15 print(transcriber.transcribe(updated_path).text)
16else:
17 # Submit the file as Dual Channel if the content wasn't the same.
18 config = aai.TranscriptionConfig(dual_channel=True)
19
20 # Load the config into our Transcriber.
21 transcriber = aai.Transcriber(config=config)
22
23 # Transcribe the stereo file.
24 print(transcriber.transcribe(updated_path).text)