在这里插入图片描述

每日一句正能量

不要总是指责自己或他人为什么做不到,而是要思考怎样才能做到。
指责(无论是自责还是责他)会消耗心理能量并固化无力感;而“怎样才能做到”激发创造性思维和行动力。

前言

摘要:2026年,音乐制作进入"智能体协同创作"时代。HarmonyOS 6(API 23)引入的鸿蒙智能体框架(HMAF)将AI能力下沉至系统层,配合悬浮导航与沉浸光感特性,为PC端专业音乐制作带来了"节拍即光效、情绪即导航"的全新交互范式。本文将实战开发一款面向HarmonyOS PC的"音浪智脑"应用,展示如何利用HMAF构建"旋律生成-和声编排-混音母带-风格迁移"四层智能体协作架构,通过悬浮导航实现创作状态实时追踪,基于沉浸光感打造"BPM即氛围"的沉浸体验,以及基于多窗口架构构建浮动音轨编辑器、实时频谱面板和风格选择器的协作创作体验。

一、前言:AI音乐制作3.0时代的智能体革命

2026年,中国独立音乐人规模突破500万,但传统DAW(数字音频工作站)面临三大痛点:

  1. 创作瓶颈:编曲新手难以驾驭复杂的和声理论与混音技巧,一首完整作品的制作周期平均需要3个月
  2. 工具割裂:旋律创作、和声编排、混音母带、风格迁移分散在不同软件,工程文件兼容性差
  3. 反馈缺失:创作者在长时间制作中难以感知作品的情绪走向与频谱缺陷,导致成品质量参差不齐

HarmonyOS 6(API 23)的HMAF框架配合**悬浮导航(Float Navigation)沉浸光感(Immersive Light Effects)**特性,为音乐制作带来了革命性解决方案:

  • 智能体协同创作:HMAF构建的"旋律智能体"可实时生成符合情绪的旋律动机,"和声智能体"自动配器,响应延迟降至1.2秒
  • BPM光效感知:根据当前工程BPM、频谱能量、情绪标签动态切换环境光色,让创作者"看见"音乐的情绪色彩
  • 悬浮创作导航:底部悬浮导航实时显示四大智能体运行状态与工程进度徽章,创作者无需切换页面即可掌握全局
  • PC多窗口协作:主音轨编辑器 + 浮动MIDI键盘窗口 + 浮动频谱面板 + 浮动风格选择器的四层架构,通过光效联动实现"一眼全局"

本文核心亮点

  • 四层智能体架构:旋律智能体(动机生成)、和声智能体(自动配器)、混音智能体(母带处理)、风格智能体(风格迁移)协同工作
  • BPM脉搏光效:根据工程BPM(慢板蓝→行板绿→快板橙→急板红)动态渲染全屏氛围光
  • 频谱能量光效:基于实时FFT频谱分析,低频触发深红光晕,高频触发冰蓝光晕
  • 悬浮创作导航:底部悬浮页签承载"音轨/和声/混音/风格"四大模块,实时显示智能体状态徽章与BPM脉冲
  • 多窗口光效同步:主窗口与三个浮动子窗口通过WindowLightSync实现跨窗口光效联动,焦点感知自动调节

二、核心特性解析与技术选型

2.1 HMAF在音乐制作场景中的价值

HMAF(Harmony Intelligent Agent Framework)提供四种编排模式,在音乐制作场景中各有妙用:

编排模式 音乐制作应用场景 技术实现
LLM模式 旋律智能体根据情绪标签生成旋律动机 基于情绪参数调用LLM生成MIDI序列
工作流模式 和声智能体按预设流程进行自动配器 旋律分析→和弦进行推荐→乐器分配→声部编排
A2A模式 四大智能体间实时协作与任务分发 旋律智能体生成动机后,和声智能体同步配器,混音智能体预置效果器参数
OpenClaw模式 创作者通过自然语言直接指挥智能体 “把这段旋律改成爵士风格,配萨克斯和钢琴”

2.2 沉浸光感在音乐制作中的创新应用

传统DAW采用固定深色UI,创作者难以感知音乐的情绪色彩。HarmonyOS 6的沉浸光感特性带来三种创新:

BPM脉搏光效:根据工程BPM动态调整背景光色与脉冲频率

  • 慢板期(<<60 BPM):深海蓝,缓慢呼吸(4秒/周期)
  • 行板期(60-90 BPM):薄荷绿,平稳律动(2秒/周期)
  • 快板期(90-120 BPM):活力橙,快速脉冲(1秒/周期)
  • 急板期(>120 BPM):炽烈红,高频闪烁(0.5秒/周期)

频谱能量光效:基于实时FFT频谱分析驱动光效

  • 低频能量(20-250Hz):深红色光晕从底部升起,模拟低频震动
  • 中频能量(250-4000Hz):暖黄色光晕从中心扩散,模拟人声与乐器
  • 高频能量(4000-20000Hz):冰蓝色光晕从顶部洒落,模拟镲片与高频

情绪标签光效:根据作品情绪标签渲染光效主题

  • 快乐(Happy):明黄色全屏光效,配合金色粒子
  • 悲伤(Sad):靛蓝色全屏光效,配合雨滴效果
  • 激昂(Energetic):炽红色全屏光效,配合火焰粒子
  • 宁静(Calm):薄荷绿全屏光效,配合水波纹

2.3 悬浮导航的创作适配

传统DAW采用顶部固定工具栏,占用宝贵竖屏空间。HarmonyOS 6的悬浮导航特性带来:

  • 底部悬浮页签:不遮挡音轨编辑器,支持透明度三档调节(55%/70%/85%)
  • 智能体状态徽章:每个页签实时显示对应智能体运行状态(空闲/思考/执行/完成/异常)
  • BPM实时徽章:导航栏中央显示当前BPM与工程时长,点击展开详细数据
  • 快捷操作入口:长按导航栏唤起快捷菜单,一键切换创作模式/紧急保存/智能体开关

三、项目实战:"音浪智脑"架构设计

3.1 应用场景与功能规划

面向HarmonyOS PC的专业音乐制作场景,核心功能包括:

功能模块 技术实现 沉浸光感/HMAF应用
主音轨编辑器 Canvas + AudioEngine BPM脉搏光效背景
悬浮创作导航 HdsTabs + systemMaterialEffect 玻璃拟态页签,智能体状态徽章
旋律智能体 HMAF Agent Framework Kit 旋律生成状态光效反馈
和声智能体 HMAF + 音乐理论引擎 和声进行光效驱动
混音智能体 HMAF + 音频处理引擎 频谱能量光效反馈
风格智能体 HMAF + 风格迁移模型 风格主题色光效
浮动MIDI键盘 子窗口 + Canvas 音符色光效同步
浮动频谱面板 子窗口 + Canvas 频段色光效同步
浮动风格选择器 子窗口 + Grid 风格主题色光效

3.2 技术架构图

┌─────────────────────────────────────────────────────────────┐
│                    HarmonyOS 6 PC 主窗口                      │
│  ┌───────────────────────────────────────────────────────┐  │
│  │              沉浸光感层 (AmbientLightLayer)              │  │
│  │         BPM脉搏光效 + 频谱能量光效 + 情绪标签光效         │  │
│  └───────────────────────────────────────────────────────┘  │
│  ┌───────────────────────────────────────────────────────┐  │
│  │           主音轨编辑器 (Canvas + AudioEngine)             │  │
│  │              多轨MIDI + 音频波形 + 自动化包络              │  │
│  └───────────────────────────────────────────────────────┘  │
│  ┌───────────────────────────────────────────────────────┐  │
│  │              悬浮创作导航 (FloatNavigation)              │  │
│  │    音轨/和声/混音/风格 页签 + 智能体状态徽章 + BPM徽章    │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│  浮动MIDI键盘  │   │  浮动频谱面板  │   │  浮动风格选择器 │
│  (音符+音高色) │   │  (频段+能量色) │   │  (风格+主题色) │
└───────────────┘   └───────────────┘   └───────────────┘
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│   旋律智能体    │   │   和声智能体    │   │   混音智能体    │
│  (MIDI动机生成) │   │ (自动配器编排)  │   │ (母带效果处理)  │
└───────────────┘   └───────────────┘   └───────────────┘
                              │
                              ▼
                    ┌───────────────┐
                    │    风格智能体   │
                    │ (风格迁移转换) │
                    └───────────────┘

四、环境配置与模块依赖

4.1 模块依赖配置

entry/oh-package.json5中添加以下依赖:

{
  "dependencies": {
    "@kit.ArkUI": "1.0.0",
    "@kit.WindowManagerKit": "1.0.0",
    "@kit.SensorServiceKit": "1.0.0",
    "@kit.UIDesignKit": "1.0.0",
    "@kit.AgentFrameworkKit": "1.0.0",
    "@kit.IntentsKit": "1.0.0",
    "@kit.AudioKit": "1.0.0",
    "@kit.MediaKit": "1.0.0",
    "@kit.NNKit": "1.0.0"
  }
}

