Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // written 2014-04-29 by tripflag <ed@irc.rizon.net>
- // licensed GPL v2
- //
- // this program takes a .wave file that contains a monophonic single-instrument,
- // playing n notes of t microseconds each followed by t microseconds of silence.
- // the notes are sliced into groups, each group is sliced by the period of the note,
- // and each period is finally averaged together to generate a perfectly-looping and
- // flawless rendition of the soundchip. N output wavefiles for N original notes.
- int seg;
- Seg[] segs;
- Seg[][] segc;
- List<Seg> segso;
- byte[] buffer;
- bool painter;
- bool paintBusy;
- int avg1, avg2;
- int span;
- void t_Tick(object sender, EventArgs e)
- {
- ((Timer)sender).Stop();
- buffer = System.IO.File.ReadAllBytes("tri.wav"); // because 20MB of RAM is nothing today (deal with it)
- paintBusy = false;
- painter = false;
- long last = 0;
- span = 1;
- seg = 0;
- segso = new List<Seg>();
- panel1.BackgroundImage = null;
- panel2.BackgroundImage = null;
- for (long a = 0; a < buffer.Length; a += 2)
- {
- // Get amplitude of sample at offset a
- long v = buffer[a + 1];
- v += v < 0x80 ? 0x80 : -0x80;
- v = v * 256 + buffer[a];
- // check whether sample is in the top half of the waveform,
- // and that the previous sample was in the bottom half
- if (v > 0x8010 && last < 0x7ff0)
- {
- // update current (old) segment with
- // this sample offset as end position
- if (segso.Count > 0)
- {
- segso[segso.Count - 1].end(a);
- }
- // add a new segment starting from this offset
- segso.Add(new Seg(a));
- // update last with current amplitude
- last = v;
- }
- // check whether sample is in the bottom half of the waveform
- if (v < 0x7ff0)
- {
- // update sample amplitude regardless
- last = v;
- }
- }
- // remove 4096 samples at the start of each new note
- for (int a = 0; a < segso.Count; a++)
- {
- //long prev = segso[a - 1].b - segso[a - 1].a;
- long cur = segso[a].b - segso[a].a;
- long next = segso[a].b - segso[a].a;
- if (cur > 40960 &&
- next < 40960)
- {
- a++;
- long sum = 0;
- while (sum < 8192)
- {
- Seg s = segso[a];
- sum += s.b - s.a;
- segso.RemoveAt(a);
- a--;
- }
- }
- }
- // combine short segs so none are shorter than 4096 samples
- List<Seg> rewq = new List<Seg>();
- Seg ts = null;
- for (int a = 0; a < segso.Count; a++)
- {
- if (ts == null)
- {
- //s = segso[a];
- ts = new Seg(segso[a].a);
- ts.b = segso[a].b;
- }
- else if (ts.b - ts.a < 2048)
- {
- ts.b = segso[a].b;
- }
- if (ts.b - ts.a >= 2048)
- {
- rewq.Add(ts);
- ts = null;
- }
- }
- segs = rewq.ToArray();
- // create list of seg arrays, note collection
- List<Seg> fdsa = new List<Seg>();
- List<Seg[]> asdf = new List<Seg[]>();
- for (int a = 0; a < segs.Length - 1; a++)
- {
- //long prev = segso[a - 1].b - segso[a - 1].a;
- long cur = segs[a+0].b - segs[a+0].a;
- long next = segs[a+1].b - segs[a+1].a;
- if (cur > 40960 &&
- next < 8192)
- {
- if (fdsa.Count > 3)
- {
- asdf.Add(fdsa.ToArray());
- }
- fdsa.Clear();
- }
- else if (cur < 8192)
- {
- fdsa.Add(segs[a]);
- }
- }
- asdf.Add(fdsa.ToArray());
- segc = asdf.ToArray();
- // find most popular segment length of each note
- for (int a = 0; a < segc.Length; a++)
- {
- var ddd = segc[a]
- .GroupBy((s) => s.b - s.a)
- .Select((f) => new {
- Len = f.Key,
- Num = segc[a].Count(
- (s2) => (s2.b - s2.a) == f.Key
- )
- })
- .OrderBy((aa) => aa.Num).ToList();
- long len = ddd[ddd.Count - 1].Len / 2;
- ulong[] avg = new ulong[len];
- for (int i = 0; i < len; i++)
- {
- avg[i] = 0;
- }
- ulong avgc = 0;
- for (int i = 0; i < segc[a].Length; i++)
- {
- if (len * 2 == segc[a][i].b - segc[a][i].a)
- {
- long startFrom = segc[a][i].a;
- for (long j = 0; j < len * 2; j += 2)
- {
- long v = buffer[startFrom + j + 1];
- v += v < 0x80 ? 0x80 : -0x80;
- v = v * 256 + buffer[startFrom + j];
- avg[j / 2] += (ulong)v;
- }
- avgc++;
- }
- }
- for (int i = 0; i < len; i++)
- {
- avg[i] = avg[i] / avgc;
- avg[i] = avg[i] < 0x8000 ?
- avg[i] + 0x8000 :
- avg[i] - 0x8000;
- }
- byte[] data = new byte[len * 2 + 44];
- Array.Copy(buffer, data, 44);
- for (var i = 0; i < len; i++)
- {
- data[i * 2 + 44] = (byte)(avg[i] % 256);
- data[i * 2 + 45] = (byte)(avg[i] / 256);
- }
- Array.Copy(BitConverter.GetBytes(data.Length - 8), 0, data, 4, 4);
- Array.Copy(BitConverter.GetBytes(data.Length - 44), 0, data, 40, 4);
- System.IO.File.WriteAllBytes(string.Format("out\\note{0:d2}.wav", a), data);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement