1

我正在开发一个自动转录钢琴音乐(单声道)的项目。我想创建一个 MATLAB GUI,它可以显示转录音乐的乐谱。但是我不太确定如何在 MATLAB GUI 上设计 Grand Staff。这是我第一次使用 GUI,真的很想得到一些帮助。我遇到了这个链接,并且想要类似的东西,唯一的事情是我将加载一个 .wav 文件而不是手动提供旋律。 http://www.pgea.unb.br/~mylene/PSMM/DSPFIRST/chapters/9specta/demos/musicgui/index.htm

我正在使用 MATLAB R2011a 软件。提前谢谢:)

这叫大参谋

我目前只专注于用谱号显示高音谱号(前 5 行)。

4

1 回答 1

3

我的第一次唠叨

我为音乐 GUI 制作了一个存根,如下所示。

到目前为止的结果:

大员工

我采取的方法如下:

  1. 上网查找(免版税)高音谱号、低音谱号和支撑的 SVG 图像。
  2. 不幸的是,MATLAB 不支持矢量图形。因此,将这些 SVG 转换为相当高分辨率的 PNG。
  3. 在 MATLAB 图形中重新缩放和定位这些图像。

在下面包括我的存根,它显示了我将采取的总体策略。基本上,我会对所有固定的音符、休止符、升号等符号使用相同的方法。为符号查找/创建图像,将其加载到 MATLAB 中,并在需要的位置和时间进行缩放/显示。

当然,你必须有点创意。例如,您不需要 128休息的图像;只需将第 8其余部分复制 3 次,并将每个副本偏移一点。另一个例子:将单个 8 分音符的图像其头部和尾部分开。它的头等于四分音符,只有在同一和弦上的最后一个音符被画出后,它的尾才被画出。

对于绘制非固定符号(想想连线、连接 ≤ 8 分音符组的线),您必须做出决定:

  1. 手动绘制它们。您必须对所有内置的绘图功能line有创意。patch可能相当耗时。
  2. 使用图像,并imtransform与朋友一起发挥创意。好处是结果可能看起来更好,并且可能会花费更少的时间。缺点是这些是图像处理工具箱的一部分,并非所有用户都可以访问。
  3. 真正最好的:检测用户是否有图像处理工具箱(使用ver('images'))。如果是,请使用选项 2。如果不是,请使用选项 1。

另外的选择

另一种选择是使用专门的音乐字体。音乐字体将字符映射到音乐符号。好的字体是可矢量化的,这意味着它们可以任意放大或缩小而不会损失质量。这消除了对许多图像的需求。您只需要担心将正确的字符映射到所需的符号以及字符的位置。

但是,对于和弦和非固定符号之类的东西,您仍然必须使用图像。

存根

但现在,这是我使用的存根:

classdef SheetMusicGui < handle

    properties (Access = private)
        f  % Figure handle
        h  % Axes handle

        % Coordinates of the box
        topLineY    = 0.8;
        bottomLineY = 0.2;

        leftLineX   = 0.1;
        maxX        = 3;
    end

    methods

        function obj = SheetMusicGui(varargin)

            % Initialize figure and axis
            obj.f = figure; clf, hold on
            set(obj.f,...
                'position', [400 400 900 300]);

            obj.h = gca;
            set(obj.h, ...
                'box', 'on',...
                'xtick',[], 'xticklabel',[],...
                'ytick',[], 'yticklabel',[]);

            % Draw the grande staff
            obj.drawGrandeStaff(obj.h);

            % Make sure all measurements work out
            axis([0 3 0 1]);
        end

    end

    methods (Access = private)

        %% The Basics

        function [h] = drawGrandeStaff(obj, h)

            % First bar line
            line([obj.leftLineX obj.leftLineX], [obj.bottomLineY obj.topLineY], 'color', 'k');

            % Brace
            img = imread('brace.png');

            X = size(img,2);    xExtent = 0.068;
            Y = size(img,1);    yExtent = xExtent/X*Y;

            C = imagesc([0.01 0.01+xExtent],[0.8 0.8-yExtent],img, 'parent',obj.h);
            uistack(C, 'bottom'); % At the bottom prevents transparency issues


            % Treble staff
            line(...
                repmat([obj.leftLineX; obj.maxX],1,5), ...
                repmat(linspace(obj.topLineY, obj.topLineY-0.15, 5), 2,1), 'color','k')
            % Treble clef
            obj.drawTrebleClef(obj.leftLineX+0.04, obj.topLineY+0.05);


            % Bass staff
            line(...
                repmat([obj.leftLineX; obj.maxX],1,5),...
                repmat(linspace(obj.bottomLineY, obj.bottomLineY+0.15, 5), 2,1), 'color','k')

            % Bass clef
            obj.drawBassClef(obj.leftLineX+0.04, obj.bottomLineY+0.155);

        end

        % Draw a G clef at location X,Y
        function C = drawTrebleClef(obj, x, y)
            persistent img
            if isempty(img)
                img = imread('GClef.png'); end

            % Scale image
            X = size(img,2);    xExtent = 0.1;
            Y = size(img,1);    yExtent = xExtent/X*Y;

            % Plage image
            C = imagesc([x x+xExtent],[y y-yExtent],img, 'parent',obj.h);
            uistack(C, 'bottom'); % At the bottom prevents transparency issues

        end

        % Draw an F clef at location X,Y
        function C = drawBassClef(obj, x, y)
            persistent img
            if isempty(img)
                img = imread('FClef.png'); end

            % Scale image
            X = size(img,2);    xExtent = 0.12;
            Y = size(img,1);    yExtent = xExtent/X*Y;

            % Plage image
            C = imagesc([x x+xExtent],[y y-yExtent],img, 'parent',obj.h);
            uistack(C, 'bottom'); % At the bottom prevents transparency issues

        end

        function T = drawTime(obj, varargin)

            % TODO

            % NOTE: you had best use some pre-defined times, like common time,
            % 2/2, 3/4, 6/8, etc. It looks much nicer. Only use text() when a
            % non-common time is encountered.
        end

        function K = drawKey(obj, varargin)
            % TODO
            % NOTE: use sharp/flat below
        end

        %% Sharps, flats

        function T = drawSharp(obj, varargin)
            % TODO
        end

        function T = drawDoubleSharp(obj, varargin)
            % TODO
        end

        function T = drawFlat(obj, varargin)
            % TODO
        end

        function T = drawDoubleFlat(obj, varargin)
            % TODO
        end

        function T = drawNatural(obj, varargin)
            % TODO
        end

        %% Bars

        function B = drawBar(obj, varargin)
            % TODO
        end

        function R = drawBeginRepeat(obj, varargin)
            % TODO
        end

        function R = drawEndRepeat(obj, varargin)
            % TODO
        end

        %% Pedalling

        function P = drawBeginPedal(obj, varargin)
            % TODO
        end

        function P = drawEndPedal(obj, varargin)
            % TODO
        end

        %% Slurs & lines

        function S = drawSlur(obj, varargin)
            % TODO
            % NOTE: You'll have to do this one by hand
        end

        function P = drawGlissando(obj, varargin)
            % TODO
        end

        %% Multi-measure rest

        function R = drawMultiMeasureRest(obj, varargin)
            % TODO
        end


        %% Whole note/rest

        function N = drawWholeNote(obj, pitch, varargin)

            % TODO

            % Possibly transform note
            N = obj.transformNote(N, varargin{:});
        end

        function R = drawWholeRest(obj, varargin)

            % TODO

            % Possibly transform rest
            N = obj.transformNote(N, varargin{:});
        end


        %% Half note/rest

        function N = drawHalfNote(obj, varargin)

            % TODO

            % Possibly transform note
            N = obj.transformNote(N, varargin{:});
        end

        function R = drawHalfRest(obj, varargin)

            % TODO

            % Possibly transform rest
            N = obj.transformNote(N, varargin{:});
        end


        %% Quarter note/rest

        function N = drawQuarterNote(obj, varargin)

            % TODO

            % Possibly transform note
            N = obj.transformNote(N, varargin{:});
        end

        function R = drawQuarterRest(obj, varargin)

            % TODO

            % Possibly transform rest
            N = obj.transformNote(N, varargin{:});
        end

        %% 8th, 16th, 32nd, 64th, ...

        function N = drawSingleShortNote(obj, type, varargin)

            % TODO

            % NOTE: all short notes have a different number of tails. Just store
            % the tail as a separate figure, and copy however many times needed.
            % Use the quarter note for the head.

            % Possibly transform rest
            N = obj.transformNote(N, varargin{:});
        end

        function R = drawShortRest(obj, type, varargin)

            % TODO

            % NOTE: all short rests are just copies of the eighth rest, so you can
            % juse load one image and copy the desired number of times.

            % Possibly transform rest
            N = obj.transformNote(N, varargin{:});
        end


        function N = drawShortNoteGroup(obj, types, varargin)

            % TODO

            % NOTE: Use the quarter note for all the heads. Draw however many
            % lines (with "line" command) where needed. Top line should be
            % "fatter"; you can do this by adjusting the "linewidth" property

            % Possibly transform one or more members of the group
            N = obj.transformNote(N, varargin{:});
        end


        %% Note/Rest transformations
        % (dots, accents, inversion, decoration, etc.)

        function N = transformNote(obj, N, varargin)

            parameters = varargin(1:2:end);
            values     = varargin(2:2:end);

            if mod(nargin,2)~=0 || ...
                    ~all(cellfun('isclass', parameters), 'char') || ...
                    ~all(cellfun('isclass', values), 'char')
                error('transformNotes:no_pv_pairs',...
                    'Transforming notes is done by all-text parameter/value pairs.'); 
            end

            if numel(parameters)==0
                return; end

            for ii = 1:numel(parameters)

                parameter = lower(parameters{ii});
                value     = lower(values{ii});

                switch parameter

                    % Note may be flipped
                    case 'orientation'
                        switch value
                            case {'upright' 'normal'}
                                % No action 
                            case {'flip', 'flipped', 'upside down'} 
                                N = flipdim(N,1);
                            otherwise
                                % error
                        end

                    % Duration of note may be extended 
                    case {'extend' 'extension'}
                        switch value
                            case {'single' 'dot'}
                            case {'double' 'dotdot' 'dot dot' 'ddot'}
                            case {'triple' 'dotdotdot' 'dot dot dot' 'dddot'}
                            otherwise
                                % error
                        end


                    % Note may be accented
                    case {'accent' 'accented'}
                        switch value
                            case 'portato'
                            case 'staccato'
                            case 'staccatissimo'
                            case 'legato'
                            case 'marcato'
                            case 'marcatissimo'
                            case 'tenuto'
                            otherwise
                                % error
                        end


                    % Note may be decorated
                    case {'decoration' 'decorated'}
                        switch value
                            case {'thril' 'thriller'}
                            case {'pralthril' 'pralthriller' 'praller'}
                            case 'mordent'
                            case 'arpeggio'
                            case 'gruppetto'
                            case 'glissando'
                            case 'portamento'
                            case 'schleifer'
                            case {'grace note' 'appoggiatura'}
                            case {'striped grace note' 'acciaccatura'}
                            otherwise
                                % error
                        end

                    otherwise
                        warning('transformNotes:unsupported_parameter',...
                            'Unknown parameter: ''%s''. Ignoring...', parameter);
                end
            end

        end % transformNote

    end % Private methods

end % Class definition

而且,您可以按原样运行它,将这些图像另存为GClef.pngFClef.pngbrace.png与类定义在同一目录中:

于 2013-11-14T09:28:02.623 回答