4.2 权限声明(module.json5)

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "$string:mic_permission_reason"
      },
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_permission_reason"
      },
      {
        "name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
        "reason": "$string:float_window_permission_reason"
      },
      {
        "name": "ohos.permission.READ_USER_STORAGE",
        "reason": "$string:storage_permission_reason"
      },
      {
        "name": "ohos.permission.WRITE_USER_STORAGE",
        "reason": "$string:storage_permission_reason"
      }
    ]
  }
}

五、核心组件实战

5.1 窗口沉浸配置(EntryAbility.ets)

// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.WindowManagerKit';

export default class EntryAbility extends UIAbility {
  async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
    const mainWindow = await windowStage.createSubWindow('music_main');
    
    // 启用全屏沉浸模式,隐藏系统标题栏
    await mainWindow.setWindowLayoutFullScreen(true);
    
    // 设置窗口背景为透明,允许沉浸光效层透传
    await mainWindow.setWindowBackgroundColor('#00000000');
    
    // 加载主页面
    windowStage.loadContent('pages/MusicStudioPage', (err) => {
      if (err) {
        console.error('Failed to load MusicStudioPage:', err.message);
      }
    });

    // 初始化窗口焦点监听,用于光效联动
    mainWindow.on('windowFocusChange', (isFocused: boolean) => {
      AppStorage.setOrCreate('window_focused', isFocused);
    });
  }

  onWindowStageDestroy(): void {
    // 清理音频资源
    AudioEngine.getInstance().release();
  }
}

5.2 BPM脉搏光效系统(BPMLightEffect.ets)

// entry/src/main/ets/components/BPMLightEffect.ets
import { HdsNavigation, SystemMaterialEffect } from '@kit.UIDesignKit';

// BPM阶段枚举
export enum BPMPhase {
  ADAGIO = 'adagio',      // 慢板 <60 BPM
  ANDANTE = 'andante',      // 行板 60-90 BPM
  ALLEGRO = 'allegro',      // 快板 90-120 BPM
  PRESTO = 'presto'         // 急板 >120 BPM
}

// 情绪标签枚举
export enum MoodTag {
  HAPPY = 'happy',          // 快乐
  SAD = 'sad',              // 悲伤
  ENERGETIC = 'energetic',  // 激昂
  CALM = 'calm'             // 宁静
}

// 智能体状态枚举
export enum AgentState {
  IDLE = 'idle',
  THINKING = 'thinking',
  EXECUTING = 'executing',
  COMPLETED = 'completed',
  ERROR = 'error'
}

@Component
export struct BPMLightEffect {
  @Prop currentBPM: number = 120;
  @Prop currentMood: MoodTag = MoodTag.CALM;
  @Prop spectrumEnergy: number[] = [0, 0, 0];  // 低中高频能量
  @State lightIntensity: number = 0.6;
  @State pulsePhase: number = 0;
  @State beatPhase: number = 0;

  // BPM阶段主题色映射
  private bpmColors: Map<BPMPhase, string> = new Map([
    [BPMPhase.ADAGIO, '#1E3A8A'],    // 深海蓝
    [BPMPhase.ANDANTE, '#10B981'],    // 薄荷绿
    [BPMPhase.ALLEGRO, '#F59E0B'],     // 活力橙
    [BPMPhase.PRESTO, '#EF4444']       // 炽烈红
  ]);

  // 情绪标签色映射
  private moodColors: Map<MoodTag, string> = new Map([
    [MoodTag.HAPPY, '#FCD34D'],       // 明黄色
    [MoodTag.SAD, '#6366F1'],          // 靛蓝色
    [MoodTag.ENERGETIC, '#EF4444'],    // 炽红色
    [MoodTag.CALM, '#10B981']          // 薄荷绿
  ]);

  // 脉冲周期映射(毫秒,基于BPM计算)
  private getPulseDuration(): number {
    return (60 / this.currentBPM) * 1000;
  }

  private getCurrentPhase(): BPMPhase {
    if (this.currentBPM < 60) return BPMPhase.ADAGIO;
    if (this.currentBPM < 90) return BPMPhase.ANDANTE;
    if (this.currentBPM < 120) return BPMPhase.ALLEGRO;
    return BPMPhase.PRESTO;
  }

  private getThemeColor(): string {
    // 情绪标签优先于BPM
    return this.moodColors.get(this.currentMood) || this.bpmColors.get(this.getCurrentPhase()) || '#1E3A8A';
  }

  // 频谱能量影响光效强度
  private getIntensityBySpectrum(): number {
    const avgEnergy = this.spectrumEnergy.reduce((a, b) => a + b, 0) / 3;
    return Math.min(1.0, 0.3 + avgEnergy * 0.7);
  }

  aboutToAppear(): void {
    // 启动光效脉冲动画
    this.startPulseAnimation();
    // 启动节拍动画
    this.startBeatAnimation();
  }

  private startPulseAnimation(): void {
    setInterval(() => {
      this.pulsePhase = this.pulsePhase === 0 ? 1 : 0;
    }, this.getPulseDuration() / 2);
  }

  private startBeatAnimation(): void {
    setInterval(() => {
      this.beatPhase = this.beatPhase === 0 ? 1 : 0;
    }, this.getPulseDuration());
  }

  build() {
    Stack() {
      // 底层:BPM脉搏光效(大面积模糊光晕)
      Column()
        .width(800)
        .height(800)
        .backgroundColor(this.getThemeColor())
        .blur(200)
        .opacity(this.getIntensityBySpectrum() * 0.25)
        .position({ x: '50%', y: '30%' })
        .anchor('50%')
        .scale({
          x: this.pulsePhase === 0 ? 1.0 : 1.3,
          y: this.pulsePhase === 0 ? 1.0 : 1.3
        })
        .animation({
          duration: this.getPulseDuration(),
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        })

      // 中层:低频能量光效(底部深红)
      Column()
        .width('100%')
        .height(200)
        .backgroundColor('#EF4444')
        .opacity(this.spectrumEnergy[0] * 0.3)
        .blur(80)
        .position({ x: 0, y: '80%' })
        .linearGradient({
          direction: GradientDirection.Top,
          colors: [
            ['#EF4444', 0.0],
            ['transparent', 1.0]
          ]
        })
        .animation({
          duration: 100,
          curve: Curve.Linear
        })

      // 中层:中频能量光效(中心暖黄)
      Column()
        .width(400)
        .height(400)
        .backgroundColor('#F59E0B')
        .opacity(this.spectrumEnergy[1] * 0.2)
        .blur(120)
        .position({ x: '50%', y: '50%' })
        .anchor('50%')
        .animation({
          duration: 100,
          curve: Curve.Linear
        })

      // 中层:高频能量光效(顶部冰蓝)
      Column()
        .width('100%')
        .height(150)
        .backgroundColor('#60A5FA')
        .opacity(this.spectrumEnergy[2] * 0.25)
        .blur(60)
        .position({ x: 0, y: 0 })
        .linearGradient({
          direction: GradientDirection.Bottom,
          colors: [
            ['#60A5FA', 0.0],
            ['transparent', 1.0]
          ]
        })
        .animation({
          duration: 100,
          curve: Curve.Linear
        })

      // 顶层:节拍粒子效果
      this.buildBeatParticles()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#050508')
  }

  @Builder
  buildBeatParticles(): void {
    ForEach([0, 1, 2, 3], (index: number) => {
      Column()
        .width(6)
        .height(6)
        .backgroundColor(this.getThemeColor())
        .borderRadius(3)
        .opacity(this.beatPhase === 0 ? 0.8 : 0.2)
        .position({
          x: `${15 + index * 22}%`,
          y: `${20 + index * 15}%`
        })
        .animation({
          duration: this.getPulseDuration() / 4,
          curve: Curve.EaseOut,
          iterations: 1
        })
        .scale({
          x: this.beatPhase === 0 ? 2.0 : 0.5,
          y: this.beatPhase === 0 ? 2.0 : 0.5
        })
    })
  }
}

5.3 HMAF四层智能体调度器(MusicAgentScheduler.ets)

// entry/src/main/ets/agents/MusicAgentScheduler.ets
import { hmaf } from '@kit.AgentFrameworkKit';
import { intents } from '@kit.IntentsKit';

// 智能体类型枚举
export enum AgentType {
  MELODY = 'melody',          // 旋律智能体
  HARMONY = 'harmony',        // 和声智能体
  MIXING = 'mixing',          // 混音智能体
  STYLE = 'style'             // 风格智能体
}

// 智能体人格色彩映射
export enum AgentPersonality {
  MELODY = '#FCD34D',       // 旋律金
  HARMONY = '#8B5CF6',       // 和声紫
  MIXING = '#06B6D4',        // 混音青
  STYLE = '#F97316'          // 风格橙
}

export class MusicAgentScheduler {
  private static instance: MusicAgentScheduler;
  private hmafSession: hmaf.AgentSession | null = null;
  private intentEngine: intents.IntentEngine | null = null;
  
