Hezu06 commited on
Commit
941bcc7
·
1 Parent(s): b00f1b7

reduce loop length in generate_ai_midi function to enhance performance

Browse files
Files changed (2) hide show
  1. index.html +103 -105
  2. main.py +1 -1
index.html CHANGED
@@ -88,132 +88,130 @@
88
  <div id="status">Chưa kết nối... Mở nRF Connect trên điện thoại để chuẩn bị!</div>
89
  </div>
90
 
91
- <script>
92
  let currentBpm = 0;
93
- let currentAudio = null; // Biến toàn cục để quản lý file âm thanh
 
94
 
95
  const bpmDisplay = document.getElementById('bpm-display');
96
  const statusText = document.getElementById('status');
97
  const btnConnect = document.getElementById('btn-connect');
98
- const btnGenerate = document.getElementById('btn-generate');
99
- const btnStop = document.getElementById('btn-stop');
100
 
101
- // ==========================================
102
- // 1. BLUETOOTH LOGIC
103
- // ==========================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  btnConnect.addEventListener('click', async () => {
105
  try {
106
- statusText.innerText = "Đang mở máy quét Bluetooth...";
 
107
  const device = await navigator.bluetooth.requestDevice({
108
  acceptAllDevices: true,
109
- optionalServices: ['heart_rate']
 
 
 
 
110
  });
111
 
112
- statusText.innerText = `Đã chọn: ${device.name}. Đang kết nối...`;
 
113
  const server = await device.gatt.connect();
114
- const service = await server.getPrimaryService('heart_rate');
115
- const characteristic = await service.getCharacteristic('heart_rate_measurement');
116
-
117
- await characteristic.startNotifications();
118
- characteristic.addEventListener('characteristicvaluechanged', handleHeartRateData);
119
-
120
- statusText.innerText = "Kết nối thành công! Đang đợi nhịp tim truyền lên...";
121
- btnConnect.innerText = "✓ Đã kết nối Bluetooth";
122
- btnConnect.style.backgroundColor = "#4ecca3";
123
- btnConnect.style.color = "#1a1a2e";
124
- } catch (error) {
125
- console.error("Bluetooth Error:", error);
126
- statusText.innerText = "Hủy kết nối hoặc lỗi thiết bị!";
127
- statusText.style.color = "#ff4d4d";
128
- }
129
- });
130
 
131
- function handleHeartRateData(event) {
132
- const value = event.target.value;
133
- const flags = value.getUint8(0);
134
-
135
- if ((flags & 0x01) === 0) {
136
- currentBpm = value.getUint8(1);
137
- } else {
138
- currentBpm = value.getUint16(1, true);
139
- }
140
-
141
- bpmDisplay.innerText = `${currentBpm} BPM`;
142
- bpmDisplay.style.color = "#e94560";
143
- statusText.innerText = "Đang đọc nhịp tim thành công. Sẵn sàng tạo nhạc!";
144
- statusText.style.color = "#4ecca3";
145
- }
146
 
