project init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Temporary files, for example, from tests.
|
||||
/tmp/
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
chromaprint-*.tar
|
||||
|
||||
/.direnv/
|
||||
/.state/
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "c_src/chromaprint"]
|
||||
path = c_src/chromaprint
|
||||
url = https://github.com/acoustid/chromaprint.git
|
||||
@@ -0,0 +1,36 @@
|
||||
PRIV_DIR := $(MIX_APP_PATH)/priv
|
||||
BUILD_DIR := $(MIX_APP_PATH)/cmake_build
|
||||
NIF_SO := $(PRIV_DIR)/chromaprint_nif.so
|
||||
JOBS ?= $(shell nproc 2>/dev/null || echo 4)
|
||||
CMAKE_BUILD_TYPE ?= Release
|
||||
CHROMAPRINT_USE_SYSTEM ?= OFF
|
||||
|
||||
CMAKE_EXTRA_ARGS ?=
|
||||
|
||||
ifneq ($(strip $(CHROMAPRINT_INCLUDE_DIR)),)
|
||||
CMAKE_EXTRA_ARGS += -DCHROMAPRINT_INCLUDE_DIR=$(CHROMAPRINT_INCLUDE_DIR)
|
||||
endif
|
||||
ifneq ($(strip $(CHROMAPRINT_LIB_DIR)),)
|
||||
CMAKE_EXTRA_ARGS += -DCMAKE_LIBRARY_PATH=$(CHROMAPRINT_LIB_DIR)
|
||||
endif
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(NIF_SO)
|
||||
|
||||
$(NIF_SO): $(BUILD_DIR)/CMakeCache.txt
|
||||
@mkdir -p $(PRIV_DIR)
|
||||
cmake --build $(BUILD_DIR) --config $(CMAKE_BUILD_TYPE) -j $(JOBS)
|
||||
cmake --install $(BUILD_DIR)
|
||||
|
||||
$(BUILD_DIR)/CMakeCache.txt:
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
cmake -S c_src -B $(BUILD_DIR) \
|
||||
-DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \
|
||||
-DERTS_INCLUDE_DIR=$(ERTS_INCLUDE_DIR) \
|
||||
-DPRIV_DIR=$(PRIV_DIR) \
|
||||
-DCHROMAPRINT_USE_SYSTEM=$(CHROMAPRINT_USE_SYSTEM) \
|
||||
$(CMAKE_EXTRA_ARGS)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) $(NIF_SO)
|
||||
@@ -0,0 +1,21 @@
|
||||
# Chromaprint
|
||||
|
||||
**TODO: Add description**
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `chromaprint` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:chromaprint, "~> 0.1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||
be found at <https://hexdocs.pm/chromaprint>.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(chromaprint_nif LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(NOT ERTS_INCLUDE_DIR)
|
||||
message(FATAL_ERROR "ERTS_INCLUDE_DIR is required (path to erts-x.y.z/include)")
|
||||
endif()
|
||||
if(NOT PRIV_DIR)
|
||||
message(FATAL_ERROR "PRIV_DIR is required (mix app priv/ directory)")
|
||||
endif()
|
||||
|
||||
option(CHROMAPRINT_USE_SYSTEM "Link against a system-provided libchromaprint" OFF)
|
||||
|
||||
if(CHROMAPRINT_USE_SYSTEM)
|
||||
find_path(CHROMAPRINT_INCLUDE_DIR chromaprint.h)
|
||||
find_library(CHROMAPRINT_LIBRARY NAMES chromaprint)
|
||||
if(NOT CHROMAPRINT_INCLUDE_DIR OR NOT CHROMAPRINT_LIBRARY)
|
||||
message(FATAL_ERROR
|
||||
"CHROMAPRINT_USE_SYSTEM=ON but chromaprint.h or libchromaprint not found. "
|
||||
"Set CHROMAPRINT_INCLUDE_DIR and CMAKE_LIBRARY_PATH (or CMAKE_PREFIX_PATH).")
|
||||
endif()
|
||||
message(STATUS "Using system chromaprint: ${CHROMAPRINT_LIBRARY}")
|
||||
add_library(chromaprint_dep INTERFACE)
|
||||
target_include_directories(chromaprint_dep INTERFACE "${CHROMAPRINT_INCLUDE_DIR}")
|
||||
target_link_libraries(chromaprint_dep INTERFACE "${CHROMAPRINT_LIBRARY}")
|
||||
else()
|
||||
message(STATUS "Building vendored chromaprint (c_src/chromaprint)")
|
||||
set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_FRAMEWORK OFF CACHE BOOL "" FORCE)
|
||||
set(FFT_LIB "kissfft" CACHE STRING "" FORCE)
|
||||
# FindKissFFT.cmake searches CMAKE_SOURCE_DIR/src/3rdparty/kissfft, which would
|
||||
# resolve to c_src/src/... when chromaprint is added as a subdirectory. Point
|
||||
# it at the vendored copy inside the submodule.
|
||||
set(KISSFFT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/chromaprint/src/3rdparty/kissfft"
|
||||
CACHE PATH "" FORCE)
|
||||
add_subdirectory(chromaprint EXCLUDE_FROM_ALL)
|
||||
add_library(chromaprint_dep INTERFACE)
|
||||
target_link_libraries(chromaprint_dep INTERFACE chromaprint)
|
||||
target_include_directories(chromaprint_dep INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/chromaprint/src")
|
||||
endif()
|
||||
|
||||
add_library(chromaprint_nif SHARED chromaprint_nif.cpp)
|
||||
|
||||
set_target_properties(chromaprint_nif PROPERTIES
|
||||
PREFIX ""
|
||||
SUFFIX ".so"
|
||||
)
|
||||
|
||||
target_include_directories(chromaprint_nif PRIVATE "${ERTS_INCLUDE_DIR}")
|
||||
target_link_libraries(chromaprint_nif PRIVATE chromaprint_dep)
|
||||
|
||||
if(APPLE)
|
||||
set_target_properties(chromaprint_nif PROPERTIES
|
||||
LINK_FLAGS "-flat_namespace -undefined suppress")
|
||||
endif()
|
||||
|
||||
install(TARGETS chromaprint_nif
|
||||
LIBRARY DESTINATION "${PRIV_DIR}"
|
||||
RUNTIME DESTINATION "${PRIV_DIR}")
|
||||
@@ -0,0 +1,282 @@
|
||||
#include <chromaprint.h>
|
||||
#include <erl_nif.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
ErlNifResourceType *CHROMAPRINT_CTX_RES = nullptr;
|
||||
|
||||
struct ChromaprintCtxRes {
|
||||
ChromaprintContext *ctx;
|
||||
};
|
||||
|
||||
ERL_NIF_TERM ATOM_OK;
|
||||
ERL_NIF_TERM ATOM_ERROR;
|
||||
ERL_NIF_TERM ATOM_TRUE;
|
||||
ERL_NIF_TERM ATOM_FALSE;
|
||||
ERL_NIF_TERM ATOM_BADARG;
|
||||
ERL_NIF_TERM ATOM_ALLOC_FAILED;
|
||||
ERL_NIF_TERM ATOM_CHROMAPRINT_FAILED;
|
||||
ERL_NIF_TERM ATOM_NIL;
|
||||
|
||||
inline ERL_NIF_TERM mk_atom(ErlNifEnv *env, const char *name) {
|
||||
ERL_NIF_TERM atom;
|
||||
if (enif_make_existing_atom(env, name, &atom, ERL_NIF_LATIN1)) return atom;
|
||||
return enif_make_atom(env, name);
|
||||
}
|
||||
|
||||
inline ERL_NIF_TERM ok_tuple(ErlNifEnv *env, ERL_NIF_TERM value) {
|
||||
return enif_make_tuple2(env, ATOM_OK, value);
|
||||
}
|
||||
|
||||
inline ERL_NIF_TERM error_tuple(ErlNifEnv *env, ERL_NIF_TERM reason) {
|
||||
return enif_make_tuple2(env, ATOM_ERROR, reason);
|
||||
}
|
||||
|
||||
void destruct_ctx(ErlNifEnv * /*env*/, void *obj) {
|
||||
auto *res = static_cast<ChromaprintCtxRes *>(obj);
|
||||
if (res->ctx != nullptr) {
|
||||
chromaprint_free(res->ctx);
|
||||
res->ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_bool(ErlNifEnv *env, ERL_NIF_TERM term, int *out) {
|
||||
if (enif_compare(term, ATOM_TRUE) == 0) {
|
||||
*out = 1;
|
||||
return true;
|
||||
}
|
||||
if (enif_compare(term, ATOM_FALSE) == 0) {
|
||||
*out = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM new_context(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
int algorithm;
|
||||
if (!enif_get_int(env, argv[0], &algorithm)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
ChromaprintContext *ctx = chromaprint_new(algorithm);
|
||||
if (ctx == nullptr) {
|
||||
return error_tuple(env, ATOM_ALLOC_FAILED);
|
||||
}
|
||||
auto *res = static_cast<ChromaprintCtxRes *>(
|
||||
enif_alloc_resource(CHROMAPRINT_CTX_RES, sizeof(ChromaprintCtxRes)));
|
||||
res->ctx = ctx;
|
||||
ERL_NIF_TERM term = enif_make_resource(env, res);
|
||||
enif_release_resource(res);
|
||||
return ok_tuple(env, term);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_start(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ChromaprintCtxRes *res;
|
||||
int sample_rate;
|
||||
int channels;
|
||||
if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res) ||
|
||||
!enif_get_int(env, argv[1], &sample_rate) ||
|
||||
!enif_get_int(env, argv[2], &channels)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
if (chromaprint_start(res->ctx, sample_rate, channels) != 1) {
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
return ATOM_OK;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_feed(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ChromaprintCtxRes *res;
|
||||
ErlNifBinary bin;
|
||||
if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res) ||
|
||||
!enif_inspect_binary(env, argv[1], &bin)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
if (bin.size % 2 != 0) {
|
||||
return error_tuple(env, ATOM_BADARG);
|
||||
}
|
||||
const auto *samples = reinterpret_cast<const int16_t *>(bin.data);
|
||||
const int sample_count = static_cast<int>(bin.size / 2);
|
||||
if (chromaprint_feed(res->ctx, samples, sample_count) != 1) {
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
return ATOM_OK;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_finish(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ChromaprintCtxRes *res;
|
||||
if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
if (chromaprint_finish(res->ctx) != 1) {
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
return ATOM_OK;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_get_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ChromaprintCtxRes *res;
|
||||
if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
char *fp = nullptr;
|
||||
if (chromaprint_get_fingerprint(res->ctx, &fp) != 1 || fp == nullptr) {
|
||||
if (fp != nullptr) chromaprint_dealloc(fp);
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
const std::size_t len = std::strlen(fp);
|
||||
ERL_NIF_TERM bin_term;
|
||||
unsigned char *buf = enif_make_new_binary(env, len, &bin_term);
|
||||
std::memcpy(buf, fp, len);
|
||||
chromaprint_dealloc(fp);
|
||||
return ok_tuple(env, bin_term);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_get_raw_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ChromaprintCtxRes *res;
|
||||
if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
uint32_t *fp = nullptr;
|
||||
int size = 0;
|
||||
if (chromaprint_get_raw_fingerprint(res->ctx, &fp, &size) != 1 || fp == nullptr) {
|
||||
if (fp != nullptr) chromaprint_dealloc(fp);
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
std::vector<ERL_NIF_TERM> items;
|
||||
items.reserve(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
items.push_back(enif_make_uint(env, fp[i]));
|
||||
}
|
||||
chromaprint_dealloc(fp);
|
||||
ERL_NIF_TERM list =
|
||||
items.empty() ? enif_make_list(env, 0)
|
||||
: enif_make_list_from_array(env, items.data(),
|
||||
static_cast<unsigned>(items.size()));
|
||||
return ok_tuple(env, list);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_get_fingerprint_hash(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ChromaprintCtxRes *res;
|
||||
if (!enif_get_resource(env, argv[0], CHROMAPRINT_CTX_RES, (void **)&res)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
uint32_t hash = 0;
|
||||
if (chromaprint_get_fingerprint_hash(res->ctx, &hash) != 1) {
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
return ok_tuple(env, enif_make_uint(env, hash));
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_encode_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
unsigned int list_len = 0;
|
||||
if (!enif_get_list_length(env, argv[0], &list_len)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
int algorithm;
|
||||
int base64;
|
||||
if (!enif_get_int(env, argv[1], &algorithm) || !get_bool(env, argv[2], &base64)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
std::vector<uint32_t> raw;
|
||||
raw.reserve(list_len);
|
||||
ERL_NIF_TERM head;
|
||||
ERL_NIF_TERM tail = argv[0];
|
||||
while (enif_get_list_cell(env, tail, &head, &tail)) {
|
||||
unsigned int val;
|
||||
if (!enif_get_uint(env, head, &val)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
raw.push_back(val);
|
||||
}
|
||||
char *encoded = nullptr;
|
||||
int encoded_size = 0;
|
||||
if (chromaprint_encode_fingerprint(raw.data(), static_cast<int>(raw.size()), algorithm,
|
||||
&encoded, &encoded_size, base64) != 1 ||
|
||||
encoded == nullptr) {
|
||||
if (encoded != nullptr) chromaprint_dealloc(encoded);
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
ERL_NIF_TERM bin_term;
|
||||
unsigned char *buf =
|
||||
enif_make_new_binary(env, static_cast<std::size_t>(encoded_size), &bin_term);
|
||||
std::memcpy(buf, encoded, static_cast<std::size_t>(encoded_size));
|
||||
chromaprint_dealloc(encoded);
|
||||
return ok_tuple(env, bin_term);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_decode_fingerprint(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM argv[]) {
|
||||
ErlNifBinary bin;
|
||||
int base64;
|
||||
if (!enif_inspect_binary(env, argv[0], &bin) || !get_bool(env, argv[1], &base64)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
uint32_t *raw = nullptr;
|
||||
int size = 0;
|
||||
int algorithm = 0;
|
||||
if (chromaprint_decode_fingerprint(reinterpret_cast<const char *>(bin.data),
|
||||
static_cast<int>(bin.size), &raw, &size, &algorithm,
|
||||
base64) != 1 ||
|
||||
raw == nullptr) {
|
||||
if (raw != nullptr) chromaprint_dealloc(raw);
|
||||
return error_tuple(env, ATOM_CHROMAPRINT_FAILED);
|
||||
}
|
||||
std::vector<ERL_NIF_TERM> items;
|
||||
items.reserve(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
items.push_back(enif_make_uint(env, raw[i]));
|
||||
}
|
||||
chromaprint_dealloc(raw);
|
||||
ERL_NIF_TERM list =
|
||||
items.empty() ? enif_make_list(env, 0)
|
||||
: enif_make_list_from_array(env, items.data(),
|
||||
static_cast<unsigned>(items.size()));
|
||||
ERL_NIF_TERM pair = enif_make_tuple2(env, enif_make_int(env, algorithm), list);
|
||||
return ok_tuple(env, pair);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM nif_version(ErlNifEnv *env, int /*argc*/, const ERL_NIF_TERM * /*argv*/) {
|
||||
const char *v = chromaprint_get_version();
|
||||
if (v == nullptr) return ATOM_NIL;
|
||||
const std::size_t len = std::strlen(v);
|
||||
ERL_NIF_TERM bin_term;
|
||||
unsigned char *buf = enif_make_new_binary(env, len, &bin_term);
|
||||
std::memcpy(buf, v, len);
|
||||
return bin_term;
|
||||
}
|
||||
|
||||
int load(ErlNifEnv *env, void ** /*priv_data*/, ERL_NIF_TERM /*load_info*/) {
|
||||
CHROMAPRINT_CTX_RES = enif_open_resource_type(env, nullptr, "ChromaprintContext",
|
||||
destruct_ctx, ERL_NIF_RT_CREATE, nullptr);
|
||||
if (CHROMAPRINT_CTX_RES == nullptr) return -1;
|
||||
|
||||
ATOM_OK = mk_atom(env, "ok");
|
||||
ATOM_ERROR = mk_atom(env, "error");
|
||||
ATOM_TRUE = mk_atom(env, "true");
|
||||
ATOM_FALSE = mk_atom(env, "false");
|
||||
ATOM_BADARG = mk_atom(env, "badarg");
|
||||
ATOM_ALLOC_FAILED = mk_atom(env, "alloc_failed");
|
||||
ATOM_CHROMAPRINT_FAILED = mk_atom(env, "chromaprint_failed");
|
||||
ATOM_NIL = mk_atom(env, "nil");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ErlNifFunc funcs[] = {
|
||||
{"new_context", 1, new_context, 0},
|
||||
{"start", 3, nif_start, 0},
|
||||
{"feed", 2, nif_feed, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||
{"finish", 1, nif_finish, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||
{"get_fingerprint", 1, nif_get_fingerprint, 0},
|
||||
{"get_raw_fingerprint", 1, nif_get_raw_fingerprint, 0},
|
||||
{"get_fingerprint_hash", 1, nif_get_fingerprint_hash, 0},
|
||||
{"encode_fingerprint", 3, nif_encode_fingerprint, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||
{"decode_fingerprint", 2, nif_decode_fingerprint, ERL_NIF_DIRTY_JOB_CPU_BOUND},
|
||||
{"version", 0, nif_version, 0},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ERL_NIF_INIT(Elixir.Chromaprint.NIF, funcs, load, nullptr, nullptr, nullptr)
|
||||
Generated
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1774386573,
|
||||
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
inputs = { nixpkgs.url = "nixpkgs/nixos-unstable"; };
|
||||
|
||||
outputs = { self, nixpkgs }: {
|
||||
devShell.x86_64-linux = let
|
||||
system = "x86_64-linux";
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
beam = pkgs.beam.packages.erlang_28;
|
||||
elixir = beam.elixir_1_20;
|
||||
elixir-ls = (beam.elixir-ls.override { inherit elixir; });
|
||||
in pkgs.mkShell {
|
||||
buildInputs = [
|
||||
elixir
|
||||
elixir-ls
|
||||
pkgs.cmake
|
||||
pkgs.gnumake
|
||||
pkgs.git
|
||||
];
|
||||
shellHook = ''
|
||||
mkdir -p .state/mix .state/hex
|
||||
export MIX_HOME=$PWD/.state/mix
|
||||
export HEX_HOME=$PWD/.state/hex
|
||||
export PATH=$MIX_HOME/bin:$MIX_HOME/escripts:$HEX_HOME/bin:$PATH
|
||||
mix local.hex --if-missing --force
|
||||
export LANG=en_US.UTF-8
|
||||
export ERL_AFLAGS="-kernel shell_history enabled -kernel shell_history_path '\"$PWD/.state\"' -kernel shell_history_file_bytes 1024000"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
defmodule Chromaprint.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :chromaprint,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.20-rc",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps(),
|
||||
compilers: [:elixir_make] ++ Mix.compilers(),
|
||||
make_targets: ["all"],
|
||||
make_clean: ["clean"],
|
||||
make_env: &make_env/0
|
||||
]
|
||||
end
|
||||
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
defp deps do
|
||||
[
|
||||
{:elixir_make, "~> 0.9", runtime: false},
|
||||
]
|
||||
end
|
||||
|
||||
defp make_env do
|
||||
verify_chromaprint_source!()
|
||||
|
||||
%{
|
||||
"ERTS_INCLUDE_DIR" => erts_include_dir(),
|
||||
"CHROMAPRINT_USE_SYSTEM" =>
|
||||
if(System.get_env("CHROMAPRINT_USE_SYSTEM") in ~w(1 true on ON YES yes),
|
||||
do: "ON",
|
||||
else: "OFF"
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
defp erts_include_dir do
|
||||
Path.join([
|
||||
:code.root_dir() |> to_string(),
|
||||
"erts-#{:erlang.system_info(:version)}",
|
||||
"include"
|
||||
])
|
||||
end
|
||||
|
||||
defp verify_chromaprint_source! do
|
||||
use_system = System.get_env("CHROMAPRINT_USE_SYSTEM") in ~w(1 true on ON YES yes)
|
||||
submodule_cmake = Path.join([__DIR__, "c_src", "chromaprint", "CMakeLists.txt"])
|
||||
|
||||
if not use_system and not File.exists?(submodule_cmake) do
|
||||
Mix.raise("""
|
||||
The chromaprint source submodule is missing at c_src/chromaprint/.
|
||||
|
||||
Either initialise it:
|
||||
|
||||
git submodule update --init c_src/chromaprint
|
||||
|
||||
Or, to link against a system-provided libchromaprint (recommended for
|
||||
Nix and other sandboxed builds), set CHROMAPRINT_USE_SYSTEM=1 and ensure
|
||||
chromaprint.h and libchromaprint can be found via the compiler's default
|
||||
paths (or CHROMAPRINT_INCLUDE_DIR / CHROMAPRINT_LIB_DIR if not).
|
||||
""")
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user