Вы когда-нибудь задумывались о создании своего собственного приложения для распознавания музыки, например Shazam или Soundhound? Теперь это возможно благодаря онлайн-службе распознавания музыки под названием ACRCloud.

В этом случае я собираюсь научить вас делать это на Android с помощью языка Kotlin, но вы также можете интегрировать его в iOS или любую другую платформу благодаря веб-API. .

Лучше всего, что вы можете подписаться на бесплатный план, чтобы пройти первые тесты. У него есть ограничение в 100 запросов в день, чего достаточно для запуска вашего проекта.

Регистрация и создание проекта

Первый шаг, который мы должны выполнить, - это зарегистрироваться на его веб-сайте, чтобы мы могли получить доступ к консоли.

Оказавшись здесь, мы сможем увидеть различные услуги, которые они предлагают.

В нашем случае нас интересует «Проекты› Распознавание аудио и видео ».

Здесь мы должны создать новый проект, нажав «Create Project». Мы даем ему имя и выбираем «Записанный звук», так как мы собираемся распознавать музыку, которую записываем через микрофон нашего устройства. В качестве «ведра» мы должны выбрать «ACRCloud Music». При желании мы можем установить флажок «Сторонняя интеграция», если нам нужны ссылки на YouTube и Spotify, среди прочего.

После создания он даст нам «Ключ доступа» и «Секрет доступа». Мы оба будем использовать их в нашем Android-проекте.

Загрузка и интеграция SDK

Следующим шагом будет загрузка Android SDK через следующий репозиторий GitHub.

Как видите, у нас есть несколько ресурсов: пример проекта на Java, пример файла на Kotlin, исходный код собственных библиотек, документация и сами библиотеки.

Папка libs по существу разделена на Java SDK (файл .jar) и собственный код в виде библиотек (файлы .so). для разных архитектур.

Что ж, давайте создадим новый пустой проект в Android Studio.

Затем мы можем переместить файл .jar в папку «app / libs».

Для собственных библиотек мы должны сначала создать папку с именем jniLib s внутри «app / src / main /». Затем мы должны скопировать папки архитектур, которые мы хотим внутри, оставив следующую структуру:

Кодирование Android

У нас уже есть готовый SDK. Теперь приступим к разработке нашего приложения.

Первое, что мы должны знать, это то, что нам потребуется разрешение микрофона для записи звука и разрешение Интернета для связи с сервером ACRCloud. Итак, в файл манифеста мы добавляем следующее:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Поскольку аудиозапись - это «опасное» разрешение, мы должны запрашивать его во время выполнения. Итак, мы собираемся создать кнопку в activity_main.xml, чтобы включить это разрешение:

<Button
    android:id="@+id/permission"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Enable mic" />

Мы можем показать или скрыть это в зависимости от того, есть ли у нас это разрешение. Также мы должны запрашивать разрешение при нажатии кнопки. Быстрый и простой способ реализовать это с помощью следующих функций:

fun checkPermission() {
    if (ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.RECORD_AUDIO) != 0) {
        permission.visibility = View.VISIBLE
        permission.setOnClickListener {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), 100)
        }
    } else {
        permission.visibility = View.GONE
        hasPermission()
    }
}
 
fun hasPermission() { ... }
 
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == 100) {
        checkPermission()
    }
}

Если у нас уже включено разрешение на микрофон, мы можем начать распознавать звук. Итак, мы возвращаемся к макету и создаем Button и TextView, чтобы показать результат.

<TextView
    android:id="@+id/result"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="21sp"
    android:textStyle="bold"
    android:layout_margin="8dp"/>
 
<Button
    android:id="@+id/recognize"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Recognize" />

Теперь мы можем инициализировать конфигурацию ACRCloud, скопировав следующий код в наше основное действие:

    private var mClient: ACRCloudClient? = null
 
    fun initAcrcloud() {
        val config = ACRCloudConfig()
 
        config.acrcloudListener = this
        config.context = this
 
        // Please create project in "http://console.acrcloud.cn/service/avr".
        // Please create project in "http://console.acrcloud.cn/service/avr".
        config.host = "XXXXXX"
        config.accessKey = "XXXXXX"
        config.accessSecret = "XXXXXX"
 
        config.recorderConfig.rate = 8000
        config.recorderConfig.channels = 1
 
        mClient = ACRCloudClient()
        if (BuildConfig.DEBUG) {
            ACRCloudLogger.setLog(true)
        }
        mClient!!.initWithConfig(config)
    }

На данный момент мы собираемся оставить переменные host, accessKey и accessSecret в виде обычного текста, но вам следует подумать о том, чтобы скрыть эти поля в производственной среде. Посмотрите несколько примеров, чтобы скрыть свои ключи.

Начнем распознавать песню, нажав на кнопку. Это будет примерно так:

    fun hasPermission() {
        recognize.setOnClickListener {
            startRecognition()
        }
    }
 
    fun startRecognition() {
        mClient?.let {
            if (it.startRecognize()) {
                result.text = "Recognizing..."
            } else {
                result.text = "Init error"
            }
        } ?: run {
            result.text = "Client not ready"
        }
    }

Для получения результата наша деятельность должна реализовывать интерфейс «IACRCloudListener». В методе onResult () мы получим обратный вызов результатов распознавания:

class MainActivity : AppCompatActivity(), IACRCloudListener {
    // ...
    override fun onResult(acrResult: ACRCloudResult?) {
        acrResult?.let {
            Log.d("ACR", "acr cloud result received: ${it.result}")
            handleResult(it.result)
        }
    }
 
    override fun onVolumeChanged(vol: Double) {
        Log.d("ACR", "volume changed $vol")
    }
 
    fun handleResult(acrResult: String) { ... }

Если мы запустим приложение, мы увидим на консоли, что результатом является строка в формате JSON. Вот почему мы можем выполнить преобразование, чтобы иметь возможность читать нужные нам данные. Мы можем увидеть пример вывода JSON на следующей странице документации ACRCloud.

Предположим, нас интересуют только название и главный художник первого результата, который также является наиболее актуальным. Для этого сделаем следующее:

    fun handleResult(acrResult: String) {
        var res = ""
        try {
            val json = JSONObject(acrResult)
            val status: JSONObject = json.getJSONObject("status")
            val code = status.getInt("code")
            if (code == 0) {
                val metadata: JSONObject = json.getJSONObject("metadata")
                if (metadata.has("music")) {
                    val musics = metadata.getJSONArray("music")
                    val tt = musics[0] as JSONObject
                    val title = tt.getString("title")
                    val artistt = tt.getJSONArray("artists")
                    val art = artistt[0] as JSONObject
                    val artist = art.getString("name")
 
                    res = "$title ($artist)"
                }
            } else {
                // TODO: Handle error
                res = acrResult
            }
        } catch (e: JSONException) {
            res = "Error parsing metadata"
            Log.e("ACR", "JSONException", e)
        }
 
        result.text = res
    }

Последний шаг - освободить клиент ACRCloud при выходе из приложения в методе onDestroy:

    override fun onDestroy() {
        super.onDestroy()
        mClient?.let { 
            it.release()
            mClient = null
        }
    }

Вот и все! При этом, когда мы нажимаем кнопку, наше приложение начинает прослушивание. Как только мы получим результат, он будет показан в текстовом поле.

Осталось только улучшить наше приложение с помощью уникального дизайна, индикатора прогресса при распознавании музыки, управления ошибками распознавания, возможности отменить начатое распознавание… Все, что вы хотите, чтобы создать отличное приложение!