MIDI::Pitch - Converts MIDI pitches, note names and frequencies into each other


MIDI-Pitch documentation Contained in the MIDI-Pitch distribution.

Index


Code Index:

NAME

Top

MIDI::Pitch - Converts MIDI pitches, note names and frequencies into each other

SYNOPSIS

Top

  use MIDI::Pitch qw(name2pitch pitch2name freq2pitch pitch2freq basefreq);

  my $pitch = name2pitch($name);

  


DESCRIPTION

Top

This module converts MIDI pitches between 0 and 127 (called 'note numbers' in the MIDI standard) and note names into each other. The octave numbers are based on the table found in the MIDI standard (see http://www.harmony-central.com/MIDI/Doc/table2.html):

    The MIDI specification only defines note number 60 as "Middle C", and
    all other notes are relative. The absolute octave number designations
    shown here are based on Middle C = C4, which is an arbitrary
    assignment.

The note names are C, C#/Db, D, ..., followed by an octave number from -1 to 9. Thus, the valid notes range between C-1 and G9.

FUNCTIONS

Top

name2pitch

  my $pitch = name2pitch($name);

Converts a note name into a pitch.

pitch2name

  my $name = pitch2name($pitch);

Converts a pitch between 0 and 127 into a note name. pitch2name returns the lowercase version with a sharp, if necessary (e.g. it will return 'g#', not 'Ab').

freq2pitch

  my $pitch = freq2pitch($440);

Converts a frequency >= 0 Hz to a pitch, using the base frequency set.

pitch2freq

  my $freq = pitch2freq(69);

Converts a pitch to a frequency, using the base frequency set.

name2freq

    my $freq = name2freq('c2');

This is just an alias for pitch2freq(name2pitch($x)).

freq2name

    my $name = freq2name('c2');

This is just an alias for pitch2name(freq2pitch($x)).

findsemitone {

    my $pitch = findsemitone('d#', 60);

Finds the nearest pitch that expresses the semitone given around the pitch given. The example above would return 63, since the d# at pitch 63 is nearer to 60 than the d# at pitch 51.

The semitone can be specified in the same format as a note name (without the octave) or as an integer between 0 and 11.

If there are two possibilities for the nearest pitch, findsemitone returns the lower one.

basefreq

  my $basefreq = basefreq;
  basefreq(432);

Sets/returns current base frequency for frequency/pitch conversion. The standard base frequency set is 440 (Hz). Note that the base frequency does not affect the pitch/name conversion.

HISTORY

Top

0.7

Added Changes file.

0.6

findsemitone now also understands semitones specified as integers between 0 and 11. Fixed bug in findsemitone.

0.5

Added findsemitone function

0.2

Added pitch rounding (60.49 and 59.5 will both be considered 60/'C4').

Added frequency/pitch conversion.

Added POD tests.

0.1

Original version; created by h2xs 1.22 with options

  -A -C -X -n MIDI::Pitch -v 0.1 -b 5.5.3

SEE ALSO

Top

MIDI. MIDI::Tools.

http://www.harmony-central.com/MIDI/Doc/table2.html

AUTHOR

Top

Christian Renz, <crenz @ web42.com>

COPYRIGHT AND LICENSE

Top


MIDI-Pitch documentation Contained in the MIDI-Pitch distribution.
package MIDI::Pitch;

use 5.00503;
use strict;

require Exporter;
use vars qw($VERSION @ISA @EXPORT_OK
  %name2pitch_lut @pitch2name_table $base_freq);

@ISA       = qw(Exporter);
@EXPORT_OK =
  qw(name2pitch pitch2name freq2pitch pitch2freq basefreq name2freq freq2name findsemitone);
$VERSION = '0.7';

$base_freq = 440;

%name2pitch_lut = (
    'b#' => 0,
    c    => 0,
    'c#' => 1,
    'db' => 1,
    d    => 2,
    'd#' => 3,
    'eb' => 3,
    e    => 4,
    'fb' => 4,
    'e#' => 5,
    f    => 5,
    'f#' => 6,
    'gb' => 6,
    g    => 7,
    'g#' => 8,
    'ab' => 8,
    a    => 9,
    'a#' => 10,
    'bb' => 10,
    b    => 11,
    'cb' => 11);

sub name2pitch {
    my $n = shift;

    return undef unless defined $n && lc($n) =~ /^([a-g][b#]?)(-?\d\d?)$/;

    my $p = $name2pitch_lut{$1} + ($2 + 1) * 12;
    return undef unless $p >= 0 && $p <= 127;
    return $p;
}

@pitch2name_table =
  ('c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'b');

sub pitch2name {
    my $p = shift;

    return undef unless defined $p && $p =~ /^-?(\d+|\d*(\.\d+))$/;
    $p = int($p + .5 * ($p <=> 0));
    return undef unless $p >= 0 && $p <= 127;

    return $pitch2name_table[$p % 12] . (int($p / 12) - 1);
}

sub freq2pitch {
    my $f = shift;

    return undef unless defined $f && $f =~ /^(\d+|\d*(\.\d+))$/ && $f > 0;
    return 69 + 12 * log($f / $base_freq) / log(2);
}

sub pitch2freq {
    my $p = shift;

    return undef unless defined $p && $p =~ /^-?(\d+|\d*(\.\d+))$/;
    return exp((($p - 69) / 12) * log(2)) * $base_freq;
}

sub name2freq {
    return pitch2freq(name2pitch(@_));
}

sub freq2name {
    return pitch2name(freq2pitch(@_));
}

sub findsemitone {
    my ($semitone, $pitch) = @_;

    return undef unless defined $semitone &&
      (($semitone =~ /^\d+$/
      && $semitone >= 0
      && $semitone <= 11) || exists $name2pitch_lut{$semitone});
    return undef
      unless defined $pitch
      && $pitch =~ /^\d+$/
      && $pitch >= 0
      && $pitch <= 127;

    $semitone = $name2pitch_lut{$semitone} if exists $name2pitch_lut{$semitone};

    my $m = $pitch % 12;
    my $result = $pitch - $m + $semitone;
    $result += 12 if ($pitch - $result > 6 && $result < 116);
    $result -= 12 if ($result - $pitch > 6 && $result > 11);

    return $result;
}

sub basefreq {
    my $f = shift;

    $base_freq = $f if defined $f && $f > 0;
    return $base_freq;
}

1;