Skip to content

Commit

Permalink
fix: add getters/setters for the mixer gain/peak settings in the RBv6…
Browse files Browse the repository at this point in the history
… db (#88).

The gain and peak values are stored as high/low binary values. It is now possible to get or set the gain/peak as a simple decibel value. Thank you @gsuberland for the help!
  • Loading branch information
dylanljones committed Oct 4, 2023
1 parent 2b0a4f3 commit 8a69a53
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
50 changes: 50 additions & 0 deletions pyrekordbox/db6/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

"""Rekordbox 6 `master.db` SQLAlchemy table declarations."""

import math
import struct

import numpy as np
from sqlalchemy import Column, Integer, VARCHAR, BigInteger, SmallInteger, DateTime
from sqlalchemy import Text, ForeignKey, Float
from sqlalchemy.orm import declarative_base, relationship, backref
Expand Down Expand Up @@ -1033,6 +1037,52 @@ class DjmdMixerParam(Base, StatsFull):
Content = relationship("DjmdContent")
"""The content this mixer parameters belong to (links to :class:`DjmdContent`)."""

@staticmethod
def _get_db(low, high):
integer = (high << 16) | low
byte_data = integer.to_bytes(4, byteorder="big")
factor = struct.unpack("!f", byte_data)[0]
if factor <= 0:
return -np.inf
return 20 * math.log10(factor)

@staticmethod
def _set_db(value):
if value == -np.inf:
return 0, 0
factor = 10 ** (value / 20)
byte_data = struct.pack("!f", factor)
integer = int.from_bytes(byte_data, byteorder="big")
low, high = integer & 0xFFFF, integer >> 16
return low, high

@property
def Gain(self) -> float:
"""The auto-gain value of a track in dB.
This value is computed from the low and high gain values.
It is the value of the auto-gain knob in the Grid Edit panel or Rekordbox,
which is also set by the analysis process.
"""
return self._get_db(self.GainLow, self.GainHigh)

@Gain.setter
def Gain(self, value: float) -> None:
self.GainLow, self.GainHigh = self._set_db(value)

@property
def Peak(self):
"""The peak amplitude of a track in dB.
This value is computed from the low and high peak values.
It is not exposed in Rekordbox.
"""
return self._get_db(self.PeakLow, self.PeakHigh)

@Peak.setter
def Peak(self, value):
self.PeakLow, self.PeakHigh = self._set_db(value)


class DjmdMyTag(Base, StatsFull):
"""Table for storing My-Tags lists in the Rekordbox library.
Expand Down
17 changes: 17 additions & 0 deletions tests/test_db6.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,23 @@ def test_songs_getters(parent_name, key, cls):
assert isinstance(query.first(), cls)


def test_mixer_gain_setters(db):
for item in db.get_mixer_param():
# Check Gain setter
low, high, value = int(item.GainLow), int(item.GainHigh), item.Gain
item.Gain = value
db.flush()
assert item.GainLow == low
assert item.GainHigh == high

# Check Peak setter
low, high, value = int(item.PeakLow), int(item.PeakHigh), item.Peak
item.Peak = value
db.flush()
assert item.PeakLow == low
assert item.PeakHigh == high


@mark.parametrize(
"search,ids",
[
Expand Down

0 comments on commit 8a69a53

Please sign in to comment.