Skip to content

Commit

Permalink
Audio analysis: mediorum changes (#8536)
Browse files Browse the repository at this point in the history
  • Loading branch information
michellebrier authored May 30, 2024
1 parent 21b71af commit 2ceae28
Show file tree
Hide file tree
Showing 8 changed files with 503 additions and 28 deletions.
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
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

0 comments on commit 2ceae28

Please sign in to comment.