65.9K
CodeProject 正在变化。 阅读更多。
Home

ProjectMIDI:一套可扩展的小型 MIDI .NET 程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (14投票s)

2006 年 1 月 11 日

26分钟阅读

viewsIcon

86781

downloadIcon

3425

本文介绍了多个 .NET 程序集如何协同工作,以在现场表演环境中控制 MIDI 设备。

Image of ProjectMIDI PDF Dialog

引言

MIDI 提供了一个通用接口,允许互连大量电子设备。让这些设备协同工作则是另一回事。本项目旨在为这个特定问题提供解决方案。

本文介绍了 ProjectMIDI,一套小型协作式 MIDI 应用程序。我将尝试解释代码的工作原理,并提供其实现的高级描述。为使本文篇幅适中,我将引用实际的源文件,而不是将代码复制到本文中。我很抱歉这意味着您可能需要在本文和源代码之间来回翻阅。

我撰写本文的原因之一是为了征求您的反馈。因此,请将您的建议通过电子邮件发送给我。

ProjectMIDI 是一个非商业软件项目,旨在为现场表演环境中的 MIDI 设备提供可扩展的控制。本项目的目的是构建软件,将最新的、现成的技术整合到用于现场表演的领先 MIDI 设置中。

其中一些代码仍在扩展中。我已尝试清理它,但我为代码中可能遗留的任何松散部分表示歉意。

Image of ProjectMIDI Task Bar icon menu

我希望其他编程爱好者会对此感兴趣,并编写自己的程序集来扩展该项目。这就是我将其开放和可扩展,并记录各部分如何工作和相互交互的原因。我主要使用 C# 进行开发,但我相信可以使用任何 .NET 语言。我还提供了一个 VB .NET 示例程序集。

我的一个关键设计点是提供核心程序集中的架构和功能,使其非常简单地创建额外的功能程序集。

快速入门

要试用代码,请下载并解压可执行文件。此文件包含一组目录和示例文件。然后启动 ProjectMidi.exe 文件。它将提示您输入文件路径。只需选择相同的目录。

背景

我既是音乐家也是程序员。我喜欢做这两件事。坦率地说,我可能更喜欢技术,而不是仅仅是演奏的音乐方面。啊,给我一个带有一大堆能发出声音的旋钮的控制面板...

话虽如此,我从未找到任何真正能让我在现场表演环境中使用 MIDI 设备大部分功能的软件。当然,使用 Cakewalk Sonar 或 Tascam Gigastudio 等程序可以完成一些事情。但每当我使用这些程序时,我总是想做更多。我非常熟悉 MIDI 硬件能做什么,我希望能够利用这种能力。我正在编写这个软件,以真正利用我拥有的 MIDI 硬件。

我也希望其他人如果感兴趣的话也能参与进来。我正在公开源代码。我还创建了这个网站,作为任何对 ProjectMIDI 感兴趣的人的聚会场所。

您可以使用 ProjectMIDI 做什么?

关于使用 ProjectMIDI 教程可在 ProjectMIDI 网站上找到。

