Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio analysis: mediorum changes #8536

Merged
merged 15 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions mediorum/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
FROM golang:alpine AS builder

RUN apk add build-base make ffmpeg
RUN apk add build-base make ffmpeg cmake fftw-dev libsndfile-dev git python3-dev py3-pip

WORKDIR /app

# Build and install libkeyfinder
RUN git clone https://github.com/mixxxdj/libKeyFinder.git /libKeyFinder
WORKDIR /libKeyFinder
RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=OFF -S . -B build && \
cmake --build build --parallel $(nproc) && \
cmake --install build

WORKDIR /app
ENV CGO_ENABLED=0
Expand All @@ -9,16 +18,23 @@ COPY go.mod go.sum ./
RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get

COPY . .

# Compile the keyfinder C++ executable
RUN g++ -o analyze-key cpp/keyfinder.cpp -I/usr/local/include -L/usr/local/lib -lkeyfinder -lsndfile && \
chmod +x analyze-key

RUN go build
RUN go build -o mediorum-cmd cmd/main.go

FROM alpine:3.17 AS final

RUN apk add curl ffmpeg
RUN apk add curl ffmpeg libsndfile python3-dev py3-pip build-base
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool to see basically all the same deps as https://github.com/swesterfeld/audiowmark which @stereosteve and I have been messing with

RUN python3 -m pip install numpy aubio

COPY --from=builder /go/bin/* /bin
COPY --from=builder /app/mediorum /bin/mediorum
COPY --from=builder /app/mediorum-cmd /bin/mediorum-cmd
COPY --from=builder /app/analyze-key /bin/analyze-key

# ARGs can be optionally defined with --build-arg while doing docker build eg in CI and then set to env vars
ARG git_sha
Expand Down
17 changes: 16 additions & 1 deletion mediorum/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
FROM golang:alpine3.18

RUN apk add build-base make ffmpeg
RUN apk add build-base make ffmpeg cmake fftw-dev libsndfile-dev git

# Required for service registration
RUN apk add curl build-base python3-dev=3.11.8-r0 py3-pip
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install 'web3==6.6.1'
RUN python3 -m pip install numpy aubio

WORKDIR /app

# Build and install libkeyfinder
RUN git clone https://github.com/mixxxdj/libKeyFinder.git /libKeyFinder
WORKDIR /libKeyFinder
RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=OFF -S . -B build && \
cmake --build build --parallel $(nproc) && \
cmake --install build

WORKDIR /app
ENV CGO_ENABLED=0
Expand All @@ -16,6 +26,11 @@ COPY go.mod go.sum ./
RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get

COPY . .

# Compile the keyfinder C++ executable
RUN g++ -o /bin/analyze-key cpp/keyfinder.cpp -I/usr/local/include -L/usr/local/lib -lkeyfinder -lsndfile && \
chmod +x /bin/analyze-key

RUN go build
RUN go build -o mediorum-cmd cmd/main.go

Expand Down
81 changes: 81 additions & 0 deletions mediorum/cpp/keyfinder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// keyfinder.cpp
#include <iostream>
#include <vector>
#include <keyfinder/keyfinder.h>
#include <sndfile.h>

// Convert KeyFinder key_t to string
std::string keyToString(KeyFinder::key_t key) {
switch (key) {
case KeyFinder::A_MAJOR: return "A major";
case KeyFinder::A_MINOR: return "A minor";
case KeyFinder::B_FLAT_MAJOR: return "B flat major";
case KeyFinder::B_FLAT_MINOR: return "B flat minor";
case KeyFinder::B_MAJOR: return "B major";
case KeyFinder::B_MINOR: return "B minor";
case KeyFinder::C_MAJOR: return "C major";
case KeyFinder::C_MINOR: return "C minor";
case KeyFinder::D_FLAT_MAJOR: return "D flat major";
case KeyFinder::D_FLAT_MINOR: return "D flat minor";
case KeyFinder::D_MAJOR: return "D major";
case KeyFinder::D_MINOR: return "D minor";
case KeyFinder::E_FLAT_MAJOR: return "E flat major";
case KeyFinder::E_FLAT_MINOR: return "E flat minor";
case KeyFinder::E_MAJOR: return "E major";
case KeyFinder::E_MINOR: return "E minor";
case KeyFinder::F_MAJOR: return "F major";
case KeyFinder::F_MINOR: return "F minor";
case KeyFinder::G_FLAT_MAJOR: return "G flat major";
case KeyFinder::G_FLAT_MINOR: return "G flat minor";
case KeyFinder::G_MAJOR: return "G major";
case KeyFinder::G_MINOR: return "G minor";
case KeyFinder::A_FLAT_MAJOR: return "A flat major";
case KeyFinder::A_FLAT_MINOR: return "A flat minor";
case KeyFinder::SILENCE: return "Silence";
default: return "Unknown";
}
}

int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <audio file path>" << std::endl;
return 1;
}

const char* filePath = argv[1];

// Open the audio file
SF_INFO sfinfo;
SNDFILE* sndfile = sf_open(filePath, SFM_READ, &sfinfo);
if (!sndfile) {
std::cerr << "Error opening audio file: " << sf_strerror(sndfile) << std::endl;
return 1;
}

static KeyFinder::KeyFinder keyFinder;

// Build an empty audio object
KeyFinder::AudioData audioDataStruct;
audioDataStruct.setFrameRate(sfinfo.samplerate);
audioDataStruct.setChannels(sfinfo.channels);

const size_t CHUNK_SIZE = 4096;
std::vector<float> buffer(CHUNK_SIZE * sfinfo.channels);
size_t totalSamples = 0;

// Read and process the file in chunks
while (sf_count_t framesRead = sf_readf_float(sndfile, buffer.data(), CHUNK_SIZE)) {
totalSamples += framesRead * sfinfo.channels;
audioDataStruct.addToSampleCount(framesRead * sfinfo.channels);
for (size_t i = 0; i < framesRead * sfinfo.channels; ++i) {
audioDataStruct.setSample(totalSamples - framesRead * sfinfo.channels + i, buffer[i]);
}
}

sf_close(sndfile);

KeyFinder::key_t key = keyFinder.keyOfAudio(audioDataStruct);
std::string keyString = keyToString(key);
std::cout << keyString << std::endl;
return 0;
}
Loading