Skip to content

Commit

Permalink
feat: 和弦过滤
Browse files Browse the repository at this point in the history
  • Loading branch information
liningzhu committed Jan 17, 2024
1 parent 6edef93 commit 1b0aeda
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 45 deletions.
4 changes: 3 additions & 1 deletion packages/buitar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pnpm dev

# TODO

## keepalive

## feature

1. 支持乐器
Expand All @@ -15,7 +17,7 @@ pnpm dev
- 1.3 ~~指板适配尤克里里~~
- 1.4 ~~鼓机~~
- 1.5 效果器
- 1.6 鼓机加入音序机[编辑](https://www.musicca.com/zh/chord-player)
- 1.6 ~~鼓机加入音序机[编辑](https://www.musicca.com/zh/chord-player)~~
2. 和弦收藏
- 2.1 ~~caged系统和弦卡片~~
- 2.2 ~~「和弦收藏」适配多指板模式~~
Expand Down
90 changes: 46 additions & 44 deletions packages/to-guitar/src/utils/trans-point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,53 @@ const transChordTaps = (
}

/**
* 过滤 连续两根弦 重复的和弦音
* 过滤 重复的和弦音
* @example 1.连续两根弦高8度 相同tone (一弦0品E + 二弦7品E)
* @example 2.存在相同绝对音高 相同pitch(一弦10品D + 三弦0品D)
* @param taps
*/
const repeatingPitchFilter = (taps: Point[]) => {
// 1.连续两根弦高8度
for (let i = 0; i < taps.length - 1; i++) {
if (taps[i].pitch === taps[i + 1].pitch) {
if (taps[i].tone === taps[i + 1].tone) {
return false
}
}
return true

// 2.存在相同绝对音高
const pitchs = new Set(taps.map((tap) => tap.pitch))
return pitchs.size === taps.length
}

/**
* 排序 根据该和弦品位从低至高
* 除重 Array.reduce 移除重复和弦(指型覆盖)
* @example [F:133211] => [F:xx3211] 弦覆盖
* @todo 两个和弦的差别在于 0 品和 12 品的区别
* @param prevArr
* @param curChord
*/
const coverTapsReducer = (prevArr: Point[][], curChord: Point[]) => {
// 遍历已选的无重复的指型
for (let i = 0; i < prevArr.length; i++) {
const prevChord = prevArr[i]

if (prevChord.every((prevPoint) => curChord.includes(prevPoint))) {
// 1.当前指型可以覆盖已选的指型,则替换该已选指型
prevArr[i] = curChord
return prevArr
} else if (curChord.every((curPoint) => prevChord.includes(curPoint))) {
// 2.当前指型可以被已选指型覆盖,则跳出本次循环
return prevArr
}
}

// 3.指型不能互相覆盖,则加入新指型
prevArr.push(curChord)
return prevArr
}

/**
* 排序 Array.sort 根据该和弦品位从低至高
* @param tapsA
* @param tapsB
*/
Expand All @@ -385,37 +418,6 @@ const transChordTaps = (
return maxGradeA - maxGradeB
}

/**
* 移除重复和弦(指型覆盖)
* @param list
* @returns
*/
const coverTapsReduce = (list: BoardChord[]) => {
return list.reduce(
(prevArr, curChord) => {
// 遍历已选的无重复的指型
for (let i = 0; i < prevArr.length; i++) {
const prevChord = prevArr[i]

if (prevChord.chordTaps.every((prevPoint) => curChord.chordTaps.includes(prevPoint))) {
// 1.当前指型可以覆盖已选的指型,则替换该已选指型
prevArr[i] = curChord
return prevArr
} else if (
curChord.chordTaps.every((curPoint) => prevChord.chordTaps.includes(curPoint))
) {
// 2.当前指型可以被已选指型覆盖,则跳出本次循环
return prevArr
}
}
// 3.指型不能互相覆盖,则加入新指型
prevArr.push(curChord)
return prevArr
},
[list[0]]
)
}

// 检索根音位置,获取该根音匹配的所有和弦指位
keyboard.forEach((grades, stringIndex) => {
// 有几根弦 > 和弦音数
Expand All @@ -430,8 +432,6 @@ const transChordTaps = (
list = []
// 获取该根音下所有和弦
findNextString(point.string, [point], list)
// 过滤无效和弦
list = list.filter(integrityFilter).filter(fingersFilter).filter(repeatingPitchFilter)
// 增加当前point为根音的和弦
root.chordTapsList.push(...list)
}
Expand All @@ -442,13 +442,15 @@ const transChordTaps = (
// 扁平化多转位和弦
overRoots.forEach((item) => {
// 格式化当前转位的所有和弦
let tempList = item.chordTapsList.sort(gradeSorter).map(
(taps) => ({ chordType: item.chordType, chordTaps: taps } as BoardChord)
)
// 所有和弦指位去重
tempList = coverTapsReduce(tempList)

if(tempList){
let tempList = item.chordTapsList
.filter(integrityFilter) // 过滤无效和弦
.filter(fingersFilter)
.filter(repeatingPitchFilter)
.reduce(coverTapsReducer, []) // 移除和弦指型覆盖
.sort(gradeSorter) // 按最低品排序
.map((taps) => ({ chordType: item.chordType, chordTaps: taps } as BoardChord))

if (tempList) {
tapsList.push(...tempList)
}
})
Expand Down

0 comments on commit 1b0aeda

Please sign in to comment.