我每周日都会为我的教堂乐队演奏鼓和键盘,并使用 ProjectMIDI。以下是该软件目前为我所做的一些事情:

  1. 它在现场表演期间显示乐谱或歌词表

    我扫描我的音乐,并使用此软件在表演期间显示它。我有一台小型平板电脑,安装在我的鼓组上,还有一台笔记本电脑,放在我的 MIDI 键盘上方。我使用 MIDI 翻页和前进歌曲。我可以将牛铃鼓垫编程为执行此操作,但通常使用 TD8 的增/减按钮或脚踏开关。

  2. 我将歌曲组织成“组曲”

    这使我能够在演出期间轻松地从一首歌曲切换到另一首歌曲。右侧显示的是“歌曲组”对话框。右侧的歌曲列表帮助我记住组曲中歌曲的顺序。左侧显示了我创建的所有组曲。我按日期组织这些组曲。

    Picture of SongSet dialog

  3. 为每首歌曲和/或页面设置音色

    如上所述,在“翻页”时,为我的每个 MIDI 乐器设置每首歌曲和页面的音色。我可以根据歌曲和页面为我的鼓垫设置不同的鼓声。

  4. 使用平板电脑手写笔注释我的音乐

    这太酷了。我只需在平板电脑上直接在显示的音乐上书写,即可制作表演笔记。然后软件会保存这些笔记,并在每次我显示该页面时显示它们。

    Picture of Connections dialog

  5. 播放关联的 MP3 文件

    有时在练习时,我们需要听原版录音才能掌握某个部分。我可以录制歌曲的 MP3 文件并将其与音乐关联。我所需要做的就是显示歌曲时点击播放按钮。我也可以用它来伴随歌曲练习。

  6. 快速将鼓声分配到任何鼓垫,并将音色分配到键盘

    尽管我倾向于对大多数歌曲使用相同的鼓组,但我经常想重新分配一个或两个鼓垫以获得独特的声音。我可以使用 TD8 的控件来完成此操作,但这很复杂且缓慢,并且更改很容易丢失。使用此程序可以使其快速简便,并且我的更改将在下次显示歌曲时记住。

ProjectMIDI 模块化方法

我意识到(也是许多编程书籍的主题)是,由于 MIDI 可以做的事情“非常”多,因此将编程分解成小的、可管理的部分变得极其重要。

  • ProjectMIDI 应用程序

    这是主程序。它负责定位和加载所有其他部分。这些其他部分作为 .NET 程序集实现。这些程序集的技术细节,包括创建新程序集的说明,将在 ProjectMIDI 网站上讨论,并将在本文后续部分进行讨论。

  • 连接程序集

    程序集之间事件和动作的连接是动态建立的。Connections 程序集提供用于建立和记住这些连接的控件。

  • Songset 程序集

    Songset 提供将歌曲组织成集合的功能。它使用事件与其他模块通信以保持同步。每个模块通常根据当前选定的歌曲和页面运行。

  • 子菜单程序集

    此程序集实现了多级自定义菜单。

  • PDF 程序集

    PDF 小程序显示来自 PDF 文件的乐谱(或任何内容)。这通常是现场表演期间使用的主要用户界面。

  • TIFF 程序集

    或者,TIFF 小程序可用于从 TIFF 文件显示乐谱。

  • 墨迹程序集

    墨迹小程序允许使用平板电脑的触控笔在 PDF 或 TIFF 显示的乐谱上书写。这需要 Windows XP Tablet PC Edition。这是一种非常棒的方式来注释和标记您的音乐以进行现场表演。

  • MIDI 程序集

    此程序集将连接到系统上存在的所有 MIDI 端口,以及其他程序集以连接到它们。

  • MIDI 设备程序集

    特定 MIDI 设备的支持由“设备程序集”提供。设备程序集可以实现所需的任何设备特定功能。通常,它将包含一个对话框,允许将特定音色(补丁)与特定歌曲甚至页面关联。如果需要,可以实现对话框以允许编程新音色。这当然取决于特定设备的功能。

    MIDI 设备上存在的输入控件由设备程序集命名并标识给 ProjectMIDI 。然后用户可以将这些控件连接到适当的“动作”。

ProjectMIDI 连接

ProjectMIDI 允许您控制系统中不同输入“事件”与输出“动作”之间的连接方式。

每个程序集都会发布它生成的“事件”和它可以响应的“动作”。这是以不需要“先验”了解其他模块的方式完成的。ProjectMIDI 然后提供了几种机制来连接“事件”到“动作”。

事件包括以下内容

  • MIDI 事件:包括按键、鼓垫、旋钮、脚踏板和按钮
  • Windows 对话框控件:包括滑块和按钮
  • 自定义菜单:ProjectMIDI 提供了创建您自己的菜单的功能

例如,您可能希望使用 MIDI 键盘的脚踏开关来更改显示的音乐页面。或者您可能希望从一个或多个方便的自定义菜单启动常用的 MIDI 设备编辑器。通过将特定事件映射到所需动作,可以轻松完成此操作。

ProjectMidi 事件

