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.

Accepted Reply

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)
  • Thanks! I tried you solution, the signature was generated by I got an error. Please check my comment on this post. Thanks

Add a Comment

Replies

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)
  • Thanks! I tried you solution, the signature was generated by I got an error. Please check my comment on this post. Thanks

Add a Comment

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()
  • 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: **Domain=com.apple.ShazamKit Code=200 "The signature was invalid (possibly no peaks). Ensure novel audio is playing" **

    What's the problem? thanks

  • .signatureInvalid means that we failed to create a signature from the audio, make sure that the audio you are supplying is validated. It could be silence.

  • Thanks for this excellent answer, it really helped. I was wondering is you could point to a good resource for learning about (iOS) these subjects like buffers, framecapacity, sample rate etc. I have seen a few answers like yours and I feel like it's a knowledge people with a computer science degree have had, but Apple doesn't really explain anywhere themselves. Any good reading material would be greatly appreciated. 🙂

Add a Comment

https://developer.apple.com/forums/thread/701947

Answer this Post

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