  // 智能体状态管理
  private agentStates: Map<string, AgentState> = new Map([
    ['melody-1', AgentState.IDLE],
    ['harmony-1', AgentState.IDLE],
    ['mixing-1', AgentState.IDLE],
    ['style-1', AgentState.IDLE]
  ]);

  private constructor() {}

  static getInstance(): MusicAgentScheduler {
    if (!MusicAgentScheduler.instance) {
      MusicAgentScheduler.instance = new MusicAgentScheduler();
    }
    return MusicAgentScheduler.instance;
  }

  async initialize(): Promise<void> {
    // 初始化HMAF多智能体会话
    this.hmafSession = await hmaf.createAgentSession({
      mode: hmaf.AgentMode.MULTI_AGENT,
      enableDistributed: true,
      maxConcurrentAgents: 4
    });

    // 初始化意图引擎
    this.intentEngine = await intents.createIntentEngine({
      supportedDomains: ['music_composition', 'harmony_arrangement', 'audio_mixing', 'style_transfer']
    });

    // 注册四大智能体
    await this.registerAgents();

    // 启动状态监听
    this.startStateMonitoring();
  }

  private async registerAgents(): Promise<void> {
    // 1. 旋律智能体:基于情绪标签生成MIDI动机
    await this.hmafSession?.registerAgent({
      agentId: 'melody-1',
      agentType: AgentType.MELODY,
      capabilities: ['melody_generation', 'motif_extraction', 'phrase_extension', 'variation_creation'],
      modelConfig: {
        modelType: 'llm',
        temperature: 0.8,
        maxTokens: 1024
      }
    });

    // 2. 和声智能体:自动配器与和弦进行
    await this.hmafSession?.registerAgent({
      agentId: 'harmony-1',
      agentType: AgentType.HARMONY,
      capabilities: ['chord_progression', 'instrumentation', 'voicing_arrangement', 'counterpoint'],
      modelConfig: {
        modelType: 'llm',
        temperature: 0.5,
        maxTokens: 1024
      }
    });

    // 3. 混音智能体:母带处理与效果器
    await this.hmafSession?.registerAgent({
      agentId: 'mixing-1',
      agentType: AgentType.MIXING,
      capabilities: ['eq_adjustment', 'compression', 'reverb_design', 'mastering', 'loudness_optimization'],
      modelConfig: {
        modelType: 'llm',
        temperature: 0.3,
        maxTokens: 512
      }
    });

    // 4. 风格智能体:风格迁移与转换
    await this.hmafSession?.registerAgent({
      agentId: 'style-1',
      agentType: AgentType.STYLE,
      capabilities: ['style_analysis', 'genre_transfer', 'instrument_swap', 'rhythm_pattern_adaptation'],
      modelConfig: {
        modelType: 'llm',
        temperature: 0.6,
        maxTokens: 512
      }
    });
  }

  // 生成旋律动机
  async generateMelody(mood: string, key: string, bpm: number): Promise<{ midi: number[]; rhythm: number[]; mood: string }> {
    this.updateAgentState('melody-1', AgentState.THINKING);
    
    const result = await this.hmafSession?.sendTask({
      targetAgent: 'melody-1',
      taskType: 'generate_melody',
      payload: {
        mood: mood,          // 'happy', 'sad', 'energetic', 'calm'
        key: key,            // 'C_major', 'A_minor', etc.
        bpm: bpm,
        length: 8,           // 8小节
        complexity: 'medium'
      }
    });

    this.updateAgentState('melody-1', AgentState.COMPLETED);
    return {
      midi: result?.midiNotes || [],
      rhythm: result?.rhythmPattern || [],
      mood: result?.detectedMood || mood
    };
  }

  // 自动配器
  async arrangeHarmony(melodyMidi: number[], style: string): Promise<{ chords: string[]; instruments: string[]; tracks: Track[] }> {
    this.updateAgentState('harmony-1', AgentState.EXECUTING);
    
    const result = await this.hmafSession?.sendTask({
      targetAgent: 'harmony-1',
      taskType: 'arrange_harmony',
      payload: {
        melody: melodyMidi,
        style: style,        // 'pop', 'jazz', 'classical', 'electronic'
        maxVoices: 4,
        includeBass: true,
        includeDrums: true
      }
    });

    this.updateAgentState('harmony-1', AgentState.COMPLETED);
    
    return {
      chords: result?.chordProgression || [],
      instruments: result?.instruments || [],
      tracks: result?.tracks || []
    };
  }

  // 混音母带
  async mixMaster(tracks: Track[], targetLoudness: number): Promise<{ eq: EQSettings; compression: CompressionSettings; reverb: ReverbSettings; loudness: number }> {
    this.updateAgentState('mixing-1', AgentState.EXECUTING);
    
    const result = await this.hmafSession?.sendTask({
      targetAgent: 'mixing-1',
      taskType: 'mix_master',
      payload: {
        tracks: tracks,
        targetLoudness: targetLoudness,  // LUFS
        genre: 'pop',
        referenceTrack: null
      }
    });

    this.updateAgentState('mixing-1', AgentState.COMPLETED);
    
    return {
      eq: result?.eqSettings || {},
      compression: result?.compressionSettings || {},
      reverb: result?.reverbSettings || {},
      loudness: result?.finalLoudness || 0
    };
  }

  // 风格迁移
  async transferStyle(originalMidi: number[], targetStyle: string): Promise<{ midi: number[]; styleFeatures: string[]; confidence: number }> {
    this.updateAgentState('style-1', AgentState.THINKING);
    
    const result = await this.hmafSession?.sendTask({
      targetAgent: 'style-1',
      taskType: 'transfer_style',
      payload: {
        originalMidi: originalMidi,
        targetStyle: targetStyle,  // 'jazz', 'rock', 'classical', 'electronic'
        preserveMelody: true,
        intensity: 0.7
      }
    });

    this.updateAgentState('style-1', AgentState.COMPLETED);
    
    return {
      midi: result?.transformedMidi || [],
      styleFeatures: result?.styleFeatures || [],
      confidence: result?.confidence || 0
    };
  }

  private updateAgentState(agentId: string, state: AgentState): void {
    this.agentStates.set(agentId, state);
    AppStorage.setOrCreate('agent_state_update', { agentId, state });
  }

  getAgentState(agentId: string): AgentState {
    return this.agentStates.get(agentId) || AgentState.IDLE;
  }

  private startStateMonitoring(): void {
    // 监听智能体状态变化,同步到UI
    this.hmafSession?.on('agentStateChange', (event: { agentId: string; state: string }) => {
      this.updateAgentState(event.agentId, event.state as AgentState);
    });
  }
}

// 音轨类型
export interface Track {
  id: string;
  name: string;
  type: 'melody' | 'harmony' | 'bass' | 'drums' | 'fx';
  midiData: number[];
  instrument: string;
  volume: number;
  pan: number;
  muted: boolean;
  solo: boolean;
}

// EQ设置
export interface EQSettings {
  lowGain: number;
  midGain: number;
  highGain: number;
  lowFreq: number;
  midFreq: number;
  highFreq: number;
}

// 压缩设置
export interface CompressionSettings {
  threshold: number;
  ratio: number;
  attack: number;
  release: number;
  makeupGain: number;
}

// 混响设置
export interface ReverbSettings {
  roomSize: number;
  damping: number;
  wetLevel: number;
  dryLevel: number;
}

5.4 悬浮创作导航(MusicFloatNavigation.ets)

// entry/src/main/ets/components/MusicFloatNavigation.ets
import { window } from '@kit.ArkUI';
import { AgentState, AgentType, AgentPersonality } from '../agents/MusicAgentScheduler';
import { BPMPhase } from './BPMLightEffect';

interface NavItem {
  id: string;
  icon: Resource;
  label: string;
  page: string;
  agentType?: AgentType;
}

@Component
export struct MusicFloatNavigation {
  @State currentIndex: number = 0;
  @State navTransparency: number = 0.70;
  @State isExpanded: boolean = false;
  @State bottomAvoidHeight: number = 0;
  @State currentBPM: number = 120;
  @State projectDuration: number = 0;  // 工程时长(秒)
  @State currentPhase: BPMPhase = BPMPhase.ALLEGRO;
  @State agentStates: Map<string, AgentState> = new Map([
    ['melody-1', AgentState.IDLE],
    ['harmony-1', AgentState.IDLE],
    ['mixing-1', AgentState.IDLE],
    ['style-1', AgentState.IDLE]
  ]);

  private navItems: NavItem[] = [
    { id: 'tracks', icon: $r('app.media.ic_tracks'), label: '音轨', page: 'TracksPage' },
    { id: 'harmony', icon: $r('app.media.ic_piano'), label: '和声', page: 'HarmonyPage', agentType: AgentType.HARMONY },
    { id: 'mixing', icon: $r('app.media.ic_sliders'), label: '混音', page: 'MixingPage', agentType: AgentType.MIXING },
    { id: 'style', icon: $r('app.media.ic_style'), label: '风格', page: 'StylePage', agentType: AgentType.STYLE },
    { id: 'settings', icon: $r('app.media.ic_settings'), label: '设置', page: 'SettingsPage' }
  ];