事件是由用户交互引起的。这包括您操作 MIDI 设备时产生的 MIDI 事件,以及与软件交互时产生的事件。

ProjectMidi 动作

动作是可以由事件控制或触发的事情。这包括选择歌曲、页面或音色以及启动 MIDI 设备音色编辑器。

连接

您可以建立“事件”和“动作”之间的“连接”。某些连接在您安装程序时已默认创建。其他连接将特定于您的设置,并取决于您使用的 MIDI 设备。

Image of Connections Dialog

此处所示的“连接编辑器”允许您更改或创建新连接。

排序连接

可以通过单击列标题对连接列表进行排序。单击“ID”列标题将按 ID 号对连接进行排序。

单击“源”或“事件”列标题将按源程序集名称和事件对连接进行排序。

同样,点击“目标”或“动作”列标题将按目标程序集和动作对连接列表进行排序。

添加连接

您可以通过在列表中的任意位置右键单击,然后选择第一个菜单项“添加新连接”来添加新连接。新的连接将在列表末尾创建。然后,您需要为新连接选择一个源事件和目标动作。

删除连接

您可以通过选择连接,然后右键单击它并选择“删除选定连接”菜单项来删除未使用或不需要的连接。

更改连接的源程序集或事件

您可以通过选择连接,然后右键单击“源”或“事件”字段来更改源程序集或事件。显示的上下文菜单将包含程序集名称或事件名称的列表。

更改连接的目标程序集或动作

您可以通过选择连接,然后右键单击“目标”或“动作”字段来更改目标程序集或动作。显示的上下文菜单将包含程序集名称或事件名称的列表。

ProjectMIDI 可自定义菜单

Picture of menu editor dialog

ProjectMIDI 允许您自定义其任何菜单。菜单由菜单事件和动作之间建立的“连接”定义。默认情况下,菜单上显示的名称将是动作的名称。

您可以使用菜单编辑器对话框重新排列菜单中的项目,以及更改菜单上显示的文本。

您可以直接编辑每个菜单项的文本。

右键单击菜单项会显示一个上下文菜单,允许您添加或删除分隔线,或向上或向下移动菜单项。

组曲、歌曲、页面和音色

ProjectMIDI 将音乐组织成组曲、歌曲、页面和音色。

歌曲集

歌曲集是歌曲的集合。您可以按照自己喜欢的方式将歌曲分组。通常,这将是在特定演出中演奏的一组歌曲。或者,它也可以是特定主题的歌曲,或某个艺术家的歌曲,等等。

歌曲

一首歌曲是基本的组织单位。ProjectMIDI 中的每个程序集通常会将一组设置与每首歌曲关联。例如,这可以是声音到键盘区域或鼓垫的映射。

页数

歌曲可以分为多个页面。每个页面都可以有自己的声音和与之关联的设置。

音色

页面可以进一步划分为音色。例如,如果您希望主歌和副歌具有不同的声音,但两者都出现在同一乐谱页面上,就可以这样做。

保存您的组曲

歌曲集保存在 SongSets 文件夹中的文件中。然后可以在以后重新加载这些文件以供重复使用。使用 SongSets 程序集对话框中的“文件”菜单项来加载和保存您的歌曲集。

使用代码

在本节中,我将描述 ProjectMIDI 的实现方式以及如何使用您自己的代码对其进行扩展。我将提供源代码示例,以便您创建自己的 MIDI 小程序或设备模块。

您将需要什么

您将需要 Visual Studio .NET。ProjectMIDI 是作为一组 .NET 程序集实现的。创建新的小程序或设备模块涉及创建一个新的 .NET 程序集,该程序集包含一个实现 ProjectMIDI 定义的特定接口的类。它还使用自定义属性,允许 ProjectMIDI 使用反射互连事件和动作(特殊事件处理程序)。

ProjectMIDI 实现了 .NET 程序集的“后期绑定”。因此,可以创建新的程序集,而 ProjectMIDI 无需了解它们即可与它们一起工作。

架构

