Skip to content

Commit

Permalink
feat: make first fret 0 indexed to make more coherent
Browse files Browse the repository at this point in the history
  • Loading branch information
antscloud committed Dec 20, 2023
1 parent 9db7471 commit c23293c
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 34 deletions.
28 changes: 17 additions & 11 deletions fretboardgtr/fretboard.py
Expand Up @@ -38,7 +38,7 @@ def build_config(config: Optional[Union[Dict, FretBoardConfig]]) -> FretBoardCon
elif isinstance(config, FretBoardConfig):
return config
else:
msg = "Invalid config type {type(config)}."
msg = f"Invalid config type {type(config)}."
msg += "Need a dictionnary or FretBoardConfig instance"
raise ValueError(msg)

Expand All @@ -52,7 +52,7 @@ def __init__(
):
self.tuning = tuning if tuning is not None else STANDARD_TUNING

self.config = build_config(config)
self.config = build_config(config).validate()
self.elements = FretBoardElements()
self.fretboard: Union[HorizontalFretBoard, VerticalFretBoard] = (
HorizontalFretBoard(tuning, self.config)
Expand Down Expand Up @@ -103,13 +103,12 @@ def add_neck_dots(self) -> None:

def add_frets(self) -> None:
"""Build and add fret elements."""
show_nut = self.config.general.show_nut
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1

# Skip the open virtual fret
first_fret = 0
if show_nut:
first_fret = 1
first_fret = 1

# +2 is to close the last fret of fretboard
for fret_no in range(first_fret, number_of_frets + 2):
Expand Down Expand Up @@ -218,11 +217,17 @@ def add_note(self, string_no: int, note: str, root: Optional[str] = None) -> Non
# Note when fret == 0
string_root = self.fretboard.get_list_in_good_order(self.tuning)[string_no]
# Note when fret == N
string_root = get_note_from_index(self.config.general.first_fret, string_root)
string_root = get_note_from_index(
self.config.general.first_fret - 1, string_root
)
# Index of the note from root
_idx = chromatic_position_from_root(note, string_root)
indices = []
while _idx <= self.config.general.last_fret - self.config.general.first_fret:
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
while _idx <= number_of_frets:
indices.append(_idx)
_idx += 12

Expand Down Expand Up @@ -251,7 +256,8 @@ def _add_cross_or_note(
self.fretboard.get_list_in_good_order(self.tuning)[string_no],
)
if finger_position > 0:
finger_position -= self.config.general.first_fret
# We add 1 as it is one-indexed
finger_position = finger_position - self.config.general.first_fret + 1
if finger_position <= 0:
return None

Expand Down
9 changes: 8 additions & 1 deletion fretboardgtr/fretboards/config.py
Expand Up @@ -23,7 +23,7 @@ class FretBoardGeneralConfig(ConfigIniter):
y_end_offset: float = 0.0
fret_height: int = 50
fret_width: int = 70
first_fret: int = 0
first_fret: int = 1
last_fret: int = 12
show_tuning: bool = True
show_frets: bool = True
Expand Down Expand Up @@ -67,3 +67,10 @@ class FretBoardConfig(ConfigIniter):
open_notes: OpenNoteConfig = field(default_factory=OpenNoteConfig)
fretted_notes: FrettedNoteConfig = field(default_factory=FrettedNoteConfig)
cross: CrossConfig = field(default_factory=CrossConfig)

def validate(self) -> "FretBoardConfig":
if self.general.first_fret <= 0:
self.general.first_fret = 1
if self.general.last_fret < self.general.first_fret:
self.general.last_fret = self.general.first_fret
return self
25 changes: 17 additions & 8 deletions fretboardgtr/fretboards/horizontal.py
Expand Up @@ -29,15 +29,18 @@ def get_background_start_position(self) -> Tuple[float, float]:
)

def get_background_dimensions(self) -> Tuple[float, float]:
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
width = (number_of_frets) * (self.config.general.fret_width)
height = (len(self.tuning) - 1) * self.config.general.fret_height
return width, height