  aboutToAppear(): void {
    this.getBottomAvoidArea();

    // 监听智能体状态更新
    AppStorage.watch('agent_state_update', (update: { agentId: string; state: string }) => {
      this.agentStates.set(update.agentId, update.state as AgentState);
    });

    // 监听工程数据
    AppStorage.watch('project_metrics', (metrics: { bpm: number; duration: number }) => {
      this.currentBPM = metrics.bpm;
      this.projectDuration = metrics.duration;
      this.updateBPMPhase();
    });
  }

  private updateBPMPhase(): void {
    if (this.currentBPM < 60) this.currentPhase = BPMPhase.ADAGIO;
    else if (this.currentBPM < 90) this.currentPhase = BPMPhase.ANDANTE;
    else if (this.currentBPM < 120) this.currentPhase = BPMPhase.ALLEGRO;
    else this.currentPhase = BPMPhase.PRESTO;
  }

  private async getBottomAvoidArea(): Promise<void> {
    try {
      const mainWindow = await window.getLastWindow();
      const avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
      this.bottomAvoidHeight = avoidArea.bottomRect.height;
    } catch (error) {
      console.error('Failed to get avoid area:', error);
    }
  }

  private getAgentStateForNavItem(item: NavItem): AgentState {
    if (!item.agentType) return AgentState.IDLE;
    
    const agentIdMap: Record<string, string> = {
      [AgentType.MELODY]: 'melody-1',
      [AgentType.HARMONY]: 'harmony-1',
      [AgentType.MIXING]: 'mixing-1',
      [AgentType.STYLE]: 'style-1'
    };
    
    return this.agentStates.get(agentIdMap[item.agentType]) || AgentState.IDLE;
  }

  private getPhaseColor(): string {
    const colors: Record<BPMPhase, string> = {
      [BPMPhase.ADAGIO]: '#1E3A8A',
      [BPMPhase.ANDANTE]: '#10B981',
      [BPMPhase.ALLEGRO]: '#F59E0B',
      [BPMPhase.PRESTO]: '#EF4444'
    };
    return colors[this.currentPhase];
  }

  private getStateBadgeColor(state: AgentState): string {
    const colors: Record<<AgentState, string> = {
      [AgentState.IDLE]: '#888888',
      [AgentState.THINKING]: '#8B5CF6',
      [AgentState.EXECUTING]: '#F97316',
      [AgentState.COMPLETED]: '#10B981',
      [AgentState.ERROR]: '#EF4444'
    };
    return colors[state] || '#888888';
  }

  private getStateBadgeAnimation(state: AgentState): object {
    switch (state) {
      case AgentState.THINKING:
        return {
          duration: 1500,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        };
      case AgentState.EXECUTING:
        return {
          duration: 800,
          curve: Curve.Linear,
          iterations: -1
        };
      case AgentState.ERROR:
        return {
          duration: 400,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        };
      default:
        return { duration: 0 };
    }
  }

  private formatDuration(seconds: number): string {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  }

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      Column() {
        this.contentBuilder()
      }
      .padding({ bottom: this.bottomAvoidHeight + 90 })