ProjectMIDI 通过将其功能划分为多个 DLL .NET 程序集来工作。这些程序集是“后期绑定”,这意味着 ProjectMIDI 将搜索并加载任何包含实现其已知接口的类的程序集。在这些页面中,我将这些 DLL 文件简称为“程序集”。

主要可执行文件是 ProjectMIDI.exe。这是核心程序,它依次定位和加载所有其他程序集。

组曲、歌曲、页面和音色数据模型

ProjectMidi.exe 实现了将数据组织成组曲、歌曲、页面和音色的基本结构。

歌曲集

一个或多个歌曲名称可以组织成一个集合,称为“歌曲集”。这可以是为特定演出播放的歌曲集,或者可能是按主题或风格相关的歌曲集。事实上,它甚至不需要是歌曲的集合,而可以是 MIDI 设置的集合。

歌曲

这些是传递给每个程序集的“名称”。现有的 PDF 和 TIFF 小程序假定这是 PDF 或 TIFF 文件的名称(减去文件扩展名)。所有其他现有程序集都严格将其视为用于其数据的文件名。

页数

歌曲可以分解成多个部分,称为页面。PDF、TIFF 和 Ink 程序集将使用此功能显示不同的乐谱页面和音符。设备模块可以选择单独的音色或其他设置。

音色

音色允许将页面分成多个部分,每个部分具有不同的音色集。PDF、TIFF 和 Ink 程序集忽略此参数。但是,设备模块应允许为每个音色选择不同的音色或设置组。

响应歌曲、页面或音色变化

程序集可以选择在歌曲、页面或音色更改时收到通知。程序集如何响应由每个程序集自行决定和实现。

事件和动作模型

ProjectMIDI 力求提供高度的灵活性和可扩展性。实现这一点的方法之一是“泛化”用户输入或事件与结果动作的关联方式。

事件

每个程序集都可以定义和发布它支持的一组事件。对于小程序来说,这可能是一个菜单或按钮,而对于设备程序集来说,这可能是一个硬件控制(滑块或旋钮)或脚踏板或 MIDI 触发器。

事件通过赋予它们预定义的“自定义属性”来暴露给 ProjectMIDI 。这些属性指定要向用户显示的名称以及输入提供的值的数量。

属性给出的名称很重要,以便使其易于使用和直观。例如,我过去曾使用过允许将特定 MIDI 数据类型(例如程序更改)连接到动作的 MIDI 软件。但这到底是什么意思却一点也不清楚。我更愿意能够指定“TD8 增/减按钮”将导致一个动作,而不必查找和指定 MIDI 数据类型和值。

除了为输入提供名称之外,自定义属性还指定了可能的输入值数量。这允许更好地匹配输入和输出。例如,将 128 位旋钮连接到简单的开/关类型动作可能需要将值 0-63 解释为“关”,将值 64-127 解释为“开”。

事件可以关联一个“自动连接”名称。ProjectMIDI 会在启动时自动连接具有匹配自动连接名称的事件和动作。

Actions

每个程序集还定义并发布它实现的一组动作。这些动作包括“下一页”、“显示 TD8 音色编辑器”等等。这只受我们的想象力限制。

动作是具有与上述事件处理所需的签名匹配的方法。自定义属性用于指定友好的名称和动作可以处理的值的数量。

从事件传递给动作的数据在 EventArgs 或派生自它的类中传递。

连接列表

输入可以通过几种方式连接到动作

  1. 使用匹配的自动连接名称
  2. 通过使用连接对话框
    提供了一个对话框,允许用户手动指定其他连接,或禁用自动连接。

程序集定义的事件/动作关联

除了上述两种方法,不同的程序集还可以通过其他几种方式相互通信

  1. 暴露事件、动作、方法或属性
    ProjectMIDI 提供了一种机制,允许程序集查看并连接到其他程序集,前提是它们已使用 ProjectMIDI 的自定义属性进行标记。
  2. 使用多重接口派生
    除了从 IProjectMidi 派生之外,程序集的 ProjectMIDI 类还可以从其他接口派生。另一个程序集可以使用 ProjectMIDI 提供的机制搜索 ProjectMIDI 加载的程序集列表。每个程序集都可以测试是否派生自所需的接口。一旦找到,就可以直接使用自定义接口。