147
- // ==========================================
148
- // 2. TẠO VÀ PHÁT NHẠC
149
- // ==========================================
150
- btnGenerate.addEventListener('click', async () => {
151
- if (currentBpm === 0) {
152
- alert("Bạn chưa kết nối Bluetooth hoặc chưa gửi số nhịp tim từ nRF Connect!");
153
- return;
154
- }
155
 
156
- // TÍNH NĂNG MỚI: Tắt ngay bài nhạc cũ (nếu có) trước khi tạo bài mới
157
- if (currentAudio) {
158
- currentAudio.pause();
159
- currentAudio.currentTime = 0; // Tua lại từ đầu
160
- bpmDisplay.style.animation = "none";
161
- }
162
 
163
- statusText.innerText = `Đang gửi ${currentBpm} BPM cho bộ não AI xử lý...`;
164
- btnGenerate.innerText = "AI đang sáng tác...";
165
- btnGenerate.disabled = true;
166
- btnStop.disabled = true;
167
 
168
- try {
169
- const response = await fetch('/generate-vibe', {
170
- method: 'POST',
171
- headers: { 'Content-Type': 'application/json' },
172
- body: JSON.stringify({ bpm: currentBpm })
173
- });
174
-
175
- const data = await response.json();
176
-
177
- if (data.status === "success") {
178
- statusText.innerText = "Sáng tác xong! Đang phát nhạc 🎵";
179
-
180
- // Gắn file nhạc mới vào biến toàn cục
181
- currentAudio = new Audio(data.audio_url);
182
- currentAudio.play();
183
-
184
- bpmDisplay.style.animation = "pulse 1s infinite";
185
- btnStop.disabled = false; // Mở khóa nút Dừng
186
-
187
- // Xử lý khi nhạc tự chạy hết
188
- currentAudio.onended = () => {
189
- bpmDisplay.style.animation = "none";
190
- statusText.innerText = "Bản nhạc đã kết thúc. Sẵn sàng tạo trải nghiệm mới!";
191
- btnStop.disabled = true;
192
- };
193
- } else {
194
- statusText.innerText = `Lỗi từ Server: ${data.message}`;
195
  }
196
- } catch (error) {
197
- console.error("API Error:", error);
198
- statusText.innerText = "Mất kết nối với máy chủ AI!";
199
- } finally {
200
- btnGenerate.innerText = "2. Sinh nhạc AI";
201
- btnGenerate.disabled = false;
202
- }
203
- });
204
 
205
- // ==========================================
206
- // 3. DỪNG NHẠC THỦ CÔNG
207
- // ==========================================
208
- btnStop.addEventListener('click', () => {
209
- if (currentAudio) {
210
- currentAudio.pause(); // Cắt âm thanh
211
- currentAudio.currentTime = 0; // Xóa cache phát
212
- bpmDisplay.style.animation = "none"; // Tắt nhấp nháy
213
- statusText.innerText = "Đã dừng phát nhạc.";
214
- btnStop.disabled = true; // Khóa lại nút dừng
215
  }
216
  });
217
- </script>
218
  </body>
219
  </html>
 
88
  <div id="status">Chưa kết nối... Mở nRF Connect trên điện thoại để chuẩn bị!</div>
89
  </div>
90
 
91
+ <script>
92
  let currentBpm = 0;
93
+ let detectedCharUUID = null;
94
+ let bpmHistory = [];
95
 
96
  const bpmDisplay = document.getElementById('bpm-display');
97
  const statusText = document.getElementById('status');
98
  const btnConnect = document.getElementById('btn-connect');
 
 
99
 
