Marking

Cobalstamp adds watermarks to audio (marking) and finds watermarks in audio (detection). Marking embeds the watermark locally on your machine and registers the mark on the server. Detection sends the audio to the server, which looks for registered marks in it.

Both operations work with mono audio as a numpy array of type float32, with amplitudes in [-1, 1].

Minimal example

import numpy as np
import soundfile
import cobalstamp

# Load the audio as a float32 signal in [-1, 1].
wav, fs = soundfile.read("input.wav", dtype="float32")

# Add a watermark and register it.
marked, info = cobalstamp.mark(wav, fs, is_ai=True)
print(info)

# Detect a watermark. The audio is sent to the server, which looks
# for registered marks in it.
result = cobalstamp.detect(marked, fs)
print(result)

is_test

Marks made with is_test=True (the only accepted value at this time) belong to a test session that can be purged with cobalstamp.forget(). Permanent sessions (is_test=False) are not accepted by mark() at this time.

API reference

All the functions and attributes below are available at the top level of the cobalstamp module (import cobalstamp).

Watermarking

cobalstamp.mark(wav, fs, is_ai, ai_type=None, is_test=True, clip_fn='compress')

Mark an audio signal with a Cobalstamp watermark and register it on the server.

Parameters:
  • wav – Input audio signal. A numpy array of type float32 or float64, with amplitudes in [-1, 1]. One-dimensional mono audio is accepted.

  • fs (float) – Sampling rate in Hz.

  • is_ai (bool) – Declares whether the audio is AI-related: False when the audio is not AI-related, True when it is.

  • ai_type – The AI type (optional, default None): "generated" when the audio is AI-generated (ex. audio from text), "transformed" when it is produced by an AI transformation (audio-to-audio). Ignored when is_ai is False.

  • is_test (bool) – Test-mode flag (default True). Test sessions (is_test=True) purgeable with cobalstamp.forget(). is_test=False is not accepted at this time.

  • clip_fn – Protects the marked audio from exceeding full scale, where any export to an integer format would produce harsh clipping. "compress" (default) applies a soft compression to the samples near full scale only; the rest of the audio is left unchanged. "rescale" slightly lowers the level of the whole marked audio (a fraction of a decibel, and only when the marked audio would exceed full scale) so that it stays within it. None disables the protection: the marked audio may then exceed [-1, 1].

Returns:

A tuple of two elements:

  • The watermarked audio signal, as a one-dimensional float32 numpy array.

  • An info dictionary with:

    • "result": the marking outcome, "marked" when the mark was embedded and registered.

    • "mark_id": the public mark id of this marking (a UUID), stable for this marking.

    • "is_test": the test-mode flag of this marking.

cobalstamp.detect(wav, fs)

Detect a Cobalstamp watermark in an audio signal.

The audio is sent to the server in a single request, and the server returns its verdict. The server runs a quick first pass that answers within seconds; only when it does not reach a verdict does it enqueue the extended search as a background job and return the pending state. The final verdict for that audio will then be available a forthcoming detection, as soon as possible.

Parameters:
  • wav – Input audio signal (numpy array, float32, [-1, 1]; mono only).

  • fs (float) – Sampling rate in Hz.

Returns:

The server’s verdict as a dictionary, one of:

{"marked": True, "ppid": str, "is_ai": bool|null, "ai_type": str|null, "is_test": bool} when a registered mark is verified — ppid is the provider identifier of the entity that marked the audio; is_ai says whether it declared the audio AI-related (True / False / None when undetermined); ai_type is "generated" / "transformed" when the mark specifies a type, else None (including when is_ai is True with an unspecified type); is_test says the mark is a test mark.

{"marked": None, "pending": "modified_marks"} when a quick first pass does not confirm a mark — the server runs the extended search in the background, and the final verdict is available on a subsequent detection of the same audio, as soon as possible.

{"marked": False} when no registered mark is found.

cobalstamp.forget(id)

Forget a registered test mark on the server, freeing the marked audio so it can be marked again.

This only applies to marks made with is_test=True. Marks made with is_test=False are never affected by this function.

Parameters:

id – The mark id to forget (the "mark_id" value returned by cobalstamp.mark()), or "all" to forget all the test marks of the logged-in account.

Returns:

The number of forgotten test marks: 1 for a single mark id, the total number of test marks forgotten for "all".

Environment variables

  • COBALSTAMP_KEY: the API key (license token). It must start with api_ and be exactly 68 characters long. Create a key at https://www.cobalstamp.dev/app/api-keys

  • COBALSTAMP_TIMEOUT: timeout in seconds for the connections to the server. It is applied when the SDK session starts, i.e. before the first call to the server, so it is in effect for the login (for example export COBALSTAMP_TIMEOUT=20 on a slow connection, see Slow connection).