持久化

用户指定的连接将持久化到 ProjectMIDI 文件夹中的 XML 文件 actions.xml 中。每次 ProjectMIDI 启动时,这些连接都将恢复。

ProjectMIDI 主可执行文件

ProjectMIDI dialog image

ProjectMIDI.exe 是主要的应用程序文件。它启动时,会依次加载所有其他 ProjectMIDI 程序集。

它作为任务栏图标加载。它在“程序集”子菜单中显示它已加载的程序集列表。可以通过单击“程序集”子菜单中其名称来显示或隐藏可以显示对话框的程序集。

ProjectMIDI.exe 提供启动序列,以允许程序集有序地启动。例如,某个程序集可能需要在所有程序集加载后执行一些启动初始化。或者它可能需要等到所有程序集之间的连接都建立后才能进行。

所有 ProjectMIDI 程序集均派生自 IProjectMidi 接口。ProjectMIDI.exe 利用此事实来识别 ProjectMIDI 程序集。

   // All ProjectMIDI Assemblies must include a class which derives

   // from this interface.

   // The IProjectMidi interface is used to allow polymorphic access

   // to each assembly.

   // It is the mother of all ProjectMIDI APIs.

   public interface IProjectMidi
   {
      IProjectMidiParent ProjectMidiParent { set; }
      void PerformStartProcessing( StartPhase phase );
   }

   public enum StartPhase {
      AfterLoading,           // After assembly is loaded

      AllAssembliesLoaded,    // After all assemblies have been loaded

      StartConnecting,        // Connections are starting to be connected

      FirstTimeEver,          // Only called the first time the assembly

                              // is loaded

      AllAssembliesConnected, // After all assemblies have been loaded

                              // and connections made

      InitDone,               // All initialization has completed

      Terminating             // ProjectMIDI is beginning to exit

    };

ProjectMIDI 提供以下接口,以协助程序集执行启动序列和与其他程序集连接

   public interface IProjectMidiParent : IProjectMidi
   {
      // The directory where all ProjectMIDI folders are placed.

      string ProjectMidiPath { get; }

      // The registry key for all other ProjectMIDI subkeys.

      RegistryKey ProjectMidiKey { get; }

      // Collection of all assemblies

      IIProjectMidiCollection IProjectMidis { get; }

     // This method is used by an assembly to manually create a connection

     // This should only be done the first time the assembly is loaded.

     void CreateAConnection(string eventAsmName, string eventName,
         string actionAsmName, string actionName,
         string connType, string connIntData,
         string connEnabled, string connFollowsSeparator,
         string connStringData);
   }

此接口在每个程序集加载后立即传递给其 ProjectMidiParent 属性。

ProjectMidiPath 指示 ProjectMIDI 根文件夹的文件路径。ProjectMIDI 程序集创建和使用的任何文件夹都应在此文件夹下创建。

同样,任何创建和使用的注册表信息都应位于 ProjectMidiKey 下。

IProjectMidis 提供了一个标准的 IProjectMidi 接口指针集合,允许访问所有其他已加载的程序集。请注意,其他程序集可能在构造函数运行时尚未加载。为确保其他程序集已加载,请等待 PerformStartProcessing 被调用,并将 phase 参数设置为 AllAssembliesLoaded

CreateAConnection 方法由程序集用于创建连接。这通常仅在首次加载时完成。连接由 Connections 程序集持久化。

SongSet 程序集

此程序集管理歌曲集。其他程序集可以连接到此程序集,以控制或接收有关当前歌曲集、歌曲编号或音色更改的通知。

ProjectMIDI 歌曲参数持久化

大多数程序集需要持久化与每首歌曲相关的设置。SongSet 程序集提供了一组可用于执行此操作的持久化方法。

为了使用 ISongSet 接口,程序集必须等到所有程序集都加载完毕,然后搜索程序集列表,查找实现 ISongSet 接口的程序集。您可以在 PDF.cs 文件中找到一个示例。PerformStartProcessing 被调用,当传入 AllAssembliesLoaded 参数时,它反过来调用 AllAssembliesLoaded() 方法。此方法然后搜索 IProjectMidis 集合,查找实现 ISongSet 的程序集。