100
+ // ================================
101
+ // HELPER: SMOOTH BPM
102
+ // ================================
103
+ function smoothBpm(newVal) {
104
+ bpmHistory.push(newVal);
105
+ if (bpmHistory.length > 5) bpmHistory.shift();
106
+
107
+ return Math.round(
108
+ bpmHistory.reduce((a, b) => a + b, 0) / bpmHistory.length
109
+ );
110
+ }
111
+
112
+ // ================================
113
+ // HELPER: PARSE DATA
114
+ // ================================
115
+ function handleAutoData(event, uuid) {
116
+ const value = event.target.value;
117
+
118
+ let raw = [];
119
+ for (let i = 0; i < value.byteLength; i++) {
120
+ raw.push(value.getUint8(i));
121
+ }
122
+
123
+ console.log("📡 UUID:", uuid, "DATA:", raw);
124
+
125
+ // ===== AUTO DETECT BPM =====
126
+ for (let i = 0; i < raw.length; i++) {
127
+ let v = raw[i];
128
+
129
+ // heuristic: BPM range
130
+ if (v >= 40 && v <= 180) {
131
+
132
+ let newBpm = smoothBpm(v);
133
+
134
+ // filter noise (tránh nhảy lung tung)
135
+ if (currentBpm !== 0 && Math.abs(newBpm - currentBpm) > 40) {
136
+ continue;
137
+ }
138
+
139
+ currentBpm = newBpm;
140
+
141
+ bpmDisplay.innerText = `${currentBpm} BPM`;
142
+ bpmDisplay.style.color = "#e94560";
143
+
144
+ statusText.innerText = `Đã detect BPM từ UUID: ${uuid}`;
145
+ statusText.style.color = "#4ecca3";
146
+
147
+ detectedCharUUID = uuid;
148
+
149
+ break;
150
+ }
151
+ }
152
+ }
153
+
154
+ // ================================
155
+ // MAIN: AUTO SCAN BLE
156
+ // ================================
157
  btnConnect.addEventListener('click', async () => {
158
  try {
159
+ statusText.innerText = "Đang mở BLE scanner (auto)...";
160
+
161
  const device = await navigator.bluetooth.requestDevice({
162
  acceptAllDevices: true,
163
+ optionalServices: [
164
+ 'battery_service',
165
+ 'device_information',
166
+ 'heart_rate'
167
+ ]
168
  });
169
 
170
+ statusText.innerText = `Đã chọn: ${device.name || "Unknown"} đang connect...`;
171
+
172
  const server = await device.gatt.connect();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
+ const services = await server.getPrimaryServices();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
+ statusText.innerText = "Đang scan toàn bộ services... (check console)";
 
 
 
 
 
 
 
177
 
178
+ for (const service of services) {
179
+ console.log("🔵 Service:", service.uuid);
 
 
 
 
180
 
181
+ const characteristics = await service.getCharacteristics();
 
 
 
182
 
183
+ for (const char of characteristics) {
184
+ console.log(" ⚪ Char:", char.uuid, char.properties);
185
+
186
+ // chỉ lấy char có notify / indicate
187
+ if (char.properties.notify || char.properties.indicate) {
188
+ try {
189
+ await char.startNotifications();
190
+
191
+ char.addEventListener(
192
+ 'characteristicvaluechanged',
193
+ (event) => handleAutoData(event, char.uuid)
194
+ );
195
+
196
+ console.log(" ✅ Subscribed:", char.uuid);
197
+ } catch (err) {
198
+ console.log(" ❌ Cannot subscribe:", char.uuid);
199
+ }
200
+ }
201
+ }
 
 
 
 
 
 
 
 
202
  }
 
 
 
 
 
 
 
 
203
 
204
+ statusText.innerText = "Đã subscribe toàn bộ notify characteristics. Đang chờ BPM...";
205
+ btnConnect.innerText = "✓ BLE Connected (Auto Mode)";
206
+ btnConnect.style.backgroundColor = "#4ecca3";
207
+ btnConnect.style.color = "#1a1a2e";
208
+
209
+ } catch (error) {
210
+ console.error("❌ BLE ERROR:", error);
211
+ statusText.innerText = "Lỗi BLE hoặc user cancel!";
212
+ statusText.style.color = "#ff4d4d";
 
213
  }
214
  });
215
+ </script>
216
  </body>
217
  </html>
main.py CHANGED
@@ -231,7 +231,7 @@ def generate_ai_midi(bpm: int, output_file: str, num_notes: int = 200):
231
  inst.midiChannel = 0
232
  final_stream.insert(0, inst)
233
 
234
- LOOP = 4 # 🔥 tăng độ dài nhạc
235
  total_length = offset # Lưu lại tổng chiều dài của 1 loop
236
 
237
  for i in range(LOOP):
 
231
  inst.midiChannel = 0
232
  final_stream.insert(0, inst)
233
 
234
+ LOOP = 2 # 🔥 tăng độ dài nhạc
235
  total_length = offset # Lưu lại tổng chiều dài của 1 loop
236
 
237
  for i in range(LOOP):