      // 悬浮导航容器
      Column() {
        Stack() {
          // 玻璃拟态背景层
          Column()
            .width('100%')
            .height('100%')
            .backgroundBlurStyle(BlurStyle.REGULAR)
            .opacity(this.navTransparency)
            .backdropFilter($r('sys.blur.20'))

          // 渐变叠加层
          Column()
            .width('100%')
            .height('100%')
            .linearGradient({
              direction: GradientDirection.Top,
              colors: [
                ['rgba(255,255,255,0.15)', 0.0],
                ['rgba(255,255,255,0.05)', 1.0]
              ]
            })
        }
        .width('100%')
        .height('100%')
        .borderRadius(28)
        .shadow({
          radius: 24,
          color: 'rgba(0,0,0,0.25)',
          offsetX: 0,
          offsetY: -6
        })

        Column() {
          // 工程信息栏(展开时显示)
          if (this.isExpanded) {
            Row() {
              Column() {
                Text(`${this.currentBPM} BPM`)
                  .fontSize(13)
                  .fontColor('#FFFFFF')
                  .fontWeight(FontWeight.Bold)
                
                Text('当前速度')
                  .fontSize(10)
                  .fontColor('rgba(255,255,255,0.6)')
              }
              .layoutWeight(1)

              Column() {
                Text(this.formatDuration(this.projectDuration))
                  .fontSize(13)
                  .fontColor('#FCD34D')
                  .fontWeight(FontWeight.Bold)
                
                Text('工程时长')
                  .fontSize(10)
                  .fontColor('rgba(255,255,255,0.6)')
              }
              .layoutWeight(1)

              Column() {
                Text(this.getPhaseLabel())
                  .fontSize(13)
                  .fontColor(this.getPhaseColor())
                  .fontWeight(FontWeight.Bold)
                
                Text('速度阶段')
                  .fontSize(10)
                  .fontColor('rgba(255,255,255,0.6)')
              }
              .layoutWeight(1)
            }
            .width('100%')
            .height(50)
            .padding({ left: 16, right: 16 })
            .backgroundColor('rgba(0,0,0,0.2)')
            .borderRadius({ topLeft: 28, topRight: 28 })
          }

          // 导航页签
          Row() {
            ForEach(this.navItems, (item: NavItem, index: number) => {
              Column() {
                Stack() {
                  Image(item.icon)
                    .width(26)
                    .height(26)
                    .fillColor(this.currentIndex === index ? this.getPhaseColor() : '#AAAAAA')

                  // 智能体状态徽章
                  if (item.agentType && this.getAgentStateForNavItem(item) !== AgentState.IDLE) {
                    Column()
                      .width(10)
                      .height(10)
                      .backgroundColor(this.getStateBadgeColor(this.getAgentStateForNavItem(item)))
                      .borderRadius(5)
                      .position({ x: 20, y: -4 })
                      .shadow({
                        radius: 8,
                        color: this.getStateBadgeColor(this.getAgentStateForNavItem(item)),
                        offsetX: 0,
                        offsetY: 0
                      })
                      .animation(this.getStateBadgeAnimation(this.getAgentStateForNavItem(item)))
                  }
                }
                .width(44)
                .height(44)

                Text(item.label)
                  .fontSize(11)
                  .fontColor(this.currentIndex === index ? this.getPhaseColor() : '#BBBBBB')
                  .margin({ top: 4 })
              }
              .layoutWeight(1)
              .onClick(() => {
                this.currentIndex = index;
                this.triggerHapticFeedback();
                AppStorage.setOrCreate('nav_page_change', item.page);
              })
            })
          }
          .width('100%')
          .height(this.isExpanded ? 70 : 80)
          .padding({ left: 16, right: 16 })
          .justifyContent(FlexAlign.SpaceAround)

          // 透明度调节(展开时显示)
          if (this.isExpanded) {
            Row() {
              Text('透明度')
                .fontSize(12)
                .fontColor('rgba(255,255,255,0.7)')
                .margin({ right: 8 })

              Slider({
                value: this.navTransparency * 100,
                min: 55,
                max: 85,
                step: 15,
                style: SliderStyle.InSet
              })
                .width(120)
                .onChange((value: number) => {
                  this.navTransparency = value / 100;
                })

              Text(`${Math.round(this.navTransparency * 100)}%`)
                .fontSize(12)
                .fontColor('rgba(255,255,255,0.7)')
                .margin({ left: 8 })
            }
            .width('100%')
            .height(40)
            .justifyContent(FlexAlign.Center)
          }
        }
        .width('100%')
        .height('100%')
      }
      .width('92%')
      .height(this.isExpanded ? 160 : 80)
      .margin({ bottom: this.bottomAvoidHeight + 12, left: '4%', right: '4%' })
      .animation({
        duration: 350,
        curve: Curve.Spring,
        iterations: 1
      })
      .gesture(
        LongPressGesture({ duration: 600 })
          .onAction(() => {
            this.isExpanded = !this.isExpanded;
          })
      )
    }
    .width('100%')
    .height('100%')
  }

  private getPhaseLabel(): string {
    const labels: Record<BPMPhase, string> = {
      [BPMPhase.ADAGIO]: '慢板',
      [BPMPhase.ANDANTE]: '行板',
      [BPMPhase.ALLEGRO]: '快板',
      [BPMPhase.PRESTO]: '急板'
    };
    return labels[this.currentPhase];
  }

  @BuilderParam contentBuilder: () => void = this.defaultContentBuilder;

  @Builder
  defaultContentBuilder(): void {
    Column() {
      Text('音轨编辑区域')
        .fontSize(16)
        .fontColor('#999999')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  private triggerHapticFeedback(): void {
    try {
      import('@kit.SensorServiceKit').then(sensor => {
        sensor.vibrator.startVibration({
          type: 'time',
          duration: 40
        }, { id: 0 });
      });
    } catch (error) {
      console.error('Haptic feedback failed:', error);
    }
  }
}

5.5 音轨编辑器(TrackEditor.ets)

// entry/src/main/ets/components/TrackEditor.ets
import { MusicAgentScheduler, Track } from '../agents/MusicAgentScheduler';

@Component
export struct TrackEditor {
  @State tracks: Track[] = [
    { id: '1', name: '旋律', type: 'melody', midiData: [], instrument: 'piano', volume: 80, pan: 0, muted: false, solo: false },
    { id: '2', name: '和声', type: 'harmony', midiData: [], instrument: 'strings', volume: 70, pan: -20, muted: false, solo: false },
    { id: '3', name: '贝斯', type: 'bass', midiData: [], instrument: 'bass', volume: 75, pan: 0, muted: false, solo: false },
    { id: '4', name: '鼓组', type: 'drums', midiData: [], instrument: 'drums', volume: 85, pan: 0, muted: false, solo: false }
  ];
  @State selectedTrack: string = '';
  @State isPlaying: boolean = false;
  @State currentTime: number = 0;
  private scheduler: MusicAgentScheduler = MusicAgentScheduler.getInstance();

  aboutToAppear(): void {
    // 监听播放状态
    AppStorage.watch('play_state', (state: boolean) => {
      this.isPlaying = state;
    });
  }

  private getTrackColor(type: string): string {
    const colors: Record<string, string> = {
      'melody': '#FCD34D',
      'harmony': '#8B5CF6',
      'bass': '#06B6D4',
      'drums': '#EF4444',
      'fx': '#10B981'
    };
    return colors[type] || '#888888';
  }

  build() {
    Column() {
      // 时间轴标尺
      Row() {
        Text('0:00')
          .fontSize(10)
          .fontColor('rgba(255,255,255,0.5)')
          .width(80)

        ForEach([1, 2, 3, 4, 5, 6, 7, 8], (bar: number) => {
          Text(`${bar}`)
            .fontSize(10)
            .fontColor('rgba(255,255,255,0.5)')
            .layoutWeight(1)
            .textAlign(TextAlign.Center)
        })
      }
      .width('100%')
      .height(30)
      .padding({ left: 80, right: 16 })
      .backgroundColor('rgba(255,255,255,0.03)')

      // 播放头
      if (this.isPlaying) {
        Column()
          .width(2)
          .height('100%')
          .backgroundColor('#EF4444')
          .position({ x: 80 + (this.currentTime % 8) * 100, y: 0 })
          .zIndex(100)
          .animation({
            duration: 100,
            curve: Curve.Linear
          })
      }

      // 音轨列表
      List() {
        ForEach(this.tracks, (track: Track) => {
          ListItem() {
            Row() {
              // 轨道控制区
              Column() {
                Row({ space: 8 }) {
                  // 静音按钮
                  Text('M')
                    .fontSize(10)
                    .fontColor(track.muted ? '#EF4444' : 'rgba(255,255,255,0.5)')
                    .backgroundColor(track.muted ? 'rgba(239,68,68,0.2)' : 'rgba(255,255,255,0.05)')
                    .padding({ left: 8, right: 8, top: 4, bottom: 4 })
                    .borderRadius(4)
                    .onClick(() => {
                      const index = this.tracks.findIndex(t => t.id === track.id);
                      this.tracks[index] = { ...track, muted: !track.muted };
                    })

                  // 独奏按钮
                  Text('S')
                    .fontSize(10)
                    .fontColor(track.solo ? '#FCD34D' : 'rgba(255,255,255,0.5)')
                    .backgroundColor(track.solo ? 'rgba(252,211,77,0.2)' : 'rgba(255,255,255,0.05)')
                    .padding({ left: 8, right: 8, top: 4, bottom: 4 })
                    .borderRadius(4)
                    .onClick(() => {
                      const index = this.tracks.findIndex(t => t.id === track.id);
                      this.tracks[index] = { ...track, solo: !track.solo };
                    })
                }

                Text(track.name)
                  .fontSize(12)
                  .fontColor(this.getTrackColor(track.type))
                  .fontWeight(FontWeight.Medium)
                  .margin({ top: 8 })

                Text(track.instrument)
                  .fontSize(10)
                  .fontColor('rgba(255,255,255,0.4)')
              }
              .width(80)
              .height(80)
              .padding(8)
              .backgroundColor('rgba(255,255,255,0.03)')
              .borderRadius({ topLeft: 8, bottomLeft: 8 })

              // 音轨内容区
              Stack() {
                // 背景网格
                Row() {
                  ForEach([0, 1, 2, 3], (i: number) => {
                    Column()
                      .width('25%')
                      .height('100%')
                      .border({ width: { right: 1 }, color: 'rgba(255,255,255,0.05)' })
                  })
                }
                .width('100%')
                .height('100%')

                // MIDI音符可视化
                if (track.midiData.length > 0) {
                  this.buildMidiVisualization(track)
                } else {
                  Text('点击生成旋律...')
                    .fontSize(11)
                    .fontColor('rgba(255,255,255,0.3)')
                }

                // 选中高亮
                if (this.selectedTrack === track.id) {
                  Column()
                    .width('100%')
                    .height('100%')
                    .border({ width: 2, color: this.getTrackColor(track.type) })
                    .backgroundColor(`${this.getTrackColor(track.type)}10`)
                }
              }
              .width('100%')
              .height(80)
              .backgroundColor('rgba(255,255,255,0.02)')
              .borderRadius({ topRight: 8, bottomRight: 8 })
              .onClick(() => {
                this.selectedTrack = track.id;
              })
            }
            .width('100%')
            .margin({ bottom: 4 })
          }
        })
      }
      .width('100%')
      .layoutWeight(1)
      .padding({ left: 16, right: 16 })

      // 底部控制栏
      Row({ space: 16 }) {
        Button(this.isPlaying ? '⏸️ 暂停' : '▶️ 播放')
          .fontSize(13)
          .fontColor('#FFFFFF')
          .backgroundColor(this.isPlaying ? '#F59E0B' : '#10B981')
          .padding({ left: 24, right: 24, top: 10, bottom: 10 })
          .borderRadius(20)
          .onClick(() => {
            this.isPlaying = !this.isPlaying;
            AppStorage.setOrCreate('play_state', this.isPlaying);
          })

        Button('🎵 生成旋律')
          .fontSize(13)
          .fontColor('#FFFFFF')
          .backgroundColor('#8B5CF6')
          .padding({ left: 20, right: 20, top: 10, bottom: 10 })
          .borderRadius(20)
          .onClick(() => {
            this.generateMelodyForSelectedTrack();
          })

        Button('🎹 自动配器')
          .fontSize(13)
          .fontColor('#FFFFFF')
          .backgroundColor('#06B6D4')
          .padding({ left: 20, right: 20, top: 10, bottom: 10 })
          .borderRadius(20)
          .onClick(() => {
            this.arrangeHarmonyForProject();
          })

        Button('🎚️ 母带处理')
          .fontSize(13)
          .fontColor('#FFFFFF')
          .backgroundColor('#F97316')
          .padding({ left: 20, right: 20, top: 10, bottom: 10 })
          .borderRadius(20)
          .onClick(() => {
            this.mixMasterProject();
          })
      }
      .width('100%')
      .height(60)
      .padding({ left: 16, right: 16 })
      .justifyContent(FlexAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('rgba(10, 10, 15, 0.95)')
    .borderRadius(16)
  }

  @Builder
  buildMidiVisualization(track: Track): void {
    Row() {
      ForEach(track.midiData.slice(0, 16), (note: number, index: number) => {
        Column()
          .width(20)
          .height(Math.max(10, note / 2))
          .backgroundColor(this.getTrackColor(track.type))
          .borderRadius(4)
          .margin({ right: 4 })
          .opacity(track.muted ? 0.3 : 1.0)
      })
    }
    .width('100%')
    .height('100%')
    .padding(8)
    .alignItems(VerticalAlign.Bottom)
  }

  private async generateMelodyForSelectedTrack(): Promise<void> {
    if (!this.selectedTrack) return;
    
    const result = await this.scheduler.generateMelody('happy', 'C_major', this.currentBPM);
    
    const index = this.tracks.findIndex(t => t.id === this.selectedTrack);
    if (index !== -1) {
      this.tracks[index] = {
        ...this.tracks[index],
        midiData: result.midi
      };
    }
  }

  private async arrangeHarmonyForProject(): Promise<void> {
    const melodyTrack = this.tracks.find(t => t.type === 'melody');
    if (!melodyTrack || melodyTrack.midiData.length === 0) return;

    const result = await this.scheduler.arrangeHarmony(melodyTrack.midiData, 'pop');

    // 更新和声、贝斯、鼓组轨道
    result.tracks.forEach((newTrack: Track) => {
      const index = this.tracks.findIndex(t => t.type === newTrack.type);
      if (index !== -1) {
        this.tracks[index] = {
          ...this.tracks[index],
          midiData: newTrack.midiData,
          instrument: newTrack.instrument
        };
      }
    });
  }

  private async mixMasterProject(): Promise<void> {
    const result = await this.scheduler.mixMaster(this.tracks, -14);
    
    // 应用混音参数到各轨道
    this.tracks = this.tracks.map(track => ({
      ...track,
      volume: Math.min(100, track.volume + 5)
    }));
  }
}

5.6 浮动频谱面板(SpectrumPanel.ets)

// entry/src/main/ets/components/SpectrumPanel.ets
import { AudioEngine } from '../utils/AudioEngine';

@Component
export struct SpectrumPanel {
  @State spectrumData: number[] = new Array(64).fill(0);
  @State peakFrequency: number = 0;
  @State peakEnergy: number = 0;
  private audioEngine: AudioEngine = AudioEngine.getInstance();
  private animationTimer: number = 0;

  aboutToAppear(): void {
    this.startSpectrumAnalysis();
  }

  aboutToDisappear(): void {
    clearInterval(this.animationTimer);
  }

  private startSpectrumAnalysis(): void {
    this.animationTimer = setInterval(() => {
      // 模拟FFT频谱数据
      this.spectrumData = this.spectrumData.map(() => Math.random() * 0.8);
      
      // 计算峰值
      this.peakEnergy = Math.max(...this.spectrumData);
      this.peakFrequency = this.spectrumData.indexOf(this.peakEnergy) * 343; // 约20Hz-20kHz范围

      // 同步频谱能量到全局光效
      const lowEnergy = this.spectrumData.slice(0, 16).reduce((a, b) => a + b, 0) / 16;
      const midEnergy = this.spectrumData.slice(16, 40).reduce((a, b) => a + b, 0) / 24;
      const highEnergy = this.spectrumData.slice(40, 64).reduce((a, b) => a + b, 0) / 24;

      AppStorage.setOrCreate('spectrum_energy', [lowEnergy, midEnergy, highEnergy]);
    }, 50); // 20fps更新
  }

  private getBarColor(index: number, value: number): string {
    if (index < 16) return `rgba(239, 68, 68, ${value})`;      // 低频-红
    if (index < 40) return `rgba(245, 158, 11, ${value})`;     // 中频-橙
    return `rgba(96, 165, 250, ${value})`;                      // 高频-蓝
  }

  build() {
    Column() {
      // 面板标题栏
      Row() {
        Text('📊 实时频谱')
          .fontSize(16)
          .fontColor('#FFFFFF')
          .fontWeight(FontWeight.Bold)
        
        Column() {
          Text(`${this.peakFrequency}Hz`)
            .fontSize(11)
            .fontColor('#FCD34D')
          
          Text(`峰值: ${(this.peakEnergy * 100).toFixed(1)}%`)
            .fontSize(10)
            .fontColor('rgba(255,255,255,0.5)')
        }
      }
      .width('100%')
      .height(50)
      .padding({ left: 16, right: 16 })
      .justifyContent(FlexAlign.SpaceBetween)

      // 频谱柱状图
      Row({ space: 2 }) {
        ForEach(this.spectrumData, (value: number, index: number) => {
          Column()
            .width(4)
            .height(`${value * 100}%`)
            .backgroundColor(this.getBarColor(index, value))
            .borderRadius({ topLeft: 2, topRight: 2 })
            .animation({
              duration: 50,
              curve: Curve.Linear
            })
        })
      }
      .width('100%')
      .height(200)
      .padding({ left: 12, right: 12 })
      .alignItems(VerticalAlign.Bottom)

      // 频段标签
      Row() {
        Text('低频 20-250Hz')
          .fontSize(10)
          .fontColor('#EF4444')
          .layoutWeight(1)
          .textAlign(TextAlign.Center)

        Text('中频 250-4kHz')
          .fontSize(10)
          .fontColor('#F59E0B')
          .layoutWeight(1)
          .textAlign(TextAlign.Center)

        Text('高频 4k-20kHz')
          .fontSize(10)
          .fontColor('#60A5FA')
          .layoutWeight(1)
          .textAlign(TextAlign.Center)
      }
      .width('100%')
      .height(30)
      .padding({ left: 16, right: 16 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('rgba(10, 10, 15, 0.95)')
    .borderRadius(16)
  }
}

5.7 多窗口光效同步管理器(WindowLightSync.ets)

// entry/src/main/ets/utils/WindowLightSync.ets
import { window } from '@kit.WindowManagerKit';

export class WindowLightSync {
  private static instance: WindowLightSync;
  private subWindows: Map<string, window.Window> = new Map();
  private currentTheme: string = '#1E3A8A';
  private currentIntensity: number = 0.6;

  private constructor() {}

  static getInstance(): WindowLightSync {
    if (!WindowLightSync.instance) {
      WindowLightSync.instance = new WindowLightSync();
    }
    return WindowLightSync.instance;
  }

  async registerSubWindow(name: string, win: window.Window): Promise<void> {
    this.subWindows.set(name, win);
    await this.syncLightToWindow(win);
  }

  async syncGlobalLightEffect(themeColor: string, intensity?: number): Promise<void> {
    this.currentTheme = themeColor;
    if (intensity !== undefined) {
      this.currentIntensity = intensity;
    }

    for (const [name, win] of this.subWindows) {
      await this.syncLightToWindow(win);
    }

    AppStorage.setOrCreate('global_theme_color', this.currentTheme);
    AppStorage.setOrCreate('global_light_intensity', this.currentIntensity);
  }

  private async syncLightToWindow(win: window.Window): Promise<void> {
    try {
      await win.setWindowBackgroundColor(`${this.currentTheme}20`);
      await win.setWindowShadow({
        radius: 20,
        color: `${this.currentTheme}40`,
        offsetX: 0,
        offsetY: 4
      });
    } catch (error) {
      console.error(`Failed to sync light to window:`, error);
    }
  }

  async handleFocusChange(focusedWindowName: string): Promise<void> {
    for (const [name, win] of this.subWindows) {
      const isFocused = name === focusedWindowName;
      const intensity = isFocused ? this.currentIntensity : this.currentIntensity * 0.4;
      
      try {
        await win.setWindowBackgroundColor(`${this.currentTheme}${Math.floor(intensity * 255).toString(16).padStart(2, '0')}`);
      } catch (error) {
        console.error(`Failed to handle focus change:`, error);
      }
    }
  }

  async createMidiKeyboardWindow(): Promise<<window.Window> {
    const keyboardWindow = await window.createWindow({
      name: 'midi_keyboard_float',
      windowType: window.WindowType.TYPE_FLOAT,
      ctx: getContext()
    });

    await keyboardWindow.moveWindowTo(1200, 100);
    await keyboardWindow.resize(320, 200);
    await keyboardWindow.setWindowLayoutFullScreen(true);
    await keyboardWindow.setWindowBackgroundColor('#00000000');

    this.registerSubWindow('midi_keyboard', keyboardWindow);
    return keyboardWindow;
  }

  async createSpectrumWindow(): Promise<<window.Window> {
    const spectrumWindow = await window.createWindow({
      name: 'spectrum_float',
      windowType: window.WindowType.TYPE_FLOAT,
      ctx: getContext()
    });

    await spectrumWindow.moveWindowTo(50, 100);
    await spectrumWindow.resize(300, 320);
    await spectrumWindow.setWindowLayoutFullScreen(true);
    await spectrumWindow.setWindowBackgroundColor('#00000000');

    this.registerSubWindow('spectrum', spectrumWindow);
    return spectrumWindow;
  }

  async createStyleSelectorWindow(): Promise<<window.Window> {
    const styleWindow = await window.createWindow({
      name: 'style_selector_float',
      windowType: window.WindowType.TYPE_FLOAT,
      ctx: getContext()
    });

    await styleWindow.moveWindowTo(50, 450);
    await styleWindow.resize(300, 280);
    await styleWindow.setWindowLayoutFullScreen(true);
    await styleWindow.setWindowBackgroundColor('#00000000');

    this.registerSubWindow('style_selector', styleWindow);
    return styleWindow;
  }
}

5.8 主页面集成(MusicStudioPage.ets)

// entry/src/main/ets/pages/MusicStudioPage.ets
import { BPMLightEffect, BPMPhase, MoodTag } from '../components/BPMLightEffect';
import { MusicFloatNavigation } from '../components/MusicFloatNavigation';
import { TrackEditor } from '../components/TrackEditor';
import { SpectrumPanel } from '../components/SpectrumPanel';
import { WindowLightSync } from '../utils/WindowLightSync';
import { MusicAgentScheduler } from '../agents/MusicAgentScheduler';

@Entry
@Component
struct MusicStudioPage {
  @State currentPage: string = 'TracksPage';
  @State currentBPM: number = 120;
  @State projectDuration: number = 0;
  @State currentMood: MoodTag = MoodTag.CALM;
  @State spectrumEnergy: number[] = [0, 0, 0];
  @State isPlaying: boolean = false;
  private windowSync: WindowLightSync = WindowLightSync.getInstance();
  private scheduler: MusicAgentScheduler = MusicAgentScheduler.getInstance();
  private playTimer: number = 0;

  aboutToAppear(): async () => {
    await this.scheduler.initialize();
    await this.initializeWindows();
    this.startProjectTimer();
    this.startSpectrumSync();

    AppStorage.watch('nav_page_change', (page: string) => {
      this.currentPage = page;
    });
  }

  private async initializeWindows(): Promise<void> {
    await this.windowSync.createMidiKeyboardWindow();
    await this.windowSync.createSpectrumWindow();
    await this.windowSync.createStyleSelectorWindow();
  }

  private startProjectTimer(): void {
    setInterval(() => {
      if (this.isPlaying) {
        this.projectDuration++;
        AppStorage.setOrCreate('project_metrics', {
          bpm: this.currentBPM,
          duration: this.projectDuration
        });

        const phase = this.getCurrentPhase();
        const themeColor = this.getPhaseColor(phase);
        this.windowSync.syncGlobalLightEffect(themeColor, this.getIntensityBySpectrum());
      }
    }, 1000);
  }

  private startSpectrumSync(): void {
    AppStorage.watch('spectrum_energy', (energy: number[]) => {
      this.spectrumEnergy = energy;
    });
  }

  private getCurrentPhase(): BPMPhase {
    if (this.currentBPM < 60) return BPMPhase.ADAGIO;
    if (this.currentBPM < 90) return BPMPhase.ANDANTE;
    if (this.currentBPM < 120) return BPMPhase.ALLEGRO;
    return BPMPhase.PRESTO;
  }

  private getPhaseColor(phase: BPMPhase): string {
    const colors: Record<BPMPhase, string> = {
      [BPMPhase.ADAGIO]: '#1E3A8A',
      [BPMPhase.ANDANTE]: '#10B981',
      [BPMPhase.ALLEGRO]: '#F59E0B',
      [BPMPhase.PRESTO]: '#EF4444'
    };
    return colors[phase];
  }

  private getIntensityBySpectrum(): number {
    const avgEnergy = this.spectrumEnergy.reduce((a, b) => a + b, 0) / 3;
    return Math.min(1.0, 0.3 + avgEnergy * 0.7);
  }

  build() {
    Stack() {
      // 底层:沉浸光效层
      BPMLightEffect({
        currentBPM: this.currentBPM,
        currentMood: this.currentMood,
        spectrumEnergy: this.spectrumEnergy
      })

      // 中层:主内容区域
      Column() {
        this.buildHeader()
        
        Stack() {
          if (this.currentPage === 'TracksPage') {
            TrackEditor()
          } else if (this.currentPage === 'HarmonyPage') {
            this.buildHarmonyPage()
          } else if (this.currentPage === 'MixingPage') {
            this.buildMixingPage()
          } else if (this.currentPage === 'StylePage') {
            this.buildStylePage()
          }
        }
        .layoutWeight(1)
      }
      .width('100%')
      .height('100%')

      // 顶层:悬浮导航
      MusicFloatNavigation({
        contentBuilder: () => {}
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#050508')
    .expandSafeArea(
      [SafeAreaType.SYSTEM],
      [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM, SafeAreaEdge.START, SafeAreaEdge.END]
    )
  }

  @Builder
  buildHeader(): void {
    Row() {
      Column() {
        Text('🎵 音浪智脑')
          .fontSize(20)
          .fontColor('#FFFFFF')
          .fontWeight(FontWeight.Bold)
        
        Text(`BPM: ${this.currentBPM} | 时长: ${this.formatDuration(this.projectDuration)}`)
          .fontSize(12)
          .fontColor('rgba(255,255,255,0.6)')
          .margin({ top: 4 })
      }
      .alignItems(HorizontalAlign.Start)

      Row({ space: 12 }) {
        // BPM调节
        Slider({
          value: this.currentBPM,
          min: 40,
          max: 200,
          step: 1,
          style: SliderStyle.InSet
        })
          .width(120)
          .onChange((value: number) => {
            this.currentBPM = Math.round(value);
          })

        // 情绪标签选择
        Select([
          { value: '快乐', icon: $r('app.media.ic_happy') },
          { value: '悲伤', icon: $r('app.media.ic_sad') },
          { value: '激昂', icon: $r('app.media.ic_energetic') },
          { value: '宁静', icon: $r('app.media.ic_calm') }
        ])
          .selected(this.getMoodIndex())
          .fontColor('#FFFFFF')
          .backgroundColor('rgba(255,255,255,0.1)')
          .borderRadius(12)
          .onSelect((index: number) => {
            const moods = [MoodTag.HAPPY, MoodTag.SAD, MoodTag.ENERGETIC, MoodTag.CALM];
            this.currentMood = moods[index];
          })

        Button('智能体面板')
          .fontSize(13)
          .fontColor('#FFFFFF')
          .backgroundColor('rgba(255,255,255,0.1)')
          .padding({ left: 16, right: 16, top: 8, bottom: 8 })
          .borderRadius(20)
          .onClick(() => {
            AppStorage.setOrCreate('show_agent_panel', true);
          })
      }
    }
    .width('100%')
    .height(70)
    .padding({ left: 24, right: 24 })
    .backgroundBlurStyle(BlurStyle.REGULAR)
    .backdropFilter($r('sys.blur.20'))
    .border({
      width: { bottom: 1 },
      color: 'rgba(255,255,255,0.1)'
    })
    .justifyContent(FlexAlign.SpaceBetween)
  }

  private getMoodIndex(): number {
    const moods = [MoodTag.HAPPY, MoodTag.SAD, MoodTag.ENERGETIC, MoodTag.CALM];
    return moods.indexOf(this.currentMood);
  }

  private formatDuration(seconds: number): string {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  }

  @Builder
  buildHarmonyPage(): void {
    Column() {
      Text('🎹 和声编排')
        .fontSize(18)
        .fontColor('#FFFFFF')
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 20 })

      // 和弦进行可视化
      Row({ space: 12 }) {
        ForEach(['C', 'G', 'Am', 'F'], (chord: string, index: number) => {
          Column() {
            Text(chord)
              .fontSize(20)
              .fontColor('#8B5CF6')
              .fontWeight(FontWeight.Bold)
            
            Text(`${index + 1}小节`)
              .fontSize(11)
              .fontColor('rgba(255,255,255,0.5)')
          }
          .width(80)
          .height(80)
          .backgroundColor('rgba(139, 92, 246, 0.1)')
          .borderRadius(12)
          .border({ width: 2, color: 'rgba(139, 92, 246, 0.3)' })
          .justifyContent(FlexAlign.Center)
        })
      }
      .margin({ bottom: 20 })

      // 乐器分配
      List() {
        ForEach([
          { name: '钢琴', role: '旋律', volume: 80 },
          { name: '弦乐', role: '铺底', volume: 70 },
          { name: '贝斯', role: '低音', volume: 75 },
          { name: '鼓组', role: '节奏', volume: 85 }
        ], (instrument: { name: string; role: string; volume: number }) => {
          ListItem() {
            Row() {
              Column() {
                Text(instrument.name)
                  .fontSize(14)
                  .fontColor('#FFFFFF')
                
                Text(instrument.role)
                  .fontSize(11)
                  .fontColor('rgba(255,255,255,0.5)')
              }
              .alignItems(HorizontalAlign.Start)
              .layoutWeight(1)

              Slider({
                value: instrument.volume,
                min: 0,
                max: 100,
                step: 1
              })
                .width(120)

              Text(`${instrument.volume}%`)
                .fontSize(12)
                .fontColor('#FFFFFF')
                .width(40)
            }
            .width('100%')
            .padding(12)
            .backgroundColor('rgba(255,255,255,0.05)')
            .borderRadius(12)
          }
          .margin({ bottom: 8 })
        })
      }
      .width('90%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildMixingPage(): void {
    Column() {
      Text('🎚️ 混音母带')
        .fontSize(18)
        .fontColor('#FFFFFF')
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 20 })

      // EQ可视化
      Column() {
        Text('均衡器 (EQ)')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .margin({ bottom: 12 })

        Row({ space: 16 }) {
          this.buildEQBand('低频', '#EF4444', 80)
          this.buildEQBand('中频', '#F59E0B', 65)
          this.buildEQBand('高频', '#60A5FA', 70)
        }
      }
      .width('90%')
      .padding(16)
      .backgroundColor('rgba(255,255,255,0.05)')
      .borderRadius(12)
      .margin({ bottom: 16 })

      // 压缩器
      Column() {
        Text('压缩器')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .margin({ bottom: 12 })

        Row({ space: 16 }) {
          this.buildCompressorParam('阈值', '-18dB', '#06B6D4')
          this.buildCompressorParam('比率', '4:1', '#06B6D4')
          this.buildCompressorParam('攻击', '10ms', '#06B6D4')
          this.buildCompressorParam('释放', '100ms', '#06B6D4')
        }
      }
      .width('90%')
      .padding(16)
      .backgroundColor('rgba(255,255,255,0.05)')
      .borderRadius(12)
      .margin({ bottom: 16 })

      // 响度表
      Column() {
        Text('响度表 (LUFS)')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .margin({ bottom: 12 })

        Row() {
          Text('-14.2')
            .fontSize(36)
            .fontColor('#10B981')
            .fontWeight(FontWeight.Bold)
          
          Text('LUFS')
            .fontSize(14)
            .fontColor('rgba(255,255,255,0.5)')
            .margin({ left: 8 })
        }

        // 响度条
        Row() {
          ForEach([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], (i: number) => {
            Column()
              .width(20)
              .height(20)
              .backgroundColor(i < 7 ? '#10B981' : i < 9 ? '#F59E0B' : '#EF4444')
              .borderRadius(4)
              .margin({ right: 4 })
          })
        }
      }
      .width('90%')
      .padding(16)
      .backgroundColor('rgba(255,255,255,0.05)')
      .borderRadius(12)

      Button('🎯 自动母带')
        .fontSize(14)
        .fontColor('#FFFFFF')
        .backgroundColor('#F97316')
        .padding({ left: 32, right: 32, top: 12, bottom: 12 })
        .borderRadius(24)
        .margin({ top: 20 })
        .onClick(() => {
          // 触发混音智能体自动母带
        })
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildEQBand(label: string, color: string, value: number): void {
    Column() {
      Text(label)
        .fontSize(12)
        .fontColor('#FFFFFF')
        .margin({ bottom: 8 })

      Slider({
        value: value,
        min: -12,
        max: 12,
        step: 0.5,
        direction: Axis.Vertical
      })
        .height(120)

      Text(`${value > 0 ? '+' : ''}${value}dB`)
        .fontSize(11)
        .fontColor(color)
        .margin({ top: 8 })
    }
  }

  @Builder
  buildCompressorParam(label: string, value: string, color: string): void {
    Column() {
      Text(value)
        .fontSize(16)
        .fontColor(color)
        .fontWeight(FontWeight.Bold)

      Text(label)
        .fontSize(10)
        .fontColor('rgba(255,255,255,0.5)')
        .margin({ top: 4 })
    }
    .width(70)
    .height(60)
    .backgroundColor('rgba(255,255,255,0.03)')
    .borderRadius(8)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildStylePage(): void {
    Column() {
      Text('🎨 风格迁移')
        .fontSize(18)
        .fontColor('#FFFFFF')
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 20 })

      Grid() {
        GridItem() {
          this.buildStyleCard('流行', 'Pop', '#F472B6', '🎤')
        }
        
        GridItem() {
          this.buildStyleCard('爵士', 'Jazz', '#F59E0B', '🎷')
        }
        
        GridItem() {
          this.buildStyleCard('古典', 'Classical', '#8B5CF6', '🎻')
        }
        
        GridItem() {
          this.buildStyleCard('电子', 'Electronic', '#06B6D4', '🎹')
        }
        
        GridItem() {
          this.buildStyleCard('摇滚', 'Rock', '#EF4444', '🎸')
        }
        
        GridItem() {
          this.buildStyleCard('民谣', 'Folk', '#10B981', '🪕')
        }
      }
      .columnsTemplate('1fr 1fr 1fr')
      .rowsTemplate('1fr 1fr')
      .width('90%')
      .height(300)
      .gap(12)

      // 风格强度滑块
      Column() {
        Text('迁移强度')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .margin({ bottom: 12 })

        Slider({
          value: 70,
          min: 0,
          max: 100,
          step: 1
        })
          .width('80%')

        Text('70% - 保留旋律,改变配器风格')
          .fontSize(11)
          .fontColor('rgba(255,255,255,0.5)')
          .margin({ top: 8 })
      }
      .width('90%')
      .padding(16)
      .backgroundColor('rgba(255,255,255,0.05)')
      .borderRadius(12)
      .margin({ top: 20 })

      Button('🔄 应用风格迁移')
        .fontSize(14)
        .fontColor('#FFFFFF')
        .backgroundColor('#8B5CF6')
        .padding({ left: 32, right: 32, top: 12, bottom: 12 })
        .borderRadius(24)
        .margin({ top: 20 })
        .onClick(() => {
          // 触发风格智能体迁移
        })
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildStyleCard(name: string, enName: string, color: string, icon: string): void {
    Column() {
      Text(icon)
        .fontSize(32)
        .margin({ bottom: 8 })

      Text(name)
        .fontSize(14)
        .fontColor('#FFFFFF')
        .fontWeight(FontWeight.Medium)

      Text(enName)
        .fontSize(11)
        .fontColor('rgba(255,255,255,0.5)')
        .margin({ top: 4 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(`${color}15`)
    .borderRadius(12)
    .border({ width: 2, color: `${color}30` })
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      // 选择风格
    })
  }
}

六、关键技术总结

6.1 HMAF音乐制作智能体开发清单

技术点 API/方法 应用场景
智能体会话创建 hmaf.createAgentSession({ mode: MULTI_AGENT }) 四层智能体协同创作
意图解析 intents.createIntentEngine({ supportedDomains }) 创作者指令意图识别
任务分发 hmafSession.sendTask({ targetAgent, taskType }) 智能体间创作任务调度
状态监听 AppStorage 全局状态回调 跨组件创作状态同步
分布式协同 enableDistributed: true 多设备协作创作
LLM旋律生成 modelType: 'llm' 旋律智能体生成MIDI动机
和声编排 modelType: 'llm' 和声智能体自动配器
风格迁移 modelType: 'llm' 风格智能体转换音乐风格

6.2 沉浸光感实现清单

技术点 API/方法 应用场景
系统材质效果 systemMaterialEffect: SystemMaterialEffect.IMMERSIVE 标题栏沉浸效果
背景模糊 backgroundBlurStyle(BlurStyle.REGULAR) 悬浮导航玻璃拟态
背景滤镜 backdropFilter($r('sys.blur.20')) 精细模糊控制
安全区扩展 expandSafeArea([SafeAreaType.SYSTEM], [...]) 全屏沉浸布局
窗口沉浸 setWindowLayoutFullScreen(true) 无边框模式
光效动画 animation({ duration, iterations: -1 }) BPM脉搏呼吸灯
动态透明度 backgroundOpacity 焦点感知降级
窗口阴影 setWindowShadow({ radius, color }) 跨窗口光效联动

6.3 BPM阶段光效映射

BPM阶段 速度范围 主题色 脉冲周期 光效强度
慢板 <60 BPM 深海蓝 #1E3A8A 4秒 30%
行板 60-90 BPM 薄荷绿 #10B981 2秒 60%
快板 90-120 BPM 活力橙 #F59E0B 1秒 80%
急板 >120 BPM 炽烈红 #EF4444 0.5秒 100%

6.4 智能体状态徽章动画

智能体状态 徽章颜色 动画效果 创作含义
空闲 #888888 静态 智能体待命
思考中 #8B5CF6 呼吸脉冲 LLM生成旋律中
执行中 #F97316 旋转进度 配器/混音处理中
已完成 #10B981 静态 任务执行成功
异常 #EF4444 快速闪烁 音频处理错误

6.5 性能优化建议

  1. 光效渲染优化:使用willChange: true标记频繁变化的动画层,避免全量重绘
  2. 智能体并发控制:通过maxConcurrentAgents: 4限制并发,防止资源争抢
  3. 频谱数据节流:FFT分析频率控制在20fps,避免过度计算
  4. 窗口管理:子窗口使用TYPE_FLOAT类型,避免创建过多独立进程
  5. 音频缓冲:使用环形缓冲区管理音频数据,避免内存泄漏

七、总结与展望

本文基于HarmonyOS 6(API 23)的HMAF智能体框架、悬浮导航与沉浸光感特性,构建了一套面向PC端专业音乐制作的"音浪智脑"系统。核心创新点包括:

  1. 四层智能体协作架构:旋律、和声、混音、风格四大智能体通过HMAF的A2A模式实时协作,将创作者从重复性编曲工作中解放出来
  2. BPM脉搏光效系统:基于实时BPM与频谱能量的动态光效渲染,让创作者"看见"音乐的情绪色彩
  3. 悬浮创作导航:底部玻璃拟态导航承载四大模块,智能体状态徽章实时反馈,工程信息一键展开
  4. 多窗口光效联动:主窗口与三个浮动子窗口通过WindowLightSync实现跨窗口光效同步,焦点感知自动调节
  5. 频谱能量光效:基于实时FFT频谱分析,低频触发深红光晕,中频触发暖黄光晕,高频触发冰蓝光晕

随着HarmonyOS生态的持续发展,音乐制作智能体将向着"数字人制作人"“多模态交互”"跨设备协作创作"等方向演进。HMAF框架的分布式能力与HarmonyOS的跨端协同特性,将为音乐创作带来"一机控全场、多屏协同作"的全新体验。


转载自:https://blog.csdn.net/u014727709/article/details/161265737
欢迎 👍点赞✍评论⭐收藏,欢迎指正

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