ISongSet 接口可用于确定当前歌曲、页面和音色。它还提供了保存和恢复自定义歌曲参数的方法。这些参数将由 SongSet 程序集保存在 songdata.xml 文件中。

   public interface ISongSet
   {
      string    CurrentSongName { get; }
      int       CurrentSongNum { get; set; }
      int       CurrentPageNum { get; set; }
      int       CurrentPatchNum { get; set; }

      // These next methods provide persistence of song related parameters.

      // Assemblies can use these to persist per-song data

      string    GetSongParameter( string name, string defaultdata );
      void      SetSongParameter( string name, string data );

      ISongCollection Songs { get; }

        // Note: the following methods are placeholders at this time.

//    string    GetPageParameter( string name, string defaultdata );

//    void      SetPageParameter( string name, string data );

//    string    GetPatchParameter( string name, string defaultdata );

//    void      SetPatchParameter( string name, string data );

   }

一旦您获得了 ISongSet 接口指针,就可以使用它来调用 SetSongParameter() GetSongParameter() 方法。

由于所有程序集都可以使用持久化方法,因此请选择名称参数,使其不会与其他程序集的参数冲突。可以通过使用程序集名称作为参数名称的一部分来完成此操作。

连接程序集

Connections 程序集提供程序集事件和事件处理程序(动作)之间连接的后期绑定。

反射用于识别用于此目的的事件和动作。

ProjectMidi 事件

程序集内部发生的事件可以通过赋予它们 [ProjectMidiEventAttribute] 属性来暴露给其他程序集。此属性通知 ProjectMIDI 此事件可以连接到“ProjectMidi 动作”。此事件必须符合以下签名

   public delegate void ProjectMidiEventHandler(object sender, EventArgs e);

   public event ProjectMidiEventHandler EventName;

有关 ProjectMIDI 中可能使用的派生自 EventArgs 的类的定义,请参阅 ProjectMidiInterfaces.cs 文件。

ProjectMidiEventAttribute

此属性将事件标识为 ProjectMIDI 事件。它可以选择指定以下参数

  • 名称

    为事件命名。此名称将显示在“Connections”对话框中。

  • 值数量

    指定此事件可以生成的不同值的数量。对于菜单项,这将是 1。对于设备滑块,这可以是 128。

  • 自动连接名称

    ProjectMIDI 首次加载程序集时,它将搜索具有匹配“自动连接”名称的事件和动作,并自动连接它们。

  • 连接类型

    这标识了连接的“类型”。此信息由 ProjectMIDI 内部使用。对于大多数连接,这应该为 ConnectionType.Normal

  • 工具提示字符串

    当鼠标悬停在此事件上时,此字符串将显示在“Connections 对话框”中。

动态事件

有些事件可能需要动态创建。例如,MIDI 输入端口事件将根据安装的特定 MIDI 硬件创建。

需要实现“动态事件”的类必须实现 IProjectMidiDynamicEvent 接口。

要创建动态事件,请使用 IProjectMidiConnection 接口将新的 PMEventInfo 对象添加到 IProjectMidiConnection.AllEvents 集合中。

请参阅 MidiPort.cs 中的 IProjectMidiDynamicEvent 代码。

ProjectMidi 动作

程序集内部实现的动作通过赋予它们 [ProjectMidiActionAttribute] 属性来暴露给其他程序集。此属性通知 ProjectMIDI 可以将 ProjectMidi 事件连接到它们。这些动作必须符合以下签名

   public void HandlerName(object sender, EventArgs e);

如您所见,此签名与上面列出的 ProjectMidiEventHandler 委托签名匹配。

请参阅示例源代码以获取实际代码列表和注释。

动态动作

有些动作可能需要动态创建。例如,MIDI 输出端口动作将根据安装的特定 MIDI 硬件创建。

需要实现“动态动作”的类必须实现 IProjectMidiDynamicActions 接口。

