unarray: cosmetic fix
[iv.d.git] / opl3test / musplay.d
blob216100e02b81a9eac7576fc6b6ac65fb9904a458
1 // This program is free software; you can redistribute it and/or
2 // modify it under the terms of the GNU General Public License
3 // as published by the Free Software Foundation; either version 2
4 // of the License, or (at your option) any later version.
5 //
6 // This program is distributed in the hope that it will be useful,
7 // but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // GNU General Public License for more details.
10 import iv.cmdcon;
11 import iv.vfs;
12 import iv.vfs.io;
14 import iv.nukedopl3;
15 import xalsa;
18 ////////////////////////////////////////////////////////////////////////////////
19 __gshared OPLPlayer player;
20 __gshared short[4096] smpbuf;
21 __gshared uint smpbufpos;
23 __gshared float amp = 1.0f;
26 void playbuf () {
27 if (smpbufpos == 0) return;
28 foreach (ref short v; smpbuf[0..smpbufpos]) {
29 int n = cast(int)(v*amp);
30 if (n < short.min) n = short.min;
31 if (n > short.max) n = short.max;
32 v = cast(short)n;
34 alsaWriteX(smpbuf.ptr, smpbufpos/2);
35 smpbufpos = 0;
39 void main (string[] args) {
40 bool useOPL3 = true;
41 string filename = null;
42 bool nomore = false;
43 string outwavname = null;
44 bool nextIsWav = false;
45 foreach (string a; args[1..$]) {
46 if (nextIsWav) {
47 if (outwavname !is null) assert(0, "too many output .wav filenames");
48 outwavname = a;
49 nextIsWav = false;
50 continue;
52 if (nomore) {
53 if (filename !is null) assert(0, "too many file names");
54 filename = a;
55 continue;
57 if (a == "--") { nomore = true; continue; }
58 if (a.length == 0) continue;
59 if (a == "-opl2" || a == "--opl2") useOPL3 = false;
60 else if (a == "-opl3" || a == "--opl3") useOPL3 = true;
61 else if (a == "--wav" || a == "-w") nextIsWav = true;
62 else if (a.length > 2 && a[0..2] == "-w") {
63 if (outwavname !is null) assert(0, "too many output .wav filenames");
64 outwavname = a[2..$];
65 } else if (a.length > 2 && a[0..2] == "-a") {
66 import std.conv : to;
67 amp = a[2..$].to!float;
68 } else if (a[0] == '-') assert(0, "invalid option: '"~a~"'");
69 else {
70 if (filename !is null) assert(0, "too many file names");
71 filename = a;
72 continue;
75 player = new OPLPlayer(48000, useOPL3);
76 version(genmidi_dumper) {
77 player.dumpGenMidi(stdout);
78 } else {
79 if (filename.length == 0) assert(0, "file?");
80 auto fl = VFile(filename);
81 uint flen = cast(uint)fl.size;
82 assert(flen > 0);
83 if (outwavname.length == 0) alsaOpen(2);
84 scope(exit) alsaClose();
86 conwriteln("OPL", (useOPL3 ? "3" : "2"), " (amp:", amp, "): ", (outwavname.length ? "writing .wav from" : "playing"), " '", filename, "'...");
87 ubyte[] fdata = new ubyte[](flen);
88 fl.rawReadExact(fdata);
89 if (!player.load(fdata)) assert(0, "cannot load song");
90 delete fdata;
91 player.play();
93 VFile of;
94 long datapos;
95 if (outwavname.length) {
96 of = VFile(outwavname, "w");
97 // write RIFF/WAV header
98 of.rawWriteExact("RIFF");
99 of.writeNum!uint(0); // will be filled later
100 of.rawWriteExact("WAVE");
101 of.rawWriteExact("fmt ");
102 of.writeNum!uint(16);
103 of.writeNum!ushort(1); // pcm
104 of.writeNum!ushort(2); // stereo
105 of.writeNum!uint(48000);
106 of.writeNum!uint(48000*2*2);
107 of.writeNum!ushort(2); // block align
108 of.writeNum!ushort(16); // bits per sample
109 of.rawWriteExact("data");
110 of.writeNum!uint(0); // will be filled later
111 datapos = of.tell;
114 while (player.playing) {
115 smpbufpos = player.generate(smpbuf[])*2;
116 if (smpbufpos == 0) break;
117 if (of.isOpen) {
118 of.rawWriteExact(smpbuf[0..smpbufpos]);
119 } else {
120 playbuf();
123 if (of.isOpen) {
124 // fix header
125 auto fsize = cast(uint)of.size;
126 of.seek(4);
127 of.writeNum!uint(fsize-8);
128 of.seek(datapos-4);
129 of.writeNum!uint(cast(uint)(fsize-datapos));
130 of.close();
131 } else {
132 playbuf();