Skip to main content

Work with Audio

Open In Colab Download View source on GitHub

Audio files are stored as Blobs in ApertureDB. The query language lets you add, find, update, and delete audio blobs with rich metadata — dish name, contributor, cuisine — so you can retrieve exactly the clips you need.

Connect to ApertureDB

Option A: ApertureDB Cloud (recommended)
Sign up for a free 30-day trial. Get your key from Connect > Generate API Key, add it to a .env file in this directory:

APERTUREDB_KEY=your_key_here

Option B: Community Edition (local Docker)
Run this in a terminal before starting the notebook:

docker run -d --name aperturedb \
-p 55555:55555 -e ADB_MASTER_KEY=admin -e ADB_FORCE_SSL=false \
aperturedata/aperturedb-community

See client configuration options for all connection methods and server setup options for deployment choices.

%pip install --upgrade --quiet aperturedb python-dotenv

# Option A: ApertureDB Cloud
from dotenv import load_dotenv
load_dotenv() # loads APERTUREDB_KEY from .env into the environment

True
# Option B: Community Edition (local Docker)
# !adb config create localdb --active \
# --host localhost --port 55555 \
# --username admin --password admin \
# --no-use-ssl --no-interactive

from aperturedb.CommonLibrary import create_connector

client = create_connector()
response, _ = client.query([{"GetStatus": {}}])
client.print_last_response()

[
{
"GetStatus": {
"info": "OK",
"status": 0,
"system": "ApertureDB",
"version": "0.19.6"
}
}
]

Generate a Sample Audio Clip

For this example we generate a short WAV file — a cooking timer beep — using Python's built-in wave module. In practice, replace this with any .wav, .mp3, or other audio file from your recipe recordings.

import wave, struct, math, os

os.makedirs("data", exist_ok=True)

sample_rate = 44100
duration = 2 # seconds
frequency = 880 # Hz — a short timer beep

# Apply a short fade-out to avoid clipping
samples = []
total = sample_rate * duration
for t in range(total):
fade = max(0.0, 1.0 - t / total)
samples.append(int(32767 * fade * math.sin(2 * math.pi * frequency * t / sample_rate)))

with wave.open("data/cooking_timer.wav", "w") as f:
f.setnchannels(1)
f.setsampwidth(2)
f.setframerate(sample_rate)
f.writeframes(struct.pack("<" + "h" * len(samples), *samples))

print(f"Generated data/cooking_timer.wav ({os.path.getsize('data/cooking_timer.wav')} bytes)")

Generated data/cooking_timer.wav (176444 bytes)

Preview the audio clip before storing it:

from IPython.display import Audio
Audio("data/cooking_timer.wav")

Add an Audio Blob to ApertureDB

Use AddBlob to store the audio binary alongside metadata. Setting type: audio makes it easy to filter later.

For bulk additions, use the Python SDK loaders.

query = [{
"AddBlob": {
"properties": {
"document_type": "wav",
"type": "audio",
"format": "wav",
"name": "cooking_timer",
"dish_name": "Baked Potato",
"cuisine": "American",
"contributor": "Gavin",
"duration_s": 2,
},
"if_not_found": {"name": ["==", "cooking_timer"]},
}
}]

with open("data/cooking_timer.wav", "rb") as f:
audio_bytes = f.read()

response, _ = client.query(query, [audio_bytes])
client.print_last_response()

[
{
"AddBlob": {
"status": 0
}
}
]

Find Audio Blobs by Metadata

Use FindBlob with constraints to retrieve audio clips. Set blobs: true to get the binary back.

query = [{
"FindBlob": {
"constraints": {
"type": ["==", "audio"],
"cuisine": ["==", "American"],
},
"blobs": True,
"results": {"all_properties": True},
}
}]

response, blobs = client.query(query)
client.print_last_response()

[
{
"FindBlob": {
"blobs_start": 0,
"entities": [
{
"_blob_index": 0,
"_uniqueid": "7.3.483380",
"contributor": "Gavin",
"cuisine": "American",
"dish_name": "Baked Potato",
"document_type": "wav",
"duration_s": 2,
"format": "wav",
"name": "cooking_timer",
"type": "audio"
}
],
"returned": 1,
"status": 0
}
}
]

Play back the retrieved audio:

from IPython.display import Audio
if blobs:
display(Audio(blobs[0]))

Update Audio Blob Metadata

Use UpdateBlob to add or change properties on existing blobs.

query = [{
"UpdateBlob": {
"constraints": {"name": ["==", "cooking_timer"]},
"properties": {"verified": True},
}
}]

response, _ = client.query(query)
client.print_last_response()

[
{
"UpdateBlob": {
"count": 1,
"status": 0
}
}
]

Delete the Audio Blob

query = [{
"DeleteBlob": {
"constraints": {"name": ["==", "cooking_timer"]},
}
}]

response, _ = client.query(query)
client.print_last_response()

[
{
"DeleteBlob": {
"count": 1,
"status": 0
}
}
]

What's Next?