要创建动态动作,请使用 IProjectMidiConnection 接口将新的 PMActionInfo 对象添加到 IProjectMidiConnection.AllActions 集合中。

请参阅 MidiPort.cs 中的 IProjectMidiDynamicAction 代码。

自动连接

有些连接需要在 ProjectMIDI 启动时自动连接。例如,将跟踪消息源连接到跟踪消息程序集,然后该程序集显示这些消息。这通过在事件和动作的属性中指定一个公共连接名称来实现。

ProjectMIDI 首次加载程序集时,它将搜索指定相同“自动连接”名称的事件和动作。找到后,它们将自动连接。

现有连接将保存到 connections.xml。当 ProjectMIDI 启动时,它将加载 connections.xml 并重新连接之前连接的事件和动作。

子菜单程序集

此程序集实现了多级上下文菜单。一个动作被暴露出来,可以连接到程序集的菜单事件。

MIDI 程序集

MIDI 程序集提供与系统上存在的 MIDI 端口的连接。它打开所有 MIDI 端口并动态地为每个端口创建事件和动作。

GMSynth 程序集

此程序集为通用 MIDI 合成器提供支持。它与 songset 程序集的 ISongSet 接口连接,为每首选定歌曲提供程序更改。

此程序集是创建您自己的 MIDI 设备程序集的良好起点。

PDF 程序集

此程序集与 Adobe Acrobat 交互,根据当前选定的歌曲和页面显示 PDF 文件。

TIFF 程序集

此程序集与 PDF 程序集类似。它根据当前选定的歌曲和页面显示 TIFF 文件。

示例程序集

此程序集作为如何公开事件和动作的示例提供。它是编写您自己的 ProjectMIDI 程序集的良好起点。

TD8 程序集

此程序集与 Roland TD8 鼓模块接口。它允许为每首歌曲和页面指定鼓垫音色。

这个模块相当大。我不建议用它来创建您自己的程序集。不过,它确实提供了一个如何生成系统独占消息的示例。

XP30 程序集

此程序集与 Roland XP30 MIDI 键盘接口。它根据当前选定的歌曲选择 XP30 音色。

墨迹程序集

此程序集使用并需要 Microsoft 平板电脑 SDK。它将自身连接到 PDF 或 TIFF 程序集以“收集墨迹”。它允许在显示的 PDF 或 TIFF 上绘制笔记。然后,墨迹将与与当前选定的歌曲和页面关联的 PDF 或 TIFF 一起显示。

它会搜索所有程序集,寻找实现 IHasDisplaySurfaces 接口的程序集。找到后,它将使用此接口挂钩其 OnDisplayResize 事件并获取其显示句柄,以供 Microsoft Table PC SDK InkOverlay 对象使用。

构建和运行代码

如果您不重新排列文件夹,构建代码应该非常简单。如果您这样做,构建可能会有点棘手,因为存在多个可执行文件,它们之间存在一些相互依赖关系。这些依赖关系如下:

  • 所有程序集都派生自 ProjectMidiInterfaces.dll 中定义的 IProjectMidi。如果您重新排列各个目录的位置,此引用可能会失效。如果发生这种情况,您需要更正对 ProjectMidiInterfaces.dll 的引用才能解决此问题。
  • MP3 需要 Quartz 库:这应该包含在 Windows XP 中
  • 墨迹需要安装 Microsoft Tablet PC SDK:这可以从 Microsoft MSDN 网站获取。

下载并解压文件后,打开 ProjectMidiAll.slnProjectMidiCore.sln 文件。这将启动 Visual Studio .NET 并显示包含所有或仅所需项目文件的解决方案。我建议您复制 ProjectMidiAll.sln 文件,并从中删除您不需要的项目。

请注意,您可能不需要包含和构建每个项目。只包含适用于您系统的项目。

