Skip to content

Commit

Permalink
finish basic UI; design the logo!
Browse files Browse the repository at this point in the history
  • Loading branch information
madderscientist committed Feb 5, 2024
1 parent f56cc07 commit 4732a96
Show file tree
Hide file tree
Showing 24 changed files with 187 additions and 52 deletions.
41 changes: 38 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,35 @@
<div align="center">
<a href="https://madderscientist.github.io/noteDigger/" target="_blank">
<img width="200" src="./img/logo.png" alt="logo" style="display:block;">
<img width="180" src="./img/logo_text.png" alt="noteDigger" style="display:block; margin: 1em;">
</a>
前端辅助人工扒谱工具~
</div>

# noteDigger!
前端扒谱。模仿的是软件wavetone。<br>
“Note Digger”——音符挖掘者,即扒谱。模仿的是软件wavetone,但是是双击即用、现代UI的前端应用。<br>
推进ing……目标是全部自己造轮子!即:不使用框架、不使用外部库;目的是减小项目大小,并掌握各个环节。目前频谱分析的软件非常多,功能也超级强大,自知比不过……所以唯一能一战的就是项目体积了!作为一个纯前端项目,就要把易用的优点完全发扬!<br>
[demo](http://htmlpreview.github.io/?https://github.com/madderscientist/noteDigger/blob/main/index.html)
[在线使用](https://madderscientist.github.io/noteDigger/)

## 使用流程
1. 在线or下载到本地,用主流现代浏览器打开(开发使用Chrome)。
2. 导入音频——文件-上传,或直接将音频拖拽进去!
3. 选择声道分析,或者导入之前分析的结果。【todo】
4. 根据频谱分析,开始绘制midi音符!调整音量,反复比对。
5. 导出为midi等,或者暂时导出项目(下次继续)【todo】

## 常规操作
- 空格: 播放
- 双击时间轴: 从双击的位置开始播放
- 在时间轴上拖拽: 设置重复区间
- 按住空白拖动: 在当前音轨绘制一个音符
- 按住音符左半边拖动: 改变位置
- 按住音符右半边拖动: 改变时长
- Ctrl+点击音符: 多选音符
- delete: 删除选中的音符
- Ctrl+滚轮: 横向缩放
- 按住中键拖拽、触摸板滑动: 移动视野
- ←↑→↓: 视野移动一格

## 快捷键
只有在导入并分析音频之后才能使用这些快捷键
Expand All @@ -14,10 +42,17 @@
- Ctrl+X: 剪贴选中的音符
- Ctrl+V: 粘贴到选中的音轨上
- Ctrl+B: 呼出/收回音轨面板
- delete: 删除选中的音符
- Shift+右键: 菜单,包含撤销/重做、复制/粘贴、删除

## 小细节
滑动条,如果旁边有数字,点击就可以恢复初始值。

## 重要更新记录
### 2024 2 5
已经能用于扒谱了!完成了midi和原曲的播放与同步,填补了扒谱过程最重要的一环。<br>
UI基本完成!将侧边栏、滑动条封装成了js类。在此基础上,设计了类似VScode的菜单,用于存放不常用的功能和界面;而顶部窄窄一条用于放置常用功能。<br>
此外,完成了logo的设计。在2月4日的commit记录中可以看到设计的多种logo,最终选定了“在勺子里的音符”,这是一个被勺子dig出来的音符。其他思路可以概括为:“音符和铲子的组合”(logo2)、“埋在地里的音符”(logo5 logo6)、“像植物一样生长的八分音符”(logo8 logo10)、“音符和铲子结合”(logo12)。

### 2024 2 1
完成了多音轨、合成器和主线的整合,象征着midi系统的完成!<br>
统一了UI风格;完善了快捷键功能;新增框选功能;修复了大部分bug。
Expand Down
35 changes: 4 additions & 31 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ function App() {
}
}
const source = this.audioContext.createMediaElementSource(a);
let last = source;
a.EQ = {
source: source,
filter: f.map((v) => {
Expand All @@ -619,11 +620,12 @@ function App() {
filter.frequency.value = v;
filter.Q.value = 1;
filter.gain.value = 0;
source.connect(filter);
filter.connect(this.audioContext.destination);
last.connect(filter);
last = filter;
return filter;
})
};
last.connect(this.audioContext.destination);
}
};
this.Keyboard = {
Expand Down Expand Up @@ -1259,35 +1261,6 @@ function App() {
else this.AudioPlayer.stop();
this.AudioPlayer.play_btn.blur(); // 防止焦点在按钮上导致空格响应失败
};
let actMode = document.getElementById('actMode').children;
actMode[0].onclick = () => {
this.MidiAction.mode = 0;
actMode[1].classList.remove('selected');
actMode[0].classList.add('selected');
};
actMode[1].onclick = () => {
if (this.MidiAction.mode == 0) this.MidiAction.mode = 1;
else {
this.MidiAction.frameXid = -1;
switch (this.MidiAction.frameMode) {
case 0:
this.MidiAction.frameMode = 1;
actMode[1].firstElementChild.className = 'iconfont icon-range';
break;
case 1:
this.MidiAction.frameMode = 2;
actMode[1].firstElementChild.style.rotate = '90deg';
break;
case 2:
this.MidiAction.frameMode = 0;
actMode[1].firstElementChild.style.rotate = '0deg';
actMode[1].firstElementChild.className = 'iconfont icon-select';
break;
}
}
actMode[0].classList.remove('selected');
actMode[1].classList.add('selected');
};
window.addEventListener('load', () => { this.resize(); });
window.addEventListener('resize', () => { this.resize(); });
this.HscrollBar.thumb.addEventListener('mousedown', this.HscrollBar.thumbMousedown);
Expand Down
Binary file added favicon.ico
Binary file not shown.
File renamed without changes
Binary file added img/logo-small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/logo_text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 77 additions & 11 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>在线扒谱</title>
<link rel="Shortcut Icon" href="./favicon.ico" type="image/x-icon" />
<title>noteDigger~在线扒谱</title>
<script src="./siderMenu.js"></script>
<script src="./myRange.js"></script>
<script src="./dataProcess/fft_real.js"></script>
Expand All @@ -22,9 +23,11 @@
<link rel="stylesheet" href="./style/channelDiv.css">
<link rel="stylesheet" href="./style/icon/iconfont.css">
</head>

<body class="fc">
<!-- 上半部分 工具区 -->
<div class="tools">
<img src="./img/logo-small.png" alt="noteDigger" class="top-logo" id="LOGO">
<div>
<div class="rangeBox">
速度<input type="range" id="speedControl" max="2" min="0.25" step="0.05" value="1">
Expand All @@ -40,23 +43,24 @@
音符<input type="range" id="midivolumeControl" max="1.5" min="0" step="0.02" value="1">
</div>
<div class="rangeBox">
音频<input type="range" id="audiovolumeControl" max="1" min="0" step="0.02" value="0.3">
</div>
音频<input type="range" id="audiovolumeControl" max="1" min="0" step="0.02" value="0.2">
</div>
</div>
</div>


<div class="switch-bar" id="actMode">
<button class="selected">
<div class="iconfont icon-pen-l"></div>
</button>
<button>
<button class="iconfont icon-pen-l selected"></button>
<button><!-- 要旋转,所以包裹了一层 -->
<div class="iconfont icon-select"></div>
</button>
</div>
<div class="switch-bar">
<button class="iconfont icon-repeat selected" id="repeat-btn"></button>
</div>

<a href="https://github.com/madderscientist/noteDigger" class="f">
<img src="./style/github-mark-white.png" alt="项目地址" style="width: 34px; height: 34px;">
<img src="./img/github-mark-white.png" alt="项目地址" class="top-logo">
</a>
</div>
<!-- 下半部分 操作区 -->
Expand All @@ -83,8 +87,14 @@
</div>
</body>
<div id="tab-Contents">
<div>第一个内容</div>
<div>第二个内容</div>
<div class="paddingbox niceScroll">
<h3>EQ设置(dB)</h3>
<div id="EQcontrol">
请先上传音频!
</div>
</div>

<div class="paddingbox niceScroll">第二个内容</div>
</div>
<script>
const menu = SiderMenu.new(funcTab, funcSider, 206);
Expand All @@ -93,12 +103,68 @@
const tabContents = document.getElementById('tab-Contents').children;
menu.add('音轨', 'iconfont icon-list', app.MidiAction.channelDiv.container);
menu.add('EQ', 'iconfont icon-mixer', tabContents[0]);
menu.add('设置', 'iconfont icon-setting', tabContents[0]);
menu.add('设置', 'iconfont icon-setting', tabContents[0]); // 内容是在变的
// 在后面初始化range; reset触发oninput事件同步app中的值
LableRange.new(speedControl).reset();
myRange.new(multiControl).reset();
hideLableRange.new(midivolumeControl).reset();
hideLableRange.new(audiovolumeControl).reset();
// 事件
document.getElementById('repeat-btn').addEventListener('click', function () {
app.AudioPlayer.repeat = this.classList.toggle('selected');
this.blur();
});
let actMode = document.getElementById('actMode').children;
actMode[0].onclick = () => {
app.MidiAction.mode = 0;
actMode[1].classList.remove('selected');
actMode[0].classList.add('selected');
};
actMode[1].onclick = () => {
if (app.MidiAction.mode == 0) app.MidiAction.mode = 1;
else {
app.MidiAction.frameXid = -1;
switch (app.MidiAction.frameMode) {
case 0:
app.MidiAction.frameMode = 1;
actMode[1].firstElementChild.className = 'iconfont icon-range';
break;
case 1:
app.MidiAction.frameMode = 2;
actMode[1].firstElementChild.style.rotate = '90deg';
break;
case 2:
app.MidiAction.frameMode = 0;
actMode[1].firstElementChild.style.rotate = '0deg';
actMode[1].firstElementChild.className = 'iconfont icon-select';
break;
}
}
actMode[0].classList.remove('selected');
actMode[1].classList.add('selected');
};
// EQ
function addEQ({detail}) {
if (detail >= 0) return;
EQcontrol.innerHTML = '';
const filters = app.AudioPlayer.audio.EQ.filter;
function controlfilter() {
this.filter.gain.value = parseInt(this.value);
}
for (const f of filters) {
const Hz = document.createElement('h5');
Hz.textContent = f.frequency.value + ' Hz';
EQcontrol.appendChild(Hz);
const r = document.createElement('input'); r.type = 'range';
r.max = 40; r.min = -40;
r.value = f.gain.value;
r.step = 1;
r.filter = f;
r.addEventListener('input', controlfilter);
EQcontrol.appendChild(r);
LableRange.new(r).reset();
} app.event.removeEventListener('progress', addEQ);
} app.event.addEventListener('progress', addEQ);
</script>
<script>
const dragEvents = {
Expand Down
Binary file removed logo/logo.png
Binary file not shown.
Binary file removed logo/logo10.png
Binary file not shown.
Binary file removed logo/logo12.png
Binary file not shown.
Binary file removed logo/logo13.png
Binary file not shown.
Binary file removed logo/logo14.png
Binary file not shown.
Binary file removed logo/logo2.png
Binary file not shown.
Binary file removed logo/logo5.png
Binary file not shown.
Binary file removed logo/logo6.png
Binary file not shown.
Binary file removed logo/logo8.png
Binary file not shown.
2 changes: 1 addition & 1 deletion siderMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SiderMenu extends HTMLDivElement {
/**
* 构造tabMenu和container
* @param {HTMLDivElement} menu 存放tab的 样式: .siderTabs 每一个tab: .siderTab
* @param {HTMLDivElement} container 展示具体内容的 样式: .siderContent 拖动条: .siderBar
* @param {HTMLDivElement} container 展示具体内容的 样式: .siderContent 拖动条: .siderBar 每一个子内容都会加上siderItem类
* @param {Number} minWidth 展示具体内容的最小宽度
* @returns
*/
Expand Down
10 changes: 7 additions & 3 deletions style/icon/iconfont.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4420000 */
src: url('iconfont.woff2?t=1707023823701') format('woff2'),
url('iconfont.woff?t=1707023823701') format('woff'),
url('iconfont.ttf?t=1707023823701') format('truetype');
src: url('iconfont.woff2?t=1707111553693') format('woff2'),
url('iconfont.woff?t=1707111553693') format('woff'),
url('iconfont.ttf?t=1707111553693') format('truetype');
}

.iconfont {
Expand All @@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale;
}

.icon-repeat:before {
content: "\e628";
}

.icon-mixer:before {
content: "\e660";
}
Expand Down
Binary file modified style/icon/iconfont.ttf
Binary file not shown.
Binary file modified style/icon/iconfont.woff
Binary file not shown.
Binary file modified style/icon/iconfont.woff2
Binary file not shown.
12 changes: 12 additions & 0 deletions style/siderMenu.css
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,16 @@
background-color: var(--theme-middle);
width: 100%;
height: 100%;
}

/* siderItem不提供内边距,用paddingbox类实现 */
.paddingbox {
box-sizing: border-box;
padding: 0.4em 0.8em;
overflow: auto;
}

.siderItem h3 {
margin: 0;
padding: 0;
}
51 changes: 48 additions & 3 deletions style/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,19 @@ canvas {
.tools {
background-color: transparent;
display: flex;
justify-content: space-around;
justify-content: space-between;
align-items: center;
padding: 2px;
}

.top-logo {
height: 36px;
padding: 0 8px;
cursor: pointer;
}

#LOGO:hover {
background-color: var(--theme-middle);
}

/* 可以套在外面的盒子,盒子中可以放属性名 */
Expand Down Expand Up @@ -137,6 +148,8 @@ canvas {
padding: 0.5em 0.6em;
border-radius: 0;
background: rgb(50, 53, 62);
/* 恢复默认大小 */
font-size: 16px;
}

.switch-bar button:first-child {
Expand All @@ -152,7 +165,39 @@ canvas {
.switch-bar .selected {
background-color: rgb(60, 87, 221);
}
.switch-bar div {
margin: 0;

/* EQ控制面板 */
#EQcontrol {
display: flex;
flex-direction: column;
align-items: center;
}
/* 频率值 */
#EQcontrol h5 {
margin: 0.4em 0 0 0;
padding: 0;
}
#EQcontrol .myrange {
width: 100%;
margin: 0 0 0.3em 0;
}
#EQcontrol input {
width: 100%;
margin: 0 5px 0 0;
}

/* 漂亮的滑动条 */
.niceScroll {
overflow: auto;
}
.niceScroll::-webkit-scrollbar {
width: 12px;
}
.niceScroll::-webkit-scrollbar-thumb {
background-color: rgb(50, 53, 62);
border: 3px solid rgb(37, 38, 45);
border-radius: 6px;
}
.niceScroll::-webkit-scrollbar-track, ::-webkit-scrollbar-corner {
background-color: rgb(37, 38, 45);
}

1 comment on commit 4732a96

@madderscientist
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

还剩:

  • 设置界面暴露一些设置内容:宽、高、重复区间精准设置、遮罩透明度
  • 结果的导入导出
  • 导出为midi或数字谱
  • 顶部工具栏还要美化,再加一些工具:自动滚屏
  • logo当做文件菜单,想办法修改右键菜单实现其下拉菜单
  • 自动分析工具:比如阈值多少以上的在某个区间内的全部创建音符;调性统计分析【后话】

Please sign in to comment.