How do I create the .shazamsignature file?

I want to create my own custom audio recognition with ShazamKit, when opening the sample project I found the FoodMath.shazamsignature file. I believe there is a way to generate that file based on my audio collections.

How do I create the .shazamsignature file?

Thanks.

Answered by Frameworks Engineer in 678194022

You can generate a .shazamsignature file using the SHSignatureGenerator object and then write the dataRepresentation on SHSignature to disk.

When creating a signature, you can use the microphone to record audio and append the PCM buffers to the signature generator. Alternatively, if you have access to the audio source, you can convert that directly into PCM buffers using the AVAudioFile and AVAudioConverter APIs.

For example if you use the microphone, your code might look something like this:

let signatureGenerator = SHSignatureGenerator()

audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: audioFormat) { (buffer, audioTime) in
    do {
        try signatureGenerator.append(buffer, at: audioTime)
    } catch {
        // Handle the error
    }
}

Once you finished processing the audio, you can generate the signature and write that to disk:

let fileURL = URL(fileURLWithPath: FileManager.default.currentDirectoryPath).appendingPathComponent("MySignature").appendingPathExtension("shazamsignature")

try signatureGenerator.signature().dataRepresentation.write(to: fileURL, options: .atomic)
Accepted Answer

You can generate a .shazamsignature file using the SHSignatureGenerator object and then write the dataRepresentation on SHSignature to disk.

When creating a signature, you can use the microphone to record audio and append the PCM buffers to the signature generator. Alternatively, if you have access to the audio source, you can convert that directly into PCM buffers using the AVAudioFile and AVAudioConverter APIs.

For example if you use the microphone, your code might look something like this:

let signatureGenerator = SHSignatureGenerator()

audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: audioFormat) { (buffer, audioTime) in
    do {
        try signatureGenerator.append(buffer, at: audioTime)
    } catch {
        // Handle the error
    }
}

Once you finished processing the audio, you can generate the signature and write that to disk:

let fileURL = URL(fileURLWithPath: FileManager.default.currentDirectoryPath).appendingPathComponent("MySignature").appendingPathExtension("shazamsignature")

try signatureGenerator.signature().dataRepresentation.write(to: fileURL, options: .atomic)

Hi @Frameworks Engineer, thank you for your response! 

I was successfully generate the .signature file, but when I use it in the project I got this error:

Error Domain=com.apple.ShazamKit Code=201 "The provided signature duration is outside the valid range" UserInfo={NSDebugDescription=The provided signature duration is outside the valid range, NSLocalizedFailureReason=The minimum signature duration allowed is 1.00 secs, this signature is only 0.00 secs}

 I believe I miss something in my code, could you help me to check what's wrong on this code:


import AVFoundation

import ShazamKit

import PlaygroundSupport



func generateSignature() {

    let path: String = Bundle.main.path(forResource: "alfatihah.mp3", ofType:nil)!

    let url = URL(fileURLWithPath: path)

    

    

    

    let signatureGenerator = SHSignatureGenerator()

    

    do {

        let audioFile = try AVAudioFile(forReading: url)

        let sampleRate = audioFile.processingFormat.sampleRate

        let sampleTime = audioFile.length

        

        let time = AVAudioTime(hostTime: mach_absolute_time(), sampleTime: sampleTime, atRate: sampleRate)

        

        do {

            let data = try Data(contentsOf: url)

            let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 2, interleaved: true)



            guard let buffer = AVAudioPCMBuffer(pcmFormat: format!, frameCapacity: AVAudioFrameCount(data.count)) else { return }

            

            try signatureGenerator.append(buffer, at: time)

            

            guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {

                print("No documents directory found.")

                return

            }

            

            // Save the signature

            let fileURL = documentsDirectory.appendingPathComponent("MySignature").appendingPathExtension("shazamsignature")

            try signatureGenerator.signature().dataRepresentation.write(to: fileURL, options: .atomic)

            

            print("Signature Successfully Generated")

        } catch let error as NSError {

            print("ERROR HERE", error.localizedDescription)

        }

    } catch {

        print(error)

    }

    

    

}



generateSignature()

Thanks!

First, you will need to convert the audio file to the output format you specify. Declaring a buffer with a different format will not work.

Here's a code snippet for converting AVAudioFile into AVAudioPCMBuffer:

static func convert(audioFile: AVAudioFile, outputFormat: AVAudioFormat, pcmBlock: (AVAudioPCMBuffer) -> Void) {

    let frameCount = AVAudioFrameCount(
        (1024 * 64) / (audioFile.processingFormat.streamDescription.pointee.mBytesPerFrame)
    )
    let outputFrameCapacity = AVAudioFrameCount(
         round(Double(frameCount) * (outputFormat.sampleRate / audioFile.processingFormat.sampleRate))
    )

    guard let inputBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: frameCount),
          let outputBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: outputFrameCapacity) else {
        return
    }

    let inputBlock : AVAudioConverterInputBlock = { inNumPackets, outStatus in
        do {
            try audioFile.read(into: inputBuffer)
            outStatus.pointee = .haveData
            return inputBuffer
        } catch {
            if audioFile.framePosition >= audioFile.length {
                outStatus.pointee = .endOfStream
                return nil
            } else {
                outStatus.pointee = .noDataNow
                return nil
            }
        }
    }

    guard let converter = AVAudioConverter(from: audioFile.processingFormat, to: outputFormat) else {
        return
    }

    while true {

        let status = converter.convert(to: outputBuffer, error: nil, withInputFrom: inputBlock)

        if status == .error || status == .endOfStream {
            return
        }

        pcmBlock(outputBuffer)            

        if status == .inputRanDry {
            return
        }        

        inputBuffer.frameLength = 0
        outputBuffer.frameLength = 0
    }
}

Then you can call this function and convert the audio file into a SHSignature. Your code might look something like this:

guard let audioURL = Bundle.main.url(forResource: "CustomAudio", withExtension: "m4a") else {
    return nil
}

guard let audioFormat = AVAudioFormat(standardFormatWithSampleRate: 44100, channels: 1) else {
    return nil
}

let signatureGenerator = SHSignatureGenerator()

do {

    let audioFile = try AVAudioFile(forReading: audioURL)
    let pcmBlock: ((AVAudioPCMBuffer) -> Void) = { buffer in
        do {
            try signatureGenerator.append(buffer, at: nil)
        } catch {
            // Handle signature generator error
        }
    }

    convert(audioFile: audioFile, outputFormat: audioFormat, pcmBlock: pcmBlock)

} catch {
    // Handle audio file error
}

let signature = signatureGenerator.signature()

We have an API update for 2022 that should simplify this, please try https://developer.apple.com/documentation/shazamkit/shsignaturegenerator/3991425-generatesignature.

There is also a Shazam CLI shipping on macOS that can perform the task.

Thanks

How do I create the .shazamsignature file?
 
 
Q