项目名称 创建的可执行文件 描述 注释
ProjectMIDI ProjectMidi.exe 主可执行文件 必需
连接 Connections.dll 管理程序集之间的连接 必需
GMSynth GMSynth.dll 示例 MIDI 设备程序集 包括用于示例目的,或用于与通用 MIDI 设备接口
墨迹 Ink.dll 添加在显示的 PDF 或 TIFF 上涂写笔记的功能。 如果您有平板电脑或数字化仪,并且已安装 MS 平板电脑 SDK,则包括此项。
MIDI Midi.dll 提供与 MIDI 端口的通信。 如果使用 MIDI,则需要
MP3 MP3.dll 提供 MP3 播放功能 如果需要 MP3 播放,请包含此项。需要 Quartzlib。
PDF PDF.dll 提供 PDF 显示功能 需要安装完整版的 Acrobat。
ProjectMidiInterfaces ProjectMidiInterfaces.dll 提供几个关键接口实现 必需。大多数其他 DLL 都使用
SampleAssembly SampleAssembly.dll 这是一个示例程序集,您可以用来重命名并启动您自己的程序集 可选
歌曲集 SongSet.dll 提供歌曲集、歌曲和音色功能。 必需
子菜单 SubMenu.dll 提供可自定义菜单功能。 必需
TD8 TD8.dll 提供与 Roland TD8 MIDI 鼓设备的接口 如果您拥有 Roland TD8 鼓模块,请包含此项
TIFF TIFF.dll 提供 .tif 显示功能。这作为 PDF 的替代方案提供 如果您未安装 PDF,则包含此项
TraceWindow TraceWindow.dll 提供一个窗口,显示来自 ProjectMIDI.exe 和其他程序集的跟踪消息。 可选
us428 us428.dll 提供与 Tascam US-428 控制界面的接口 如果您拥有 Tascam US-428 控制界面,请包含此项
VBAssembly VBAssembly.dll 这是一个 VB 示例程序集 如果您打算在 VB 中工作,请作为示例包含
XP30 XP30.dll 提供与 Roland XP30 MIDI 键盘的接口 如果您拥有 Roland XP30 键盘,请包含此项

首次运行代码

在运行 ProjectMIDI 之前,您需要将所有创建的程序集 (.DLL) 复制到 Assemblies 文件夹中。我已设置了一个构建后批处理文件,以自动将这些文件复制到 Runtime/Assemblies 文件夹。如果您移动此文件夹,则需要更新每个批处理文件,或者在启动 ProjectMidi.exe 之前手动复制文件。

ProjectMIDI.exe 可执行文件首次运行时,它将搜索其环境变量。特别是,它需要知道 FoldersPath。如果未找到,它将提示用户输入此路径。如果使用完整安装程序,则会创建此路径。如果您从头开始构建代码而未运行安装程序,则需要创建这些文件夹并将文件复制到其中。请务必将所有创建的 .DLL 复制到 /Assemblies 文件夹。当 ProjectMIDI.exe 首次运行时,它会询问 ProjectMidi 文件夹的位置。选择包含所有这些其他文件夹的文件夹。此变量指向包含以下文件夹的路径

文件夹名称 文件夹内容 由程序集使用
Assemblies 所有 ProjectMIDI 程序集 DLL ProjectMIDI.exe
墨迹 平板电脑墨迹文件 Ink.dll
PDFs 所有 PDF 文件 PDF.dll
Sets 所有 .set 歌曲集文件 SongSet.dll
TD8 所有 .td8 鼓音色文件 TD8.dll
TIFFs 所有 .tif 文件 TIFF.dll

您需要哪些文件夹将取决于您系统中包含哪些 DLL。您可能不希望同时包含 PDF 和 TIFF。如果您的系统上安装了 Acrobat,请选择 PDF,否则使用 TIFF。

同样,如果您有平板电脑并安装了 Table PC SDK,请包含 InkInk.dll

关注点

在这个项目中,我学到了很多关于 .NET 可执行文件的知识。不过我认为这是值得的。我创建的平台允许非常快速地创建 MIDI 小程序,我将利用这些小程序充分利用我现有和未来的 MIDI 硬件的能力。

历史

日期 描述
2006 年 1 月 8 日 初步文档创建,使用 www.ProjectMIDI.com 页面的组合内容
© . All rights reserved.