{
    "content": [
        {
            "type": "text",
            "text": "# MIDI::Opus (perldoc)\n\n## NAME\n\nMIDI::Opus -- functions and methods for MIDI opuses\n\n## SYNOPSIS\n\nuse MIDI; # uses MIDI::Opus et al\nforeach $one (@ARGV) {\nmy $opus = MIDI::Opus->new({ 'fromfile' => $one, 'noparse' => 1 });\nprint \"$one has \", scalar( $opus->tracks ) \" tracks\\n\";\n}\nexit;\n\n## DESCRIPTION\n\nMIDI::Opus provides a constructor and methods for objects representing a MIDI opus (AKA \"song\").\nIt is part of the MIDI suite.\n\n## Sections\n\n- **NAME**\n- **SYNOPSIS**\n- **DESCRIPTION**\n- **CONSTRUCTOR AND METHODS**\n- **NOTE ON TICKS**\n- **NOTE ON WARN-ING AND DIE-ING**\n- **COPYRIGHT**\n- **AUTHORS**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "MIDI::Opus",
        "section": "",
        "mode": "perldoc",
        "summary": "MIDI::Opus -- functions and methods for MIDI opuses",
        "synopsis": "use MIDI; # uses MIDI::Opus et al\nforeach $one (@ARGV) {\nmy $opus = MIDI::Opus->new({ 'fromfile' => $one, 'noparse' => 1 });\nprint \"$one has \", scalar( $opus->tracks ) \" tracks\\n\";\n}\nexit;",
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "SYNOPSIS",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 12,
                "subsections": []
            },
            {
                "name": "CONSTRUCTOR AND METHODS",
                "lines": 156,
                "subsections": []
            },
            {
                "name": "NOTE ON TICKS",
                "lines": 12,
                "subsections": []
            },
            {
                "name": "NOTE ON WARN-ING AND DIE-ING",
                "lines": 9,
                "subsections": []
            },
            {
                "name": "COPYRIGHT",
                "lines": 5,
                "subsections": []
            },
            {
                "name": "AUTHORS",
                "lines": 4,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "MIDI::Opus -- functions and methods for MIDI opuses\n",
                "subsections": []
            },
            "SYNOPSIS": {
                "content": "use MIDI; # uses MIDI::Opus et al\nforeach $one (@ARGV) {\nmy $opus = MIDI::Opus->new({ 'fromfile' => $one, 'noparse' => 1 });\nprint \"$one has \", scalar( $opus->tracks ) \" tracks\\n\";\n}\nexit;\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "MIDI::Opus provides a constructor and methods for objects representing a MIDI opus (AKA \"song\").\nIt is part of the MIDI suite.\n\nAn opus object has three attributes: a format (0 for MIDI Format 0), a tick parameter (parameter\n\"division\" in MIDI::Filespec), and a list of tracks objects that are the real content of that\nopus.\n\nBe aware that options specified for the encoding or decoding of an opus may not be documented in\n*this* module's documentation, as they may be (and, in fact, generally are) options just passed\ndown to the decoder/encoder in MIDI::Event -- so see MIDI::Event for an explanation of most of\nthem, actually.\n",
                "subsections": []
            },
            "CONSTRUCTOR AND METHODS": {
                "content": "MIDI::Opus provides...\n\nthe constructor MIDI::Opus->new({ ...options... })\nThis returns a new opus object. The options, which are optional, is an anonymous hash. By\ndefault, you get a new format-0 opus with no tracks and a tick parameter of 96. There are\nsix recognized options: \"format\", to set the MIDI format number (generally either 0 or 1) of\nthe new object; \"ticks\", to set its ticks parameter; \"tracks\", which sets the tracks of the\nnew opus to the contents of the list-reference provided; \"tracksr\", which is an exact\nsynonym of \"tracks\"; \"fromfile\", which reads the opus from the given filespec; and\n\"fromhandle\", which reads the opus from the the given filehandle reference (e.g.,\n*STDIN{IO}), after having called binmode() on that handle, if that's a problem.\n\nIf you specify either \"fromfile\" or \"fromhandle\", you probably don't want to specify any\nof the other options -- altho you may well want to specify options that'll get passed down\nto the decoder in MIDI::Events, such as 'include' => ['sysexf0', 'sysexf7'], just for\nexample.\n\nFinally, the option \"noparse\" can be used in conjunction with either \"fromfile\" or\n\"fromhandle\", and, if true, will block MTrk tracks' data from being parsed into MIDI\nevents, and will leave them as track data (i.e., what you get from $track->data). This is\nuseful if you are just moving tracks around across files (or just counting them in files, as\nin the code in the Synopsis, above), without having to deal with any of the events in them.\n(Actually, this option is implemented in code in MIDI::Track, but in a routine there that\nI've left undocumented, as you should access it only thru here.)\n\nthe method $newopus = $opus->copy\nThis duplicates the contents of the given opus, and returns the duplicate. If you are\nunclear on why you may need this function, read the documentation for the \"copy\" method in\nMIDI::Track.\n\nthe method $opus->tracks( @tracks )\nReturns the list of tracks in the opus, possibly after having set it to @tracks, if\nspecified and not empty. (If you happen to want to set the list of tracks to an empty list,\nfor whatever reason, you have to use \"$opus->tracksr([])\".)\n\nIn other words: $opus->tracks(@tracks) is how to set the list of tracks (assuming @tracks is\nnot empty), and @tracks = $opus->tracks is how to read the list of tracks.\n\nthe method $opus->tracksr( $tracksr )\nReturns a reference to the list of tracks in the opus, possibly after having set it to\n$tracksr, if specified. \"$tracksr\" can actually be any listref, whether it comes from a\nscalar as in $sometracksr, or from something like \"[@tracks]\", or just plain old\n\"\\@tracks\"\n\nOriginally $opus->tracks was the only way to deal with tracks, but I added $opus->tracksr\nto make possible 1) setting the list of tracks to (), for whatever that's worth, 2) parallel\nstructure between MIDI::Opus::tracks[r] and MIDI::Tracks::events[r] and 3) so you can\ndirectly manipulate the opus's tracks, without having to *copy* the list of tracks back and\nforth. This way, you can say:\n\n$tracksr = $opus->tracksr();\n@somestuff = splice(@$tracksr, 4, 6);\n\nBut if you don't know how to deal with listrefs like that, that's OK, just use\n$opus->tracks.\n\nthe method $opus->ticks( $tickparameter )\nReturns the tick parameter from $opus, after having set it to $tickparameter, if provided.\n\nthe method $opus->format( $format )\nReturns the MIDI format for $opus, after having set it to $format, if provided.\n\nthe method $newopus = $opus->quantize\nThis grid quantizes an opus. It simply calls MIDI::Score::quantize on every track. See docs\nfor MIDI::Score::quantize. Original opus is destroyed, use MIDI::Opus::copy if you want to\ntake a copy first.\n\nthe method $opus->dump( { ...options...} )\nDumps the opus object as a bunch of text, for your perusal. Options include: \"flat\", if\ntrue, will have each event in the opus as a tab-delimited line -- or as delimited with\nwhatever you specify with option \"delimiter\"; *otherwise*, dump the data as Perl code that,\nif run, would/should reproduce the opus. For concision's sake, the track data isn't dumped,\nunless you specify the option \"dumptracks\" as true.\n\nthe method $opus->writetofile('filespec', { ...options...} )\nWrites $opus as a MIDI file named by the given filespec. The options hash is optional, and\nwhatever you specify as options percolates down to the calls to MIDI::Event::encode -- which\nsee. Currently this just opens the file, calls $opus->writetohandle on the resulting\nfilehandle, and closes the file.\n\nthe method $opus->writetohandle(IOREF, { ...options...} )\nWrites $opus as a MIDI file to the IO handle you pass a reference to (example: *STDOUT{IO}).\nThe options hash is optional, and whatever you specify as options percolates down to the\ncalls to MIDI::Event::encode -- which see. Note that this is probably not what you'd want\nfor sending music to \"/dev/sequencer\", since MIDI files are not MIDI-on-the-wire.\n\nthe method $opus->draw({ ...options...})\nThis currently experimental method returns a new GD image object that's a graphic\nrepresentation of the notes in the given opus. Options include: \"width\" -- the width of the\nimage in pixels (defaults to 600); \"bgcolor\" -- a six-digit hex RGB representation of the\nbackground color for the image (defaults to $MIDI::Opus::BGcolor, currently '000000');\n\"channelcolors\" -- a reference to a list of colors (in six-digit hex RGB) to use for\nrepresenting notes on given channels. Defaults to @MIDI::Opus::Channelcolors. This list is\na list of pairs of colors, such that: the first of a pair (color N*2) is the color for the\nfirst pixel in a note on channel N; and the second (color N*2 + 1) is the color for the\nremaining pixels of that note. If you specify only enough colors for channels 0 to M, notes\non a channels above M will use 'recycled' colors -- they will be plotted with the color for\nchannel \"channelnumber % M\" (where \"%\" = the MOD operator).\n\nThis means that if you specify\n\nchannelcolors => ['00ffff','0000ff']\n\nthen all the channels' notes will be plotted with an aqua pixel followed by blue ones; and\nif you specify\n\nchannelcolors => ['00ffff','0000ff', 'ff00ff','ff0000']\n\nthen all the *even* channels' notes will be plotted with an aqua pixel followed by blue\nones, and all the *odd* channels' notes will be plotted with a purple pixel followed by red\nones.\n\nAs to what to do with the object you get back, you probably want something like:\n\n$im = $chachacha->draw;\nopen(OUT, \">$gifout\"); binmode(OUT);\nprint OUT $im->gif;\nclose(OUT);\n\nUsing this method will cause a \"die\" if it can't successfully \"use GD\".\n\nI emphasise that \"draw\" is expermental, and, in any case, is only meant to be a crude hack.\nNotably, it does not address well some basic problems: neither volume nor patch-selection\n(nor any notable aspects of the patch selected) are represented; pitch-wheel changes are not\nrepresented; percussion (whether on percussive patches or on channel 10) is not specially\nrepresented, as it probably should be; notes overlapping are not represented at all well.\n\nWHERE'S THE DESTRUCTOR?\nBecause MIDI objects (whether opuses or tracks) do not contain any circular data structures, you\ndon't need to explicitly destroy them in order to deallocate their memory. Consider this code\nsnippet:\n\nuse MIDI;\nforeach $one (@ARGV) {\nmy $opus = MIDI::Opus->new({ 'fromfile' => $one, 'noparse' => 1 });\nprint \"$one has \", scalar( $opus->tracks ) \" tracks\\n\";\n}\n\nAt the end of each iteration of the foreach loop, the variable $opus goes away, along with its\ncontents, a reference to the opus object. Since no other references to it exist (i.e., you\ndidn't do anything like push(@Allopuses,$opus) where @Allopuses is a global), the object is\nautomagically destroyed and its memory marked for recovery.\n\nIf you wanted to explicitly free up the memory used by a given opus object (and its tracks, if\nthose tracks aren't used anywhere else) without having to wait for it to pass out of scope, just\nreplace it with a new empty object:\n\n$opus = MIDI::Opus->new;\n\nor replace it with anything at all -- or even just undef it:\n\nundef $opus;\n\nOf course, in the latter case, you can't then use $opus as an opus object anymore, since it\nisn't one.\n",
                "subsections": []
            },
            "NOTE ON TICKS": {
                "content": "If you want to use \"negative\" values for ticks (so says the spec: \"If division is negative, it\nrepresents the division of a second represented by the delta-times in the file,[...]\"), then\nit's up to you to figure out how to represent that whole ball of wax so that when it gets\n\"pack()\"'d as an \"n\", it comes out right. I think it'll involve something like:\n\n$opus->ticks(  (unpack('C', pack('c', -25)) << 8) & 80  );\n\nfor bit resolution (80) at 25 f/s.\n\nBut I've never tested this. Let me know if you get it working right, OK? If anyone *does* get it\nworking right, and tells me how, I'll try to support it natively.\n",
                "subsections": []
            },
            "NOTE ON WARN-ING AND DIE-ING": {
                "content": "In the case of trying to parse a malformed MIDI file (which is not a common thing, in my\nexperience), this module (or MIDI::Track or MIDI::Event) may warn() or die() (Actually, carp()\nor croak(), but it's all the same in the end). For this reason, you shouldn't use this suite in\na case where the script, well, can't warn or die -- such as, for example, in a CGI that scans\nfor text events in a uploaded MIDI file that may or may not be well-formed. If this *is* the\nkind of task you or someone you know may want to do, let me know and I'll consider some kind of\n'nodie' parameter in future releases. (Or just trap the die in an eval { } around your call to\nanything you think you could die.)\n",
                "subsections": []
            },
            "COPYRIGHT": {
                "content": "Copyright (c) 1998-2002 Sean M. Burke. All rights reserved.\n\nThis library is free software; you can redistribute it and/or modify it under the same terms as\nPerl itself.\n",
                "subsections": []
            },
            "AUTHORS": {
                "content": "Sean M. Burke \"sburke@cpan.org\" (until 2010)\n\nDarrell Conklin \"conklin@cpan.org\" (from 2010)\n",
                "subsections": []
            }
        }
    }
}