diff --git a/.gitmodules b/.gitmodules
index 193102c4..54120b54 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,9 @@
[submodule "plugins/libs/wil"]
path = plugins/libs/wil
url = https://github.com/microsoft/wil.git
+[submodule "plugins/libs/tinymp3"]
+ path = plugins/libs/tinymp3
+ url = https://github.com/HIllya51/tinymp3
+[submodule "plugins/libs/miniaudio"]
+ path = plugins/libs/miniaudio
+ url = https://github.com/HIllya51/miniaudio
diff --git a/LunaTranslator/LunaTranslator/gui/showword.py b/LunaTranslator/LunaTranslator/gui/showword.py
index 976083e5..d52a4cae 100644
--- a/LunaTranslator/LunaTranslator/gui/showword.py
+++ b/LunaTranslator/LunaTranslator/gui/showword.py
@@ -16,9 +16,9 @@ from PyQt5.QtWidgets import (
)
from PyQt5.QtGui import QPixmap, QImage
from traceback import print_exc
-import requests, json, subprocess, time
-from PyQt5.QtCore import pyqtSignal, Qt, QUrl
-import qtawesome, functools, os, base64
+import requests, json, time
+from PyQt5.QtCore import pyqtSignal, Qt
+import qtawesome, functools, os, base64, winsharedutils
import gobject, uuid, windows, platform
from myutils.config import globalconfig, _TR, static_data
import myutils.ankiconnect as anki
@@ -33,38 +33,12 @@ from gui.usefulwidget import (
getcolorbutton,
tabadd_lazy,
)
-from myutils.subproc import subproc_w, autoproc
-
+from myutils.subproc import subproc_w
from myutils.wrapper import threader
from myutils.ocrutil import imageCut, ocr_run
from gui.rangeselect import rangeselct_function
-class ffmpeg_virtual_audio_capturer:
- def __init__(self):
- os.makedirs("./cache/tts", exist_ok=True)
- self.file = os.path.abspath(
- os.path.join("./cache/tts", str(time.time()) + ".mp3")
- )
- try:
- self.engine = subprocess.Popen(
- os.path.join(
- globalconfig["ffmpeg"],
- f'ffmpeg.exe -f dshow -i audio="virtual-audio-capturer" "{self.file}"',
- ),
- stdin=subprocess.PIPE,
- )
- except:
- print_exc()
-
- def end(self):
- try:
- self.engine.stdin.write(b"q")
- self.engine.stdin.flush()
- except:
- pass
-
-
class loopbackrecorder:
def __init__(self):
os.makedirs("./cache/tts", exist_ok=True)
@@ -72,26 +46,37 @@ class loopbackrecorder:
os.path.join("./cache/tts", str(time.time()) + ".wav")
)
try:
- if platform.architecture()[0] == "64bit":
- _6432 = "64"
- elif platform.architecture()[0] == "32bit":
- _6432 = "32"
self.waitsignal = str(time.time())
- self.engine = autoproc(
- subproc_w(
- './files/plugins/shareddllproxy{}.exe recordaudio "{}" "{}"'.format(
- _6432, self.file, self.waitsignal
- ),
- name="recordaudio",
- )
+ self.engine = subproc_w(
+ './files/plugins/shareddllproxy32.exe recordaudio "{}" "{}"'.format(
+ self.file, self.waitsignal
+ ),
)
except:
print_exc()
- def end(self):
+ @threader
+ def end(self, callback):
windows.SetEvent(
windows.AutoHandle(windows.CreateEvent(False, False, self.waitsignal))
)
+ self.engine.wait()
+ filewav = self.file
+ if os.path.exists(filewav) == False:
+ callback("")
+ return
+ filemp3 = filewav.replace(".wav", ".mp3")
+ subproc_w(
+ './files/plugins/shareddllproxy32.exe mainmp3 "{}" "{}"'.format(
+ filewav, filemp3
+ ),
+ run=True,
+ )
+ if os.path.exists(filemp3):
+ os.remove(filewav)
+ callback(filemp3)
+ else:
+ callback(filewav)
class statusbutton(QPushButton):
@@ -390,49 +375,13 @@ class AnkiWindow(QWidget):
getsimpleswitch(globalconfig["ankiconnect"], "autoruntts"),
)
- layout.addWidget(QLabel())
- layout.addRow(_TR("录音"), QLabel())
- lb = QLabel()
- lb.setOpenExternalLinks(True)
- lb.setText(
- 'virtual-audio-capturer'
- )
- layout.addRow(_TR("安装录音驱动"), lb)
- ffmpegpath = getlineedit(globalconfig, "ffmpeg", readonly=True)
-
- def selectpath():
- f = QFileDialog.getExistingDirectory()
- if f != "":
- ffmpegpath.setText(f)
-
- layout.addRow(
- _TR("ffmpeg"),
- getboxlayout(
- [
- ffmpegpath,
- getcolorbutton(
- "",
- "",
- selectpath,
- icon="fa.gear",
- constcolor="#FF69B4",
- ),
- ],
- makewidget=True,
- ),
- )
-
return wid
def startorendrecord(self, target: QLineEdit, idx):
if idx == 1:
- if len(globalconfig["ffmpeg"]) and os.path.exists(globalconfig["ffmpeg"]):
- self.recorder = ffmpeg_virtual_audio_capturer()
- else:
- self.recorder = loopbackrecorder()
+ self.recorder = loopbackrecorder()
else:
- self.recorder.end()
- target.setText(self.recorder.file)
+ self.recorder.end(callback=target.setText)
def createaddtab(self):
layout = QVBoxLayout()
diff --git a/LunaTranslator/LunaTranslator/myutils/utils.py b/LunaTranslator/LunaTranslator/myutils/utils.py
index 9a72980f..05123be0 100644
--- a/LunaTranslator/LunaTranslator/myutils/utils.py
+++ b/LunaTranslator/LunaTranslator/myutils/utils.py
@@ -20,8 +20,9 @@ from myutils.config import (
savehook_new_data,
getdefaultsavehook,
)
+from ctypes import c_float, pointer, c_void_p
import threading
-import re, heapq
+import re, heapq, winsharedutils
from myutils.vndb import searchfordata, getvidbytitle
from myutils.wrapper import tryprint
@@ -260,48 +261,36 @@ class wavmp3player:
if task is None:
continue
binary, volume, force = task
- os.makedirs("./cache/tts", exist_ok=True)
+ durationms = self._playsoundWin(binary, volume)
- tgt = os.path.abspath("./cache/tts/" + str(time.time()) + ".wav")
- with open(tgt, "wb") as ff:
- ff.write(binary)
- durationms = self._playsoundWin(tgt, volume)
- self.lastfile = tgt
if durationms and globalconfig["ttsnointerrupt"]:
while durationms > 0:
durationms -= 100
time.sleep(0.1)
if self.tasks and self.tasks[-1]:
break
- # time.sleep(durationms / 1000)
except:
print_exc()
- def _playsoundWin(self, sound, volume):
+ def _playsoundWin(self, binary, volume):
try:
-
- windows.mciSendString(("stop lunatranslator_mci_{}".format(self.i)))
- windows.mciSendString(("close lunatranslator_mci_{}".format(self.i)))
- self.i += 1
+ duration = c_float()
+ device = c_void_p()
+ decoder = c_void_p()
+ succ = winsharedutils.PlayAudioInMem(
+ binary,
+ len(binary),
+ volume / 100,
+ pointer(decoder),
+ pointer(device),
+ pointer(duration),
+ )
+ if succ != 0:
+ return 0
if self.lastfile:
- os.remove(self.lastfile)
- self.lastfile = sound
- windows.mciSendString(
- 'open "{}" type mpegvideo alias lunatranslator_mci_{}'.format(
- sound, self.i
- )
- )
- durationms = int(
- windows.mciSendString(
- "status lunatranslator_mci_{} length".format(self.i)
- )
- )
- windows.mciSendString(
- "setaudio lunatranslator_mci_{} volume to {}".format(
- self.i, volume * 10
- )
- )
- windows.mciSendString(("play lunatranslator_mci_{}".format(self.i)))
+ winsharedutils.PlayAudioInMem_Stop(self.lastfile[0], self.lastfile[1])
+ self.lastfile = decoder, device
+ durationms = duration.value * 1000
except:
durationms = 0
diff --git a/LunaTranslator/LunaTranslator/winsharedutils.py b/LunaTranslator/LunaTranslator/winsharedutils.py
index c5a7b9f5..8a7e5c67 100644
--- a/LunaTranslator/LunaTranslator/winsharedutils.py
+++ b/LunaTranslator/LunaTranslator/winsharedutils.py
@@ -16,6 +16,7 @@ from ctypes import (
create_string_buffer,
c_size_t,
windll,
+ c_float,
c_char,
)
from ctypes.wintypes import WORD, HANDLE, HWND, LONG, DWORD
@@ -186,7 +187,10 @@ html_release.argtypes = (c_void_p,)
html_get_current_url = utilsdll.html_get_current_url
html_get_current_url.argtypes = c_void_p, c_wchar_p
html_set_html = utilsdll.html_set_html
-html_set_html.argtypes = c_void_p, c_wchar_p,
+html_set_html.argtypes = (
+ c_void_p,
+ c_wchar_p,
+)
class HTMLBrowser:
@@ -333,3 +337,17 @@ startmaglistener = utilsdll.startmaglistener
startmaglistener.restype = HANDLE
endmaglistener = utilsdll.endmaglistener
endmaglistener.argtypes = (HANDLE,)
+
+PlayAudioInMem = utilsdll.PlayAudioInMem
+PlayAudioInMem.argtypes = (
+ c_void_p,
+ c_size_t,
+ c_float,
+ c_void_p,
+ c_void_p,
+ POINTER(c_float),
+)
+PlayAudioInMem.restype = c_int
+
+PlayAudioInMem_Stop = utilsdll.PlayAudioInMem_Stop
+PlayAudioInMem_Stop.argtypes = c_void_p, c_void_p
diff --git a/LunaTranslator/files/defaultconfig/config.json b/LunaTranslator/files/defaultconfig/config.json
index 924965cc..94fa9535 100644
--- a/LunaTranslator/files/defaultconfig/config.json
+++ b/LunaTranslator/files/defaultconfig/config.json
@@ -54,7 +54,6 @@
"changecharset": false,
"changecharset_charset": 2
},
- "ffmpeg": "",
"requestinterval": 1,
"keepontop": true,
"buttonsize": 20,
diff --git a/LunaTranslator/files/lang/ar.json b/LunaTranslator/files/lang/ar.json
index 85116dbf..f8753b01 100644
--- a/LunaTranslator/files/lang/ar.json
+++ b/LunaTranslator/files/lang/ar.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "التعرف الضوئي على الحروف",
"优先级": "الأولوية",
"编码": "ترميز",
- "安装录音驱动": "تثبيت برنامج تشغيل التسجيل",
- "录音": "تسجيل صوتي",
"自动TTS": "التلقائي تحويل النص إلى كلام",
"使用webview显示": "عرض باستخدام WebView"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/cht.json b/LunaTranslator/files/lang/cht.json
index e233d2c7..9468500d 100644
--- a/LunaTranslator/files/lang/cht.json
+++ b/LunaTranslator/files/lang/cht.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "截圖後進行OCR",
"优先级": "優先順序",
"编码": "編碼",
- "安装录音驱动": "安裝錄音驅動",
- "录音": "錄音",
"自动TTS": "自動TTS",
"使用webview显示": "使用webview顯示"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/en.json b/LunaTranslator/files/lang/en.json
index 36b73a40..7d7a9664 100644
--- a/LunaTranslator/files/lang/en.json
+++ b/LunaTranslator/files/lang/en.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "Perform OCR after taking screenshots",
"优先级": "priority",
"编码": "coding",
- "安装录音驱动": "Install recording driver",
- "录音": "tape",
"自动TTS": "Automatic TTS",
"使用webview显示": "Display using webview"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/es.json b/LunaTranslator/files/lang/es.json
index 9a72c073..5641b665 100644
--- a/LunaTranslator/files/lang/es.json
+++ b/LunaTranslator/files/lang/es.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "OCR después de la captura de pantalla",
"优先级": "Prioridad",
"编码": "Codificación",
- "安装录音驱动": "Instalación de la unidad de grabación",
- "录音": "Grabación",
"自动TTS": "TTS automático",
"使用webview显示": "Mostrar con Webview"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/fr.json b/LunaTranslator/files/lang/fr.json
index 2d439931..f73e8b7f 100644
--- a/LunaTranslator/files/lang/fr.json
+++ b/LunaTranslator/files/lang/fr.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "OCR après capture d'écran",
"优先级": "Priorité",
"编码": "Codage",
- "安装录音驱动": "Installer le driver d'enregistrement",
- "录音": "Enregistrement sonore",
"自动TTS": "Tts automatique",
"使用webview显示": "Afficher avec webview"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/it.json b/LunaTranslator/files/lang/it.json
index 2b1caaff..32a25380 100644
--- a/LunaTranslator/files/lang/it.json
+++ b/LunaTranslator/files/lang/it.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "Esegui OCR dopo aver scattato screenshot",
"优先级": "priorità",
"编码": "codifica",
- "安装录音驱动": "Installa il driver di registrazione",
- "录音": "nastro",
"自动TTS": "TTS automatico",
"使用webview显示": "Visualizzazione tramite webview"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/ja.json b/LunaTranslator/files/lang/ja.json
index a9a183b4..17c10e63 100644
--- a/LunaTranslator/files/lang/ja.json
+++ b/LunaTranslator/files/lang/ja.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "スクリーンショット後にOCR",
"优先级": "優先度",
"编码": "エンコード",
- "安装录音驱动": "録音ドライブのインストール",
- "录音": "レコーディング",
"自动TTS": "自動TTS",
"使用webview显示": "webview表示の使用"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/ko.json b/LunaTranslator/files/lang/ko.json
index bdd6ef33..cbcb888f 100644
--- a/LunaTranslator/files/lang/ko.json
+++ b/LunaTranslator/files/lang/ko.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "캡처해서 OCR 진행하도록 하겠습니다.",
"优先级": "우선 순위",
"编码": "인코딩",
- "安装录音驱动": "녹음 드라이브 설치",
- "录音": "녹음",
"自动TTS": "자동 TTS",
"使用webview显示": "웹뷰를 사용하여 표시"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/pl.json b/LunaTranslator/files/lang/pl.json
index 951a1b3b..a528170d 100644
--- a/LunaTranslator/files/lang/pl.json
+++ b/LunaTranslator/files/lang/pl.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "Wykonanie OCR po wykonaniu zrzutów ekranu",
"优先级": "priorytet",
"编码": "kodowanie",
- "安装录音驱动": "Zainstaluj sterownik nagrywania",
- "录音": "taśma",
"自动TTS": "Automatyczny TTS",
"使用webview显示": "Wyświetlanie przy użyciu widoku internetowego"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/ru.json b/LunaTranslator/files/lang/ru.json
index 936dd5ba..3568101d 100644
--- a/LunaTranslator/files/lang/ru.json
+++ b/LunaTranslator/files/lang/ru.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "Снимок экрана после OCR",
"优先级": "Приоритеты",
"编码": "Код",
- "安装录音驱动": "Установка привода звукозаписи",
- "录音": "Запись",
"自动TTS": "Автоматический TTS",
"使用webview显示": "Использовать webview"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/th.json b/LunaTranslator/files/lang/th.json
index 904cbd17..4000b2d8 100644
--- a/LunaTranslator/files/lang/th.json
+++ b/LunaTranslator/files/lang/th.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "ทำ OCR หลังจากจับภาพหน้าจอ",
"优先级": "ลำดับความสำคัญ",
"编码": "การเข้ารหัส",
- "安装录音驱动": "ติดตั้งไดรฟ์บันทึก",
- "录音": "การบันทึกเสียง",
"自动TTS": "TTS อัตโนมัติ",
"使用webview显示": "ใช้ webview เพื่อแสดงผล"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/tr.json b/LunaTranslator/files/lang/tr.json
index c5d6f216..c92af5d8 100644
--- a/LunaTranslator/files/lang/tr.json
+++ b/LunaTranslator/files/lang/tr.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "Ekran fotoğraflarını aldıktan sonra OCR yap",
"优先级": "Prioritet",
"编码": "coding",
- "安装录音驱动": "Kayıt sürücüsünü kur",
- "录音": "kaset",
"自动TTS": "Otomatik TTS",
"使用webview显示": "Web görüntüsünü kullanarak göster"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/uk.json b/LunaTranslator/files/lang/uk.json
index d40a9ae8..27275c79 100644
--- a/LunaTranslator/files/lang/uk.json
+++ b/LunaTranslator/files/lang/uk.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "Виконати OCR після роботи знімків екрана",
"优先级": "пріоритет",
"编码": "кодування",
- "安装录音驱动": "Встановити драйвер запису",
- "录音": "стрічку",
"自动TTS": "Автоматичний TTS",
"使用webview显示": "Показувати за допомогою веб- перегляду"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/vi.json b/LunaTranslator/files/lang/vi.json
index a4dca34d..8622a8e1 100644
--- a/LunaTranslator/files/lang/vi.json
+++ b/LunaTranslator/files/lang/vi.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "OCR sau khi chụp ảnh màn hình",
"优先级": "Ưu tiên",
"编码": "Mã hóa",
- "安装录音驱动": "Cài đặt Recording Drive",
- "录音": "Ghi âm",
"自动TTS": "Tự động TTS",
"使用webview显示": "Sử dụng WebView để hiển thị"
}
\ No newline at end of file
diff --git a/LunaTranslator/files/lang/zh.json b/LunaTranslator/files/lang/zh.json
index a281f896..0c90a7cc 100644
--- a/LunaTranslator/files/lang/zh.json
+++ b/LunaTranslator/files/lang/zh.json
@@ -789,8 +789,6 @@
"截图后进行OCR": "",
"优先级": "",
"编码": "",
- "安装录音驱动": "",
- "录音": "",
"自动TTS": "",
"使用webview显示": ""
}
\ No newline at end of file
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index faf9f693..d91db755 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -29,7 +29,7 @@ include(generate_product_version)
set(VERSION_MAJOR 2)
set(VERSION_MINOR 51)
-set(VERSION_PATCH 7)
+set(VERSION_PATCH 8)
add_library(pch pch.cpp)
target_precompile_headers(pch PUBLIC pch.h)
diff --git a/plugins/libs/libs.cmake b/plugins/libs/libs.cmake
index 14974665..9ce4c0d0 100644
--- a/plugins/libs/libs.cmake
+++ b/plugins/libs/libs.cmake
@@ -8,6 +8,9 @@ include_directories(${CMAKE_CURRENT_LIST_DIR})
include_directories(${CMAKE_CURRENT_LIST_DIR}/Detours-4.0.1/include)
include_directories(${CMAKE_CURRENT_LIST_DIR}/wil/include)
+include_directories(${CMAKE_CURRENT_LIST_DIR}/miniaudio)
+include_directories(${CMAKE_CURRENT_LIST_DIR}/tinymp3)
+
if(${CMAKE_SIZEOF_VOID_P} EQUAL 4)
set(LTLPlatform "Win32")
diff --git a/plugins/libs/miniaudio b/plugins/libs/miniaudio
new file mode 160000
index 00000000..4a5b74be
--- /dev/null
+++ b/plugins/libs/miniaudio
@@ -0,0 +1 @@
+Subproject commit 4a5b74bef029b3592c54b6048650ee5f972c1a48
diff --git a/plugins/libs/tinymp3 b/plugins/libs/tinymp3
new file mode 160000
index 00000000..9781d63b
--- /dev/null
+++ b/plugins/libs/tinymp3
@@ -0,0 +1 @@
+Subproject commit 9781d63bf7d057457b25b5e77492bcf2cfa109c5
diff --git a/plugins/shareddllproxy/CMakeLists.txt b/plugins/shareddllproxy/CMakeLists.txt
index c0ced5ba..d9ffed6b 100644
--- a/plugins/shareddllproxy/CMakeLists.txt
+++ b/plugins/shareddllproxy/CMakeLists.txt
@@ -12,17 +12,18 @@ generate_product_version(
)
-add_executable(shareddllproxy applicationloopbackaudio/LoopbackCapture.cpp applicationloopbackaudio/runer.cpp shareddllproxy.cpp dllinject.cpp ntleas.cpp aspatch.cpp update.cpp ${versioninfo})
+add_executable(shareddllproxy shareddllproxy.cpp dllinject.cpp ntleas.cpp aspatch.cpp update.cpp ${versioninfo})
target_precompile_headers(shareddllproxy REUSE_FROM pch)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
target_link_libraries(shareddllproxy Mfplat mfuuid ${Detours})
set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy64")
else()
+ add_library(tinymp3 ../libs/tinymp3/shine_mp3.c)
add_subdirectory(voiceroid2)
- add_library(x86lib dreye.cpp jbj7.cpp kingsoft.cpp le.cpp neospeech.cpp ../implsapi.cpp LR.cpp)
+ add_library(x86lib dreye.cpp jbj7.cpp kingsoft.cpp le.cpp neospeech.cpp ../implsapi.cpp LR.cpp applicationloopbackaudio/runer.cpp applicationloopbackaudio/LoopbackCapture.cpp mp3.cpp)
target_precompile_headers(voiceroid2 REUSE_FROM pch)
target_precompile_headers(x86lib REUSE_FROM pch)
- target_link_libraries(shareddllproxy Mfplat mfuuid x86lib voiceroid2 ${Detours})
+ target_link_libraries(shareddllproxy Mfplat mfuuid x86lib tinymp3 voiceroid2 ${Detours})
set_target_properties(shareddllproxy PROPERTIES OUTPUT_NAME "shareddllproxy32")
endif()
diff --git a/plugins/shareddllproxy/mp3.cpp b/plugins/shareddllproxy/mp3.cpp
new file mode 100644
index 00000000..8962ecc4
--- /dev/null
+++ b/plugins/shareddllproxy/mp3.cpp
@@ -0,0 +1,248 @@
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DR_WAV_IMPLEMENTATION
+
+#include
+
+#define DR_MP3_IMPLEMENTATION
+
+#include
+
+void error(char *s);
+
+
+int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint32_t *channels, uint64_t *totalSampleCount) {
+ int16_t *buffer = drwav_open_file_and_read_pcm_frames_s16(filename, channels, sampleRate, totalSampleCount, NULL);
+ if (buffer == NULL) {
+ drmp3_config pConfig;
+ buffer = drmp3_open_file_and_read_pcm_frames_s16(filename, &pConfig, totalSampleCount, NULL);
+ if (buffer != NULL) {
+ *channels = pConfig.channels;
+ *sampleRate = pConfig.sampleRate;
+ *totalSampleCount *= *channels;
+ } else {
+ printf("read file [%s] error.\n", filename);
+ }
+ } else {
+ *totalSampleCount *= *channels;
+ }
+ return buffer;
+}
+
+
+/* Some global vars. */
+char *infname, *outfname;
+FILE *outfile;
+int quiet = 0;
+int stereo = STEREO;
+int force_mono = 0;
+
+/* Write out the MP3 file */
+int write_mp3(long bytes, void *buffer, void *config) {
+ return fwrite(buffer, sizeof(unsigned char), bytes, outfile) / sizeof(unsigned char);
+}
+
+/* Output error message and exit */
+void error(char *s) {
+ fprintf(stderr, "Error: %s\n", s);
+ exit(1);
+}
+
+static void print_usage() {
+ printf("Audio Processing\n");
+ printf("mp3 encoder && decoder\n");
+ printf("blog: http://cpuimage.cnblogs.com/\n");
+ printf("Usage: tinymp3 [options] \n\n");
+ printf("Use \"-\" for standard input or output.\n\n");
+ printf("Options:\n");
+ printf(" -h this help message\n");
+ printf(" -b set the bitrate [8-320], default 64 kbit\n");
+ printf(" -m force encoder to operate in mono\n");
+ printf(" -c set copyright flag, default off\n");
+ printf(" -j encode in joint stereo (stereo data only)\n");
+ printf(" -d encode in dual-channel (stereo data only)\n");
+ printf(" -q quiet mode\n");
+}
+
+/* Use these default settings, can be overridden */
+static void set_defaults(shine_config_t *config) {
+ shine_set_config_mpeg_defaults(&config->mpeg);
+}
+
+/* Parse command line arguments */
+static int parse_command(int argc, char **argv, shine_config_t *config) {
+ int i = 0;
+
+ if (argc < 3) return 0;
+
+ while (argv[++i][0] == '-' && argv[i][1] != '\000' && argv[i][1] != ' ')
+ switch (argv[i][1]) {
+ case 'b':
+ config->mpeg.bitr = atoi(argv[++i]);
+ break;
+
+ case 'm':
+ force_mono = 1;
+ break;
+
+ case 'j':
+ stereo = JOINT_STEREO;
+ break;
+
+ case 'd':
+ stereo = DUAL_CHANNEL;
+ break;
+
+ case 'c':
+ config->mpeg.copyright = 1;
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'v':
+ quiet = 0;
+ break;
+
+ case 'h':
+ default :
+ return 0;
+ }
+
+ if (argc - i != 2) return 0;
+ infname = argv[i++];
+ outfname = argv[i];
+ return 1;
+}
+
+/* Print some info about what we're going to encode */
+static void check_config(shine_config_t *config) {
+ static char *version_names[4] = {"2.5", "reserved", "II", "I"};
+ static char *mode_names[4] = {"stereo", "joint-stereo", "dual-channel", "mono"};
+ static char *demp_names[4] = {"none", "50/15us", "", "CITT"};
+
+ printf("MPEG-%s layer III, %s Psychoacoustic Model: Shine\n",
+ version_names[shine_check_config(config->wave.samplerate, config->mpeg.bitr)],
+ mode_names[config->mpeg.mode]);
+ printf("Bitrate: %d kbps ", config->mpeg.bitr);
+ printf("De-emphasis: %s %s %s\n",
+ demp_names[config->mpeg.emph],
+ ((config->mpeg.original) ? "Original" : ""),
+ ((config->mpeg.copyright) ? "(C)" : ""));
+ printf("Encoding \"%s\" to \"%s\"\n", infname, outfname);
+}
+
+int mainmp3(int argc, wchar_t *wargv[]) {
+ char **argv = new char *[argc];
+ for (int i = 0; i < argc; i++)
+ {
+ int length = WideCharToMultiByte(CP_ACP, 0, wargv[i], -1, NULL, 0, NULL, NULL);
+ argv[i] = new char[length];
+ WideCharToMultiByte(CP_ACP, 0, wargv[i], -1, argv[i], length, NULL, NULL);
+ }
+ shine_config_t config;
+ shine_t s;
+ int written;
+ unsigned char *data;
+ /* Set the default MPEG encoding paramters - basically init the struct */
+ set_defaults(&config);
+
+ if (!parse_command(argc, argv, &config)) {
+ print_usage();
+ exit(1);
+ }
+
+ quiet = quiet || !strcmp(outfname, "-");
+
+ if (!quiet) {
+ printf("Audio Processing\n");
+ printf("mp3 encoder && decoder\n");
+ printf("blog:http://cpuimage.cnblogs.com/\n");
+ }
+ uint32_t sampleRate = 0;
+ uint64_t totalSampleCount = 0;
+ uint32_t channels = 0;
+ int16_t *data_in = wavRead_int16(infname, &sampleRate, &channels, &totalSampleCount);
+ if (data_in == NULL)
+ return -1;
+ double startTime = now();
+ config.wave.samplerate = sampleRate;
+ config.wave.channels = (decltype(config.wave.channels))channels;
+
+ if (force_mono)
+ config.wave.channels = (decltype(config.wave.channels))1;
+
+ /* See if samplerate and bitrate are valid */
+ if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0)
+ error("Unsupported samplerate/bitrate configuration.");
+
+ /* open the output file */
+ if (!strcmp(outfname, "-"))
+ outfile = stdout;
+ else
+ outfile = fopen(outfname, "wb");
+ if (!outfile) {
+ fprintf(stderr, "Could not create \"%s\".\n", outfname);
+ exit(1);
+ }
+
+ /* Set to stereo mode if wave data is stereo, mono otherwise. */
+ if (config.wave.channels > 1)
+ config.mpeg.mode = (decltype(config.mpeg.mode))stereo;
+ else
+ config.mpeg.mode = MONO;
+
+ /* Initiate encoder */
+ s = shine_initialise(&config);
+
+ // assert(s != NULL);
+ /* Print some info about the file about to be created (optional) */
+ if (!quiet) check_config(&config);
+
+ int samples_per_pass = shine_samples_per_pass(s) * channels;
+
+ /* All the magic happens here */
+ size_t count = totalSampleCount / samples_per_pass;
+ int16_t *buffer = data_in;
+ for (int i = 0; i < count; i++) {
+ data = shine_encode_buffer_interleaved(s, buffer, &written);
+ if (write_mp3(written, data, &config) != written) {
+ fprintf(stderr, "mp3 encoder && decoder: write error\n");
+ return 1;
+ }
+ buffer += samples_per_pass;
+ }
+ size_t last = totalSampleCount % samples_per_pass;
+ if (last != 0) {
+ int16_t *cache = (int16_t *) calloc(samples_per_pass, sizeof(int16_t));
+ if (cache != NULL) {
+ memcpy(cache, buffer, last * sizeof(int16_t));
+ data = shine_encode_buffer_interleaved(s, cache, &written);
+ free(cache);
+ if (write_mp3(written, data, &config) != written) {
+ fprintf(stderr, "mp3 encoder && decoder: write error\n");
+ return 1;
+ }
+ }
+ }
+ /* Flush and write remaining data. */
+ data = shine_flush(s, &written);
+ write_mp3(written, data, &config);
+ /* Close encoder. */
+ shine_close(s);
+ /* Close the MP3 file */
+ fclose(outfile);
+ free(data_in);
+ double time_interval = calcElapsed(startTime, now());
+ if (!quiet)
+ printf("time interval: %d ms\n ", (int) (time_interval * 1000));
+
+ return 0;
+}
diff --git a/plugins/shareddllproxy/shareddllproxy.cpp b/plugins/shareddllproxy/shareddllproxy.cpp
index 65bbadb1..72052060 100644
--- a/plugins/shareddllproxy/shareddllproxy.cpp
+++ b/plugins/shareddllproxy/shareddllproxy.cpp
@@ -1,11 +1,12 @@
#pragma comment(linker, "/subsystem:windows /entry:wmainCRTStartup")
-int recordaudio(int argc, wchar_t *argv[]);
int dllinjectwmain(int argc, wchar_t *argv[]);
int ntleaswmain(int argc, wchar_t *wargv[]);
int updatewmain(int argc, wchar_t *wargv[]);
bool checkisapatch();
#ifndef _WIN64
+int recordaudio(int argc, wchar_t *argv[]);
+int mainmp3(int argc, wchar_t *argv[]);
int LRwmain(int argc, wchar_t *argv[]);
int jbjwmain(int argc, wchar_t *argv[]);
int dreyewmain(int argc, wchar_t *argv[]);
@@ -65,9 +66,11 @@ int wmain(int argc, wchar_t *argv[])
return listprocessmodule(argc - 1, argv + 1);
if (argv0 == L"update")
return updatewmain(argc - 1, argv + 1);
- if (argv0 == L"recordaudio")
- return recordaudio(argc - 1, argv + 1);
#ifndef _WIN64
+ else if (argv0 == L"recordaudio")
+ return recordaudio(argc - 1, argv + 1);
+ else if (argv0 == L"mainmp3")
+ return mainmp3(argc - 1, argv + 1);
else if (argv0 == L"LR")
return LRwmain(argc - 1, argv + 1);
else if (argv0 == L"le")
diff --git a/plugins/winsharedutils/CMakeLists.txt b/plugins/winsharedutils/CMakeLists.txt
index 53941200..e158075a 100644
--- a/plugins/winsharedutils/CMakeLists.txt
+++ b/plugins/winsharedutils/CMakeLists.txt
@@ -11,7 +11,7 @@ generate_product_version(
VERSION_PATCH ${VERSION_PATCH}
)
-add_library(winsharedutils MODULE ../implsapi.cpp hwnd.cpp darklistener.cpp theme.cpp version.cpp otsu.cpp cinterface.cpp clipboard.cpp lnk.cpp dllmain.cpp levenshtein.cpp muteprocess.cpp sapi_dll.cpp simplemecab.cpp SimpleBrowser.cpp MWebBrowser.cpp icon.cpp maglistener.cpp ${versioninfo})
+add_library(winsharedutils MODULE audio.cpp ../implsapi.cpp hwnd.cpp darklistener.cpp theme.cpp version.cpp otsu.cpp cinterface.cpp clipboard.cpp lnk.cpp dllmain.cpp levenshtein.cpp muteprocess.cpp sapi_dll.cpp simplemecab.cpp SimpleBrowser.cpp MWebBrowser.cpp icon.cpp maglistener.cpp ${versioninfo})
target_precompile_headers(winsharedutils REUSE_FROM pch)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
set_target_properties(winsharedutils PROPERTIES OUTPUT_NAME "winsharedutils64")
diff --git a/plugins/winsharedutils/audio.cpp b/plugins/winsharedutils/audio.cpp
new file mode 100644
index 00000000..28808c80
--- /dev/null
+++ b/plugins/winsharedutils/audio.cpp
@@ -0,0 +1,71 @@
+
+#define MINIAUDIO_IMPLEMENTATION
+#include
+
+void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
+{
+ ma_decoder *pDecoder = (ma_decoder *)pDevice->pUserData;
+ if (pDecoder == NULL)
+ {
+ return;
+ }
+
+ ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, NULL);
+
+ (void)pInput;
+}
+extern "C" __declspec(dllexport) void PlayAudioInMem_Stop(ma_decoder *decoder, ma_device *device)
+{
+ ma_device_stop(device);
+ ma_device_uninit(device);
+ ma_decoder_uninit(decoder);
+ delete decoder;
+ delete device;
+}
+
+extern "C" __declspec(dllexport) int PlayAudioInMem(void *ptr, size_t len, float volume, ma_decoder **decoderet, ma_device **deviceret, float *duration)
+{
+ ma_result result;
+ ma_decoder *decoder = new ma_decoder;
+ ma_device_config deviceConfig;
+ ma_device *device = new ma_device;
+ ZeroMemory(device, sizeof(ma_device));
+ ZeroMemory(decoder, sizeof(ma_decoder));
+ result = ma_decoder_init_memory(ptr, len, NULL, decoder);
+ if (result != MA_SUCCESS)
+ {
+ delete decoder;
+ delete device;
+ return -2;
+ }
+ deviceConfig = ma_device_config_init(ma_device_type_playback);
+ deviceConfig.playback.format = decoder->outputFormat;
+ deviceConfig.playback.channels = decoder->outputChannels;
+ deviceConfig.sampleRate = decoder->outputSampleRate;
+ deviceConfig.dataCallback = data_callback;
+ deviceConfig.pUserData = decoder;
+
+ if (ma_device_init(NULL, &deviceConfig, device) != MA_SUCCESS)
+ {
+ ma_decoder_uninit(decoder);
+ delete decoder;
+ delete device;
+ return -3;
+ }
+ ma_device_set_master_volume(device, volume);
+ if (ma_device_start(device) != MA_SUCCESS)
+ {
+ ma_device_uninit(device);
+ ma_decoder_uninit(decoder);
+ delete decoder;
+ delete device;
+ return -4;
+ }
+
+ *decoderet = decoder;
+ *deviceret = device;
+ ma_uint64 frames;
+ ma_decoder_get_length_in_pcm_frames(decoder, &frames);
+ *duration = 1.0f * frames / (decoder->outputSampleRate);
+ return 0;
+}