EqualizerManager.ets 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /**
  2. * 均衡器管理器
  3. * 管理均衡器预设、状态和 FFmpeg 过滤器生成
  4. */
  5. import { PreferencesUtil } from '@pura/harmony-utils';
  6. import { IjkMediaPlayer } from '@ohos/ijkplayer';
  7. import Logger from './Logger';
  8. // 频段定义
  9. export interface EqualizerBand {
  10. frequency: number; // 中心频率 (Hz)
  11. label: string; // 显示标签 (如 "32Hz", "1kHz")
  12. gain: number; // 增益值 (-12 到 +12 dB)
  13. }
  14. // 预设定义
  15. export interface EqualizerPreset {
  16. id: string; // 预设唯一标识
  17. name: string; // 预设名称
  18. gains: number[]; // 10 个频段的增益值
  19. isCustom: boolean; // 是否为自定义预设
  20. }
  21. export class EqualizerManager {
  22. private static instance: EqualizerManager | null = null;
  23. private static readonly TAG: string = 'heanup EqualizerManager';
  24. // 持久化键名
  25. private static readonly PREF_ENABLED: string = 'equalizer_enabled';
  26. private static readonly PREF_PRESET_ID: string = 'equalizer_preset_id';
  27. private static readonly PREF_CUSTOM_GAINS: string = 'equalizer_custom_gains';
  28. private static readonly PREF_CUSTOM_PRESETS: string = 'equalizer_custom_presets';
  29. // 10 频段定义
  30. public static readonly BANDS: EqualizerBand[] = [
  31. { frequency: 32, label: '32Hz', gain: 0 },
  32. { frequency: 64, label: '64Hz', gain: 0 },
  33. { frequency: 125, label: '125Hz', gain: 0 },
  34. { frequency: 250, label: '250Hz', gain: 0 },
  35. { frequency: 500, label: '500Hz', gain: 0 },
  36. { frequency: 1000, label: '1kHz', gain: 0 },
  37. { frequency: 2000, label: '2kHz', gain: 0 },
  38. { frequency: 4000, label: '4kHz', gain: 0 },
  39. { frequency: 8000, label: '8kHz', gain: 0 },
  40. { frequency: 16000, label: '16kHz', gain: 0 }
  41. ];
  42. // 内置预设 - 增益值增大以获得更明显的效果
  43. public static readonly BUILT_IN_PRESETS: EqualizerPreset[] = [
  44. { id: 'normal', name: '正常', gains: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], isCustom: false },
  45. { id: 'pop', name: '流行', gains: [-2, 3, 6, 6, 3, 0, -2, -2, -2, -2], isCustom: false },
  46. { id: 'rock', name: '摇滚', gains: [6, 5, 2, 0, -2, 0, 3, 5, 6, 6], isCustom: false },
  47. { id: 'jazz', name: '爵士', gains: [5, 3, 2, 3, -3, -3, 0, 2, 3, 5], isCustom: false },
  48. { id: 'classical', name: '古典', gains: [6, 5, 3, 2, -2, -2, 0, 3, 5, 6], isCustom: false },
  49. { id: 'bass_boost', name: '低音增强', gains: [10, 8, 6, 3, 0, 0, 0, 0, 0, 0], isCustom: false },
  50. { id: 'treble_boost', name: '高音增强', gains: [0, 0, 0, 0, 0, 2, 4, 6, 8, 10], isCustom: false },
  51. { id: 'vocal', name: '人声增强', gains: [-4, -2, 0, 4, 6, 6, 4, 0, -2, -4], isCustom: false },
  52. { id: 'dance', name: '舞曲', gains: [8, 6, 3, 0, 0, -3, -2, 3, 5, 6], isCustom: false },
  53. { id: 'acoustic', name: '原声', gains: [5, 4, 2, 2, 3, 3, 3, 5, 4, 2], isCustom: false }
  54. ];
  55. // 当前状态
  56. private _enabled: boolean = false;
  57. private _currentPresetId: string = 'normal';
  58. private _customGains: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  59. private _customPresets: EqualizerPreset[] = [];
  60. private constructor() {
  61. this.loadState();
  62. }
  63. public static getInstance(): EqualizerManager {
  64. if (EqualizerManager.instance === null) {
  65. EqualizerManager.instance = new EqualizerManager();
  66. }
  67. return EqualizerManager.instance;
  68. }
  69. // 类型守卫:验证是否为有效的增益数组
  70. private isValidGainsArray(value: object): boolean {
  71. if (!Array.isArray(value)) {
  72. return false;
  73. }
  74. if (value.length !== 10) {
  75. return false;
  76. }
  77. for (let i = 0; i < value.length; i++) {
  78. if (typeof value[i] !== 'number') {
  79. return false;
  80. }
  81. }
  82. return true;
  83. }
  84. // 类型守卫:验证是否为有效的预设数组
  85. private isValidPresetArray(value: object): boolean {
  86. if (!Array.isArray(value)) {
  87. return false;
  88. }
  89. for (let i = 0; i < value.length; i++) {
  90. const item = value[i] as Record<string, object>;
  91. if (typeof item !== 'object' || item === null) {
  92. return false;
  93. }
  94. if (typeof item['id'] !== 'string' ||
  95. typeof item['name'] !== 'string' ||
  96. !Array.isArray(item['gains']) ||
  97. typeof item['isCustom'] !== 'boolean') {
  98. return false;
  99. }
  100. }
  101. return true;
  102. }
  103. // 加载持久化状态
  104. private loadState(): void {
  105. this._enabled = PreferencesUtil.getBooleanSync(EqualizerManager.PREF_ENABLED, false);
  106. this._currentPresetId = PreferencesUtil.getStringSync(EqualizerManager.PREF_PRESET_ID, 'normal');
  107. const gainsStr = PreferencesUtil.getStringSync(EqualizerManager.PREF_CUSTOM_GAINS, '');
  108. if (gainsStr.length > 0) {
  109. try {
  110. const parsed: object = JSON.parse(gainsStr) as object;
  111. if (this.isValidGainsArray(parsed)) {
  112. this._customGains = parsed as number[];
  113. }
  114. } catch (e) {
  115. Logger.error(EqualizerManager.TAG, `解析自定义增益失败: ${(e as Error).message}`);
  116. }
  117. }
  118. const presetsStr = PreferencesUtil.getStringSync(EqualizerManager.PREF_CUSTOM_PRESETS, '');
  119. if (presetsStr.length > 0) {
  120. try {
  121. const parsed: object = JSON.parse(presetsStr) as object;
  122. if (this.isValidPresetArray(parsed)) {
  123. this._customPresets = parsed as EqualizerPreset[];
  124. }
  125. } catch (e) {
  126. Logger.error(EqualizerManager.TAG, `解析自定义预设失败: ${(e as Error).message}`);
  127. }
  128. }
  129. Logger.info(EqualizerManager.TAG, `状态已加载: enabled=${this._enabled}, preset=${this._currentPresetId}`);
  130. }
  131. // 保存状态
  132. private saveState(): void {
  133. PreferencesUtil.putSync(EqualizerManager.PREF_ENABLED, this._enabled);
  134. PreferencesUtil.putSync(EqualizerManager.PREF_PRESET_ID, this._currentPresetId);
  135. PreferencesUtil.putSync(EqualizerManager.PREF_CUSTOM_GAINS, JSON.stringify(this._customGains));
  136. PreferencesUtil.putSync(EqualizerManager.PREF_CUSTOM_PRESETS, JSON.stringify(this._customPresets));
  137. }
  138. // Getter/Setter
  139. get enabled(): boolean {
  140. return this._enabled;
  141. }
  142. set enabled(value: boolean) {
  143. this._enabled = value;
  144. this.saveState();
  145. }
  146. get currentPresetId(): string {
  147. return this._currentPresetId;
  148. }
  149. get customGains(): number[] {
  150. return this._customGains.slice();
  151. }
  152. // 获取所有预设(内置 + 自定义)
  153. getAllPresets(): EqualizerPreset[] {
  154. const result: EqualizerPreset[] = [];
  155. for (let i = 0; i < EqualizerManager.BUILT_IN_PRESETS.length; i++) {
  156. result.push(EqualizerManager.BUILT_IN_PRESETS[i]);
  157. }
  158. for (let i = 0; i < this._customPresets.length; i++) {
  159. result.push(this._customPresets[i]);
  160. }
  161. return result;
  162. }
  163. // 获取当前预设
  164. getCurrentPreset(): EqualizerPreset | null {
  165. const allPresets = this.getAllPresets();
  166. for (let i = 0; i < allPresets.length; i++) {
  167. if (allPresets[i].id === this._currentPresetId) {
  168. return allPresets[i];
  169. }
  170. }
  171. return null;
  172. }
  173. // 获取当前增益值
  174. getCurrentGains(): number[] {
  175. if (this._currentPresetId === 'custom') {
  176. return this._customGains.slice();
  177. }
  178. const preset = this.getCurrentPreset();
  179. if (preset !== null) {
  180. return preset.gains.slice();
  181. }
  182. return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  183. }
  184. // 设置预设
  185. setPreset(presetId: string): void {
  186. this._currentPresetId = presetId;
  187. this.saveState();
  188. Logger.info(EqualizerManager.TAG, `预设已更改: ${presetId}`);
  189. }
  190. // 设置自定义增益
  191. setCustomGain(bandIndex: number, gain: number): void {
  192. if (bandIndex < 0 || bandIndex >= 10) {
  193. return;
  194. }
  195. // 限制增益范围 -12 到 +12
  196. let clampedGain = gain;
  197. if (clampedGain < -12) {
  198. clampedGain = -12;
  199. }
  200. if (clampedGain > 12) {
  201. clampedGain = 12;
  202. }
  203. this._customGains[bandIndex] = clampedGain;
  204. this._currentPresetId = 'custom';
  205. this.saveState();
  206. }
  207. // 设置所有自定义增益
  208. setAllCustomGains(gains: number[]): void {
  209. if (gains.length !== 10) {
  210. return;
  211. }
  212. for (let i = 0; i < 10; i++) {
  213. let g = gains[i];
  214. if (g < -12) {
  215. g = -12;
  216. }
  217. if (g > 12) {
  218. g = 12;
  219. }
  220. this._customGains[i] = g;
  221. }
  222. this._currentPresetId = 'custom';
  223. this.saveState();
  224. }
  225. // 重置为平坦
  226. resetToFlat(): void {
  227. this._customGains = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  228. this._currentPresetId = 'normal';
  229. this.saveState();
  230. }
  231. // 保存当前设置为新预设
  232. saveAsPreset(name: string): EqualizerPreset {
  233. const id = `custom_${Date.now()}`;
  234. const currentGains = this.getCurrentGains();
  235. const newPreset: EqualizerPreset = {
  236. id: id,
  237. name: name,
  238. gains: currentGains,
  239. isCustom: true
  240. };
  241. this._customPresets.push(newPreset);
  242. this._currentPresetId = id;
  243. this.saveState();
  244. return newPreset;
  245. }
  246. // 删除自定义预设
  247. deleteCustomPreset(presetId: string): boolean {
  248. let index = -1;
  249. for (let i = 0; i < this._customPresets.length; i++) {
  250. if (this._customPresets[i].id === presetId) {
  251. index = i;
  252. break;
  253. }
  254. }
  255. if (index >= 0) {
  256. this._customPresets.splice(index, 1);
  257. if (this._currentPresetId === presetId) {
  258. this._currentPresetId = 'normal';
  259. }
  260. this.saveState();
  261. return true;
  262. }
  263. return false;
  264. }
  265. /**
  266. * 应用均衡器到播放器(OHAudioSuite 实时生效)
  267. */
  268. applyToPlayer(player: IjkMediaPlayer): void {
  269. const gains = this.getCurrentGains();
  270. player.setEqualizerEnabled(this._enabled);
  271. player.setEqualizerGains(gains);
  272. Logger.info(EqualizerManager.TAG, `均衡器已下发: enabled=${this._enabled}, gains=${JSON.stringify(gains)}`);
  273. }
  274. /**
  275. * 获取预设的显示名称
  276. */
  277. getPresetDisplayName(presetId: string): string {
  278. if (presetId === 'custom') {
  279. return '自定义';
  280. }
  281. const preset = this.getCurrentPreset();
  282. if (preset !== null && preset.id === presetId) {
  283. return preset.name;
  284. }
  285. const allPresets = this.getAllPresets();
  286. for (let i = 0; i < allPresets.length; i++) {
  287. if (allPresets[i].id === presetId) {
  288. return allPresets[i].name;
  289. }
  290. }
  291. return '自定义';
  292. }
  293. }