def get_neck_dot_position(self, dot: int) -> List[Tuple[float, float]]:
x = (
self.config.general.x_start
+ (0.5 + dot - self.config.general.first_fret)
+ (0.5 + dot - self.config.general.first_fret + 1)
* self.config.general.fret_width
)
y = (
Expand Down Expand Up @@ -80,7 +83,7 @@ def get_strings_position(
x_start = self.config.general.x_start + open_fret_width
x_end = self.config.general.x_start + (
self.config.general.fret_width
+ (self.config.general.last_fret - self.config.general.first_fret)
+ (self.config.general.last_fret - self.config.general.first_fret + 1)
* self.config.general.fret_width
)
start = (
Expand All @@ -98,7 +101,7 @@ def get_strings_position(
def get_nut_position(
self,
) -> Optional[Tuple[Tuple[float, float], Tuple[float, float]]]:
if self.config.general.first_fret != 0 or not self.config.general.show_nut:
if self.config.general.first_fret != 1 or not self.config.general.show_nut:
return None
open_fret_width = self.config.general.fret_width

Expand All @@ -115,7 +118,7 @@ def get_nut_position(

def get_fret_number_position(self, dot: int) -> Tuple[float, float]:
x = self.config.general.x_start + self.config.general.fret_width * (
1 / 2 + dot - self.config.general.first_fret
1 / 2 + dot - self.config.general.first_fret + 1
)
y = self.config.general.y_start + self.config.general.fret_height * (
len(self.tuning)
Expand All @@ -125,7 +128,7 @@ def get_fret_number_position(self, dot: int) -> Tuple[float, float]:
def get_tuning_position(self, string_no: int) -> Tuple[float, float]:
x = self.config.general.x_start + (
self.config.general.fret_width
* (self.config.general.last_fret - self.config.general.first_fret + 3 / 2)
* (self.config.general.last_fret - self.config.general.first_fret + 5 / 2)
)
y = self.config.general.y_start + self.config.general.fret_height * (string_no)
return x, y
Expand Down Expand Up @@ -153,7 +156,10 @@ def get_size(self) -> Tuple[float, float]:
Tuple[float, float]
Width and heigth
"""
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
width = (
self.config.general.x_start
+ self.config.general.fret_width * (number_of_frets + 2)
Expand All @@ -180,7 +186,10 @@ def get_inside_bounds(
Lower right corner x coordinate, lower right corner y coordinate
"""
open_fret_width = self.config.general.fret_width
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
upper_left_x = self.config.general.x_start
upper_left_y = self.config.general.y_start
lower_right_x = (
Expand Down
25 changes: 17 additions & 8 deletions fretboardgtr/fretboards/vertical.py
Expand Up @@ -29,7 +29,10 @@ def get_background_start_position(self) -> Tuple[float, float]:
)

def get_background_dimensions(self) -> Tuple[float, float]:
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
width = (len(self.tuning) - 1) * self.config.general.fret_width
height = (number_of_frets) * (self.config.general.fret_height)
return width, height
Expand All @@ -41,7 +44,7 @@ def get_neck_dot_position(self, dot: int) -> List[Tuple[float, float]]:
)
y = (
self.config.general.y_start
+ (0.5 + dot - self.config.general.first_fret)
+ (0.5 + dot - self.config.general.first_fret + 1)
* self.config.general.fret_height
)
if dot % 12 == 0:
Expand Down Expand Up @@ -80,7 +83,7 @@ def get_strings_position(
y_start = self.config.general.y_start + open_fret_height
y_end = self.config.general.y_start + (
self.config.general.fret_height
+ (self.config.general.last_fret - self.config.general.first_fret)
+ (self.config.general.last_fret - self.config.general.first_fret + 1)
* self.config.general.fret_height
)
start = (
Expand All @@ -98,7 +101,7 @@ def get_strings_position(
def get_nut_position(
self,
) -> Optional[Tuple[Tuple[float, float], Tuple[float, float]]]:
if self.config.general.first_fret != 0 or not self.config.general.show_nut:
if self.config.general.first_fret != 1 or not self.config.general.show_nut:
return None
open_fret_height = self.config.general.fret_height

Expand All @@ -118,15 +121,15 @@ def get_fret_number_position(self, dot: int) -> Tuple[float, float]:
len(self.tuning)
)
y = self.config.general.y_start + self.config.general.fret_height * (
1 / 2 + dot - self.config.general.first_fret
1 / 2 + dot - self.config.general.first_fret + 1
)
return x, y

def get_tuning_position(self, string_no: int) -> Tuple[float, float]:
x = self.config.general.x_start + self.config.general.fret_width * (string_no)
y = self.config.general.y_start + (
self.config.general.fret_height
* (self.config.general.last_fret - self.config.general.first_fret + 3 / 2)
* (self.config.general.last_fret - self.config.general.first_fret + 5 / 2)
)
return x, y

Expand All @@ -151,7 +154,10 @@ def get_size(self) -> Tuple[float, float]:
Tuple[float, float]
Width and heigth
"""
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
width = (
self.config.general.x_start
+ self.config.general.fret_width * (len(self.tuning) + 1)
Expand All @@ -178,7 +184,10 @@ def get_inside_bounds(
Lower right corner x coordinate, lower right corner y coordinate
"""
open_fret_height = self.config.general.fret_height
number_of_frets = self.config.general.last_fret - self.config.general.first_fret
# We add 1 as it is one-indexed for first fret
number_of_frets = (
self.config.general.last_fret - self.config.general.first_fret
) + 1
upper_left_x = self.config.general.x_start
upper_left_y = self.config.general.y_start
lower_right_x = (
Expand Down
43 changes: 40 additions & 3 deletions tests/test_e2e.py
Expand Up @@ -101,7 +101,7 @@ def test_c_major_fingering():
def test_c_major_vertical_fingering():
config = {
"general": {
"first_fret": 0,
"first_fret": 1,
"last_fret": 5,
"fret_width": 50,
}
Expand All @@ -122,7 +122,7 @@ def test_c_major_vertical_fingering():
def test_a_major_pentatonic_scale():
config = {
"general": {
"first_fret": 0,
"first_fret": 1,
"last_fret": 12,
"fret_width": 50,
}
Expand All @@ -143,7 +143,7 @@ def test_a_major_pentatonic_scale():
def test_a_major_vertical_pentatonic_scale():
config = {
"general": {
"first_fret": 0,
"first_fret": 1,
"last_fret": 12,
"fret_width": 50,
}
Expand All @@ -159,3 +159,40 @@ def test_a_major_vertical_pentatonic_scale():
assert not tmp_file.exists()
fretboard.export(tmp_file)
assert tmp_file.exists()


def test_c_major_fretboard_no_nut():
config = {
"general": {
"show_nut": False,
}
}
fretboard_config = FretBoardConfig.from_dict(config)
fretboard = FretBoard(config=fretboard_config)
c_major = ScaleFromName(root="C", mode="Ionian").get()
fretboard.add_notes(scale=c_major)
os.makedirs(OUTPUTS_ARTIFACT_FOLDER, exist_ok=True)
tmp_file = OUTPUTS_ARTIFACT_FOLDER / "horizontal_no_nut.svg"
remove_test_file(tmp_file)
assert not tmp_file.exists()
fretboard.export(tmp_file)
assert tmp_file.exists()


def test_c_major_fretboard_neck_dot_odd():
config = {
"general": {
"first_fret": 3,
"last_fret": 12,
}
}
fretboard_config = FretBoardConfig.from_dict(config)
fretboard = FretBoard(config=fretboard_config)
c_major = ScaleFromName(root="C", mode="Ionian").get()
fretboard.add_notes(scale=c_major)
os.makedirs(OUTPUTS_ARTIFACT_FOLDER, exist_ok=True)
tmp_file = OUTPUTS_ARTIFACT_FOLDER / "horizontal_fretboard_neck_dot_odd.svg"
remove_test_file(tmp_file)
assert not tmp_file.exists()
fretboard.export(tmp_file)
assert tmp_file.exists()
4 changes: 2 additions & 2 deletions tests/test_fretboard.py
Expand Up @@ -27,7 +27,7 @@ def default_config():
y_start=30.0,
fret_height=50,
fret_width=70,
first_fret=0,
first_fret=1,
last_fret=12,
show_tuning=True,
show_frets=True,
Expand Down Expand Up @@ -326,7 +326,7 @@ def test_fretboard_get_nut(default_config: FretBoardConfig):


def test_fretboard_get_nut_not_first_fret(default_config: FretBoardConfig):
default_config.general.first_fret = 1
default_config.general.first_fret = 2
fretboard = FretBoard(config=default_config)
fretboard.add_nut()

Expand Down
2 changes: 1 addition & 1 deletion tests/test_fretboard_vertical.py
Expand Up @@ -220,7 +220,7 @@ def test_fretboard_get_nut(default_config: FretBoardConfig):


def test_fretboard_get_nut_not_first_fret(default_config: FretBoardConfig):
default_config.general.first_fret = 1
default_config.general.first_fret = 2
fretboard = FretBoard(config=default_config, vertical=True)
fretboard.add_nut()

Expand Down

0 comments on commit c23293c

Please sign in to comment.