On my computer, I have a bunch of lossless music files that I want to convert to opus for listening on my phone. After looking online and not really finding anything, my first thought was to use make, but unfortunately, it turned out to be a lot harder than I thought because make really doesn't like spaces in filenames... for a while, I wasn't really able to figure it out, but I tried again recently and was able to get it working!
Basically, the trick is you have to use a shell command to find the
files, not the make wildcard, and then you have to pipe it
through sed to escape the spaces. Here's my complete
makefile:
FLAC_DIR = Flac
OPUS_DIR = Opus
OGG_DIR = Ogg
LOSSLESS_SRC = $(shell find "$(FLAC_DIR)" -type f -name "*.flac" -o -name "*.wav" | sed -E 's:([ ;]):\\\1:g')
LOSSY_SRC = $(shell find "$(FLAC_DIR)" -type f -name "*.mp3" -o -name "*.m4a" | sed -E 's:([ ;]):\\\1:g')
ALBUM_ART_SRC = $(shell find "$(FLAC_DIR)" -type f -name "cover.jpg" -o -name "cover.png" | sed -E 's:([ ;]):\\\1:g')
OPUS_LOSSLESS_DST = $(shell echo "$(LOSSLESS_SRC)" | sed 's:$(FLAC_DIR):$(OPUS_DIR):g' | sed -E 's:\.(flac|wav):\.opus:g')
OPUS_LOSSY_DST = $(shell echo "$(LOSSY_SRC)" | sed 's:$(FLAC_DIR):$(OPUS_DIR):g')
OPUS_ALBUM_ART_DST = $(shell echo "$(ALBUM_ART_SRC)" | sed 's:$(FLAC_DIR):$(OPUS_DIR):g')
OGG_LOSSLESS_DST = $(shell echo "$(LOSSLESS_SRC)" | sed 's:$(FLAC_DIR):$(OGG_DIR):g' | sed -E 's:\.(flac|wav):\.ogg:g')
OGG_LOSSY_DST = $(shell echo "$(LOSSY_SRC)" | sed 's:$(FLAC_DIR):$(OGG_DIR):g')
OGG_ALBUM_ART_DST = $(shell echo "$(ALBUM_ART_SRC)" | sed 's:$(FLAC_DIR):$(OGG_DIR):g')
.PHONY: all
all: opus ogg
.PHONY: opus
.PHONY: ogg
opus: $(OPUS_LOSSLESS_DST) $(OPUS_LOSSY_DST) $(OPUS_ALBUM_ART_DST)
ogg: $(OGG_LOSSLESS_DST) $(OGG_LOSSY_DST) $(OGG_ALBUM_ART_DST)
define opusEncode
@echo "Encoding \033[1;35m$<\033[0m => \033[1;35m$@\033[0m"
@mkdir -p "$(shell dirname "$@")"
@ffmpeg -loglevel quiet -i "$<" -c:a libopus -b:a 128k "$@"
endef
define oggEncode
@echo "Encoding \033[1;35m$<\033[0m => \033[1;35m$@\033[0m"
@mkdir -p "$(shell dirname "$@")"
@ffmpeg -loglevel quiet -i "$<" -c:a libvorbis -q:a 5.0 "$@"
endef
define copy
@echo "Copying \033[1;36m$<\033[0m => \033[1;36m$@\033[0m"
@mkdir -p "$(shell dirname "$@")"
@cp "$<" "$@"
endef
$(OPUS_DIR)/%.opus : $(FLAC_DIR)/%.flac ; $(opusEncode)
$(OPUS_DIR)/%.opus : $(FLAC_DIR)/%.wav ; $(opusEncode)
$(OPUS_DIR)/%.mp3 : $(FLAC_DIR)/%.mp3 ; $(copy)
$(OPUS_DIR)/%.m4a : $(FLAC_DIR)/%.m4a ; $(copy)
$(OPUS_DIR)/%.png : $(FLAC_DIR)/%.png ; $(copy)
$(OPUS_DIR)/%.jpg : $(FLAC_DIR)/%.jpg ; $(copy)
$(OGG_DIR)/%.ogg : $(FLAC_DIR)/%.flac ; $(oggEncode)
$(OGG_DIR)/%.ogg : $(FLAC_DIR)/%.wav ; $(oggEncode)
$(OGG_DIR)/%.mp3 : $(FLAC_DIR)/%.mp3 ; $(copy)
$(OGG_DIR)/%.m4a : $(FLAC_DIR)/%.m4a ; $(copy)
$(OGG_DIR)/%.png : $(FLAC_DIR)/%.png ; $(copy)
$(OGG_DIR)/%.jpg : $(FLAC_DIR)/%.jpg ; $(copy)
.PHONY: clean
clean:
@rm -rf "$(OPUS_DIR)" "$(OGG_DIR)"What it does is it takes all the music files in FLAC_DIR
and converts them to opus files in OPUS_DIR and ogg vorbis
files in OGG_DIR. Any lossy files will just get copied
over.
What I like about this is:
- It's able to convert in parallel, so it's really quick to convert my whole library. (Although it does make my computer sound like a jet engine, hehe)
- It only updates the files that need to be updated, and it detects that automatically
I'm not a makefile expert, so it's possible some of this stuff could be improved, but I think it's overall pretty good! :3