Browse Source

Initial commit.

Wei Mingzhi 11 years ago
parent
commit
f56380d1ef
61 changed files with 29896 additions and 0 deletions
  1. BIN
      English.lproj/InfoPlist.strings
  2. 685 0
      Pal.xcodeproj/project.pbxproj
  3. 76 0
      adplug/NOTES/AUTHORS
  4. 509 0
      adplug/NOTES/COPYING
  5. 6 0
      adplug/NOTES/NOTES
  6. 86 0
      adplug/NOTES/README
  7. 253 0
      adplug/binfile.cpp
  8. 111 0
      adplug/binfile.h
  9. 655 0
      adplug/binio.cpp
  10. 180 0
      adplug/binio.h
  11. 75 0
      adplug/demuopl.h
  12. 1488 0
      adplug/dosbox_opl.cpp
  13. 188 0
      adplug/dosbox_opl.h
  14. 146 0
      adplug/emuopl.cpp
  15. 48 0
      adplug/emuopl.h
  16. 1263 0
      adplug/fmopl.c
  17. 180 0
      adplug/fmopl.h
  18. 83 0
      adplug/fprovide.cpp
  19. 47 0
      adplug/fprovide.h
  20. 63 0
      adplug/opl.h
  21. 65 0
      adplug/player.cpp
  22. 92 0
      adplug/player.h
  23. 518 0
      adplug/rix.cpp
  24. 121 0
      adplug/rix.h
  25. 203 0
      adplug/surroundopl.cpp
  26. 69 0
      adplug/surroundopl.h
  27. 607 0
      libmad/D.dat
  28. 235 0
      libmad/bit.c
  29. 47 0
      libmad/bit.h
  30. 580 0
      libmad/decoder.c
  31. 91 0
      libmad/decoder.h
  32. 79 0
      libmad/fixed.c
  33. 499 0
      libmad/fixed.h
  34. 501 0
      libmad/frame.c
  35. 118 0
      libmad/frame.h
  36. 3107 0
      libmad/huffman.c
  37. 66 0
      libmad/huffman.h
  38. 62 0
      libmad/imdct_s.dat
  39. 532 0
      libmad/layer12.c
  40. 31 0
      libmad/layer12.h
  41. 2696 0
      libmad/layer3.c
  42. 30 0
      libmad/layer3.h
  43. 139 0
      libmad/libmad_config.h
  44. 58 0
      libmad/libmad_global.h
  45. 964 0
      libmad/mad.h
  46. 327 0
      libmad/music_mad.c
  47. 68 0
      libmad/music_mad.h
  48. 77 0
      libmad/qc_table.dat
  49. 8747 0
      libmad/rq_table.dat
  50. 106 0
      libmad/sf_table.dat
  51. 159 0
      libmad/stream.c
  52. 108 0
      libmad/stream.h
  53. 855 0
      libmad/synth.c
  54. 69 0
      libmad/synth.h
  55. 483 0
      libmad/timer.c
  56. 100 0
      libmad/timer.h
  57. 40 0
      native_midi/native_midi.h
  58. 409 0
      native_midi/native_midi_common.c
  59. 67 0
      native_midi/native_midi_common.h
  60. 312 0
      native_midi/native_midi_macosx.c
  61. 317 0
      native_midi/native_midi_win32.c

BIN
English.lproj/InfoPlist.strings


+ 685 - 0
Pal.xcodeproj/project.pbxproj

@@ -0,0 +1,685 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 42;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		002F39FA09D0881F00EBEB88 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002F39F909D0881F00EBEB88 /* SDL.framework */; };
+		002F3A0009D0884600EBEB88 /* SDL.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 002F39F909D0881F00EBEB88 /* SDL.framework */; };
+		002F3A2E09D0888800EBEB88 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A2C09D0888800EBEB88 /* SDLMain.m */; };
+		002F3A3F09D088BA00EBEB88 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A3E09D088BA00EBEB88 /* main.c */; };
+		7104FD6A0D772F6300A97E53 /* battle.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD3A0D772F6300A97E53 /* battle.c */; };
+		7104FD6D0D772F6300A97E53 /* font.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD3D0D772F6300A97E53 /* font.c */; };
+		7104FD710D772F6300A97E53 /* getopt.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD410D772F6300A97E53 /* getopt.c */; };
+		7104FD730D772F6300A97E53 /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD430D772F6300A97E53 /* global.c */; };
+		7104FD750D772F6300A97E53 /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD450D772F6300A97E53 /* input.c */; };
+		7104FD780D772F6300A97E53 /* map.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD480D772F6300A97E53 /* map.c */; };
+		7104FD7A0D772F6300A97E53 /* palcommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD4A0D772F6300A97E53 /* palcommon.c */; };
+		7104FD7C0D772F6300A97E53 /* palette.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD4C0D772F6300A97E53 /* palette.c */; };
+		7104FD7E0D772F6300A97E53 /* play.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD4E0D772F6300A97E53 /* play.c */; };
+		7104FD800D772F6300A97E53 /* res.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD500D772F6300A97E53 /* res.c */; };
+		7104FD820D772F6300A97E53 /* rixplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD520D772F6300A97E53 /* rixplay.cpp */; };
+		7104FD840D772F6300A97E53 /* rngplay.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD540D772F6300A97E53 /* rngplay.c */; };
+		7104FD860D772F6300A97E53 /* scene.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD560D772F6300A97E53 /* scene.c */; };
+		7104FD880D772F6300A97E53 /* script.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD580D772F6300A97E53 /* script.c */; };
+		7104FD8A0D772F6300A97E53 /* sound.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD5A0D772F6300A97E53 /* sound.c */; };
+		7104FD8C0D772F6300A97E53 /* text.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD5C0D772F6300A97E53 /* text.c */; };
+		7104FD900D772F6300A97E53 /* uibattle.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD600D772F6300A97E53 /* uibattle.c */; };
+		7104FD920D772F6300A97E53 /* uigame.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD620D772F6300A97E53 /* uigame.c */; };
+		7104FD940D772F6300A97E53 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD640D772F6300A97E53 /* util.c */; };
+		7104FD960D772F6300A97E53 /* video.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD660D772F6300A97E53 /* video.c */; };
+		7104FD980D772F6300A97E53 /* yj1.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD680D772F6300A97E53 /* yj1.c */; };
+		7104FDA90D772FBC00A97E53 /* binfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD9A0D772FBC00A97E53 /* binfile.cpp */; };
+		7104FDAB0D772FBC00A97E53 /* binio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD9C0D772FBC00A97E53 /* binio.cpp */; };
+		7104FDAD0D772FBC00A97E53 /* emuopl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD9E0D772FBC00A97E53 /* emuopl.cpp */; };
+		7104FDAF0D772FBC00A97E53 /* fmopl.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FDA00D772FBC00A97E53 /* fmopl.c */; };
+		7104FDB10D772FBC00A97E53 /* fprovide.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FDA20D772FBC00A97E53 /* fprovide.cpp */; };
+		7104FDB40D772FBC00A97E53 /* player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FDA50D772FBC00A97E53 /* player.cpp */; };
+		7104FDB60D772FBC00A97E53 /* rix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7104FDA70D772FBC00A97E53 /* rix.cpp */; };
+		71147E4014085E31003FB2DB /* surroundopl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71147E3E14085E31003FB2DB /* surroundopl.cpp */; };
+		71147E4114085E31003FB2DB /* surroundopl.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71147E3F14085E31003FB2DB /* surroundopl.h */; };
+		7138FD0E1424E4810060DE76 /* demuopl.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 7138FD0B1424E4810060DE76 /* demuopl.h */; };
+		7138FD0F1424E4810060DE76 /* dosbox_opl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7138FD0C1424E4810060DE76 /* dosbox_opl.cpp */; };
+		7138FD101424E4810060DE76 /* dosbox_opl.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 7138FD0D1424E4810060DE76 /* dosbox_opl.h */; };
+		716EB9BC0D77318900D5DE1F /* game.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD3F0D772F6300A97E53 /* game.c */; };
+		716EB9C70D77340300D5DE1F /* sdlpal.icns in Resources */ = {isa = PBXBuildFile; fileRef = 716EB9C60D77340300D5DE1F /* sdlpal.icns */; };
+		716EB9CA0D77347B00D5DE1F /* ui.c in Sources */ = {isa = PBXBuildFile; fileRef = 7104FD5E0D772F6300A97E53 /* ui.c */; };
+		71E23E9113F6D1AD001287B6 /* bit.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7113F6D1AD001287B6 /* bit.c */; };
+		71E23E9213F6D1AD001287B6 /* bit.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E7213F6D1AD001287B6 /* bit.h */; };
+		71E23E9313F6D1AD001287B6 /* D.dat in Resources */ = {isa = PBXBuildFile; fileRef = 71E23E7313F6D1AD001287B6 /* D.dat */; };
+		71E23E9413F6D1AD001287B6 /* decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7413F6D1AD001287B6 /* decoder.c */; };
+		71E23E9513F6D1AD001287B6 /* decoder.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E7513F6D1AD001287B6 /* decoder.h */; };
+		71E23E9613F6D1AD001287B6 /* fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7613F6D1AD001287B6 /* fixed.c */; };
+		71E23E9713F6D1AD001287B6 /* fixed.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E7713F6D1AD001287B6 /* fixed.h */; };
+		71E23E9813F6D1AD001287B6 /* frame.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7813F6D1AD001287B6 /* frame.c */; };
+		71E23E9913F6D1AD001287B6 /* frame.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E7913F6D1AD001287B6 /* frame.h */; };
+		71E23E9A13F6D1AD001287B6 /* huffman.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7A13F6D1AD001287B6 /* huffman.c */; };
+		71E23E9B13F6D1AD001287B6 /* huffman.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E7B13F6D1AD001287B6 /* huffman.h */; };
+		71E23E9C13F6D1AD001287B6 /* imdct_s.dat in Resources */ = {isa = PBXBuildFile; fileRef = 71E23E7C13F6D1AD001287B6 /* imdct_s.dat */; };
+		71E23E9D13F6D1AD001287B6 /* layer3.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7D13F6D1AD001287B6 /* layer3.c */; };
+		71E23E9E13F6D1AD001287B6 /* layer3.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E7E13F6D1AD001287B6 /* layer3.h */; };
+		71E23E9F13F6D1AD001287B6 /* layer12.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E7F13F6D1AD001287B6 /* layer12.c */; };
+		71E23EA013F6D1AD001287B6 /* layer12.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8013F6D1AD001287B6 /* layer12.h */; };
+		71E23EA113F6D1AD001287B6 /* libmad_config.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8113F6D1AD001287B6 /* libmad_config.h */; };
+		71E23EA213F6D1AD001287B6 /* libmad_global.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8213F6D1AD001287B6 /* libmad_global.h */; };
+		71E23EA313F6D1AD001287B6 /* mad.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8313F6D1AD001287B6 /* mad.h */; };
+		71E23EA413F6D1AD001287B6 /* music_mad.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E8413F6D1AD001287B6 /* music_mad.c */; };
+		71E23EA513F6D1AD001287B6 /* music_mad.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8513F6D1AD001287B6 /* music_mad.h */; };
+		71E23EA613F6D1AD001287B6 /* qc_table.dat in Resources */ = {isa = PBXBuildFile; fileRef = 71E23E8613F6D1AD001287B6 /* qc_table.dat */; };
+		71E23EA713F6D1AD001287B6 /* rq_table.dat in Resources */ = {isa = PBXBuildFile; fileRef = 71E23E8713F6D1AD001287B6 /* rq_table.dat */; };
+		71E23EA813F6D1AD001287B6 /* sf_table.dat in Resources */ = {isa = PBXBuildFile; fileRef = 71E23E8813F6D1AD001287B6 /* sf_table.dat */; };
+		71E23EA913F6D1AD001287B6 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E8913F6D1AD001287B6 /* stream.c */; };
+		71E23EAA13F6D1AD001287B6 /* stream.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8A13F6D1AD001287B6 /* stream.h */; };
+		71E23EAB13F6D1AD001287B6 /* synth.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E8B13F6D1AD001287B6 /* synth.c */; };
+		71E23EAC13F6D1AD001287B6 /* synth.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8C13F6D1AD001287B6 /* synth.h */; };
+		71E23EAD13F6D1AD001287B6 /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E8D13F6D1AD001287B6 /* timer.c */; };
+		71E23EAE13F6D1AD001287B6 /* timer.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E8E13F6D1AD001287B6 /* timer.h */; };
+		71E23EAF13F6D1AD001287B6 /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E23E8F13F6D1AD001287B6 /* version.c */; };
+		71E23EB013F6D1AD001287B6 /* version.h in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 71E23E9013F6D1AD001287B6 /* version.h */; };
+		71E27E050D8C7E2F0048BA16 /* fight.c in Sources */ = {isa = PBXBuildFile; fileRef = 71E27E030D8C7E2F0048BA16 /* fight.c */; };
+		71F0F6D70DAA63B400F88C16 /* ending.c in Sources */ = {isa = PBXBuildFile; fileRef = 71F0F6D10DAA63B400F88C16 /* ending.c */; };
+		71F0F6D90DAA63B500F88C16 /* itemmenu.c in Sources */ = {isa = PBXBuildFile; fileRef = 71F0F6D30DAA63B400F88C16 /* itemmenu.c */; };
+		71F0F6DB0DAA63B500F88C16 /* magicmenu.c in Sources */ = {isa = PBXBuildFile; fileRef = 71F0F6D50DAA63B400F88C16 /* magicmenu.c */; };
+		8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
+		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+				002F3A0009D0884600EBEB88 /* SDL.framework in Copy Frameworks into .app bundle */,
+				71E23E9213F6D1AD001287B6 /* bit.h in Copy Frameworks into .app bundle */,
+				71E23E9513F6D1AD001287B6 /* decoder.h in Copy Frameworks into .app bundle */,
+				71E23E9713F6D1AD001287B6 /* fixed.h in Copy Frameworks into .app bundle */,
+				71E23E9913F6D1AD001287B6 /* frame.h in Copy Frameworks into .app bundle */,
+				71E23E9B13F6D1AD001287B6 /* huffman.h in Copy Frameworks into .app bundle */,
+				71E23E9E13F6D1AD001287B6 /* layer3.h in Copy Frameworks into .app bundle */,
+				71E23EA013F6D1AD001287B6 /* layer12.h in Copy Frameworks into .app bundle */,
+				71E23EA113F6D1AD001287B6 /* libmad_config.h in Copy Frameworks into .app bundle */,
+				71E23EA213F6D1AD001287B6 /* libmad_global.h in Copy Frameworks into .app bundle */,
+				71E23EA313F6D1AD001287B6 /* mad.h in Copy Frameworks into .app bundle */,
+				71E23EA513F6D1AD001287B6 /* music_mad.h in Copy Frameworks into .app bundle */,
+				71E23EAA13F6D1AD001287B6 /* stream.h in Copy Frameworks into .app bundle */,
+				71E23EAC13F6D1AD001287B6 /* synth.h in Copy Frameworks into .app bundle */,
+				71E23EAE13F6D1AD001287B6 /* timer.h in Copy Frameworks into .app bundle */,
+				71E23EB013F6D1AD001287B6 /* version.h in Copy Frameworks into .app bundle */,
+				71147E4114085E31003FB2DB /* surroundopl.h in Copy Frameworks into .app bundle */,
+				7138FD0E1424E4810060DE76 /* demuopl.h in Copy Frameworks into .app bundle */,
+				7138FD101424E4810060DE76 /* dosbox_opl.h in Copy Frameworks into .app bundle */,
+			);
+			name = "Copy Frameworks into .app bundle";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		002F39F909D0881F00EBEB88 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = "<absolute>"; };
+		002F3A2B09D0888800EBEB88 /* SDLMain_Cocoa.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SDLMain_Cocoa.h; sourceTree = SOURCE_ROOT; };
+		002F3A2C09D0888800EBEB88 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = SOURCE_ROOT; };
+		002F3A3E09D088BA00EBEB88 /* main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = SOURCE_ROOT; };
+		089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+		29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+		29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+		32CA4F630368D1EE00C91783 /* Pal_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pal_Prefix.pch; sourceTree = "<group>"; };
+		7104FD390D772F6300A97E53 /* ascii.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ascii.h; sourceTree = "<group>"; };
+		7104FD3A0D772F6300A97E53 /* battle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = battle.c; sourceTree = "<group>"; };
+		7104FD3B0D772F6300A97E53 /* battle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = battle.h; sourceTree = "<group>"; };
+		7104FD3C0D772F6300A97E53 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+		7104FD3D0D772F6300A97E53 /* font.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = font.c; sourceTree = "<group>"; };
+		7104FD3E0D772F6300A97E53 /* font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = font.h; sourceTree = "<group>"; };
+		7104FD3F0D772F6300A97E53 /* game.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = game.c; sourceTree = "<group>"; };
+		7104FD400D772F6300A97E53 /* game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = game.h; sourceTree = "<group>"; };
+		7104FD410D772F6300A97E53 /* getopt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getopt.c; sourceTree = "<group>"; };
+		7104FD420D772F6300A97E53 /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = "<group>"; };
+		7104FD430D772F6300A97E53 /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = global.c; sourceTree = "<group>"; };
+		7104FD440D772F6300A97E53 /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = global.h; sourceTree = "<group>"; };
+		7104FD450D772F6300A97E53 /* input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = input.c; sourceTree = "<group>"; };
+		7104FD460D772F6300A97E53 /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input.h; sourceTree = "<group>"; };
+		7104FD470D772F6300A97E53 /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
+		7104FD480D772F6300A97E53 /* map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = map.c; sourceTree = "<group>"; };
+		7104FD490D772F6300A97E53 /* map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = map.h; sourceTree = "<group>"; };
+		7104FD4A0D772F6300A97E53 /* palcommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = palcommon.c; sourceTree = "<group>"; };
+		7104FD4B0D772F6300A97E53 /* palcommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = palcommon.h; sourceTree = "<group>"; };
+		7104FD4C0D772F6300A97E53 /* palette.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = palette.c; sourceTree = "<group>"; };
+		7104FD4D0D772F6300A97E53 /* palette.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = palette.h; sourceTree = "<group>"; };
+		7104FD4E0D772F6300A97E53 /* play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = play.c; sourceTree = "<group>"; };
+		7104FD4F0D772F6300A97E53 /* play.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = play.h; sourceTree = "<group>"; };
+		7104FD500D772F6300A97E53 /* res.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = res.c; sourceTree = "<group>"; };
+		7104FD510D772F6300A97E53 /* res.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = res.h; sourceTree = "<group>"; };
+		7104FD520D772F6300A97E53 /* rixplay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rixplay.cpp; sourceTree = "<group>"; };
+		7104FD530D772F6300A97E53 /* rixplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rixplay.h; sourceTree = "<group>"; };
+		7104FD540D772F6300A97E53 /* rngplay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rngplay.c; sourceTree = "<group>"; };
+		7104FD550D772F6300A97E53 /* rngplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rngplay.h; sourceTree = "<group>"; };
+		7104FD560D772F6300A97E53 /* scene.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scene.c; sourceTree = "<group>"; };
+		7104FD570D772F6300A97E53 /* scene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scene.h; sourceTree = "<group>"; };
+		7104FD580D772F6300A97E53 /* script.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = script.c; sourceTree = "<group>"; };
+		7104FD590D772F6300A97E53 /* script.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = script.h; sourceTree = "<group>"; };
+		7104FD5A0D772F6300A97E53 /* sound.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sound.c; sourceTree = "<group>"; };
+		7104FD5B0D772F6300A97E53 /* sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sound.h; sourceTree = "<group>"; };
+		7104FD5C0D772F6300A97E53 /* text.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = text.c; sourceTree = "<group>"; };
+		7104FD5D0D772F6300A97E53 /* text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text.h; sourceTree = "<group>"; };
+		7104FD5E0D772F6300A97E53 /* ui.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ui.c; sourceTree = "<group>"; };
+		7104FD5F0D772F6300A97E53 /* ui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = "<group>"; };
+		7104FD600D772F6300A97E53 /* uibattle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uibattle.c; sourceTree = "<group>"; };
+		7104FD610D772F6300A97E53 /* uibattle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uibattle.h; sourceTree = "<group>"; };
+		7104FD620D772F6300A97E53 /* uigame.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uigame.c; sourceTree = "<group>"; };
+		7104FD630D772F6300A97E53 /* uigame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uigame.h; sourceTree = "<group>"; };
+		7104FD640D772F6300A97E53 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+		7104FD650D772F6300A97E53 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
+		7104FD660D772F6300A97E53 /* video.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = video.c; sourceTree = "<group>"; };
+		7104FD670D772F6300A97E53 /* video.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video.h; sourceTree = "<group>"; };
+		7104FD680D772F6300A97E53 /* yj1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yj1.c; sourceTree = "<group>"; };
+		7104FD9A0D772FBC00A97E53 /* binfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = binfile.cpp; path = adplug/binfile.cpp; sourceTree = SOURCE_ROOT; };
+		7104FD9B0D772FBC00A97E53 /* binfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = binfile.h; path = adplug/binfile.h; sourceTree = SOURCE_ROOT; };
+		7104FD9C0D772FBC00A97E53 /* binio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = binio.cpp; path = adplug/binio.cpp; sourceTree = SOURCE_ROOT; };
+		7104FD9D0D772FBC00A97E53 /* binio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = binio.h; path = adplug/binio.h; sourceTree = SOURCE_ROOT; };
+		7104FD9E0D772FBC00A97E53 /* emuopl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = emuopl.cpp; path = adplug/emuopl.cpp; sourceTree = SOURCE_ROOT; };
+		7104FD9F0D772FBC00A97E53 /* emuopl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = emuopl.h; path = adplug/emuopl.h; sourceTree = SOURCE_ROOT; };
+		7104FDA00D772FBC00A97E53 /* fmopl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fmopl.c; path = adplug/fmopl.c; sourceTree = SOURCE_ROOT; };
+		7104FDA10D772FBC00A97E53 /* fmopl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fmopl.h; path = adplug/fmopl.h; sourceTree = SOURCE_ROOT; };
+		7104FDA20D772FBC00A97E53 /* fprovide.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fprovide.cpp; path = adplug/fprovide.cpp; sourceTree = SOURCE_ROOT; };
+		7104FDA30D772FBC00A97E53 /* fprovide.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fprovide.h; path = adplug/fprovide.h; sourceTree = SOURCE_ROOT; };
+		7104FDA40D772FBC00A97E53 /* opl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = opl.h; path = adplug/opl.h; sourceTree = SOURCE_ROOT; };
+		7104FDA50D772FBC00A97E53 /* player.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = player.cpp; path = adplug/player.cpp; sourceTree = SOURCE_ROOT; };
+		7104FDA60D772FBC00A97E53 /* player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = player.h; path = adplug/player.h; sourceTree = SOURCE_ROOT; };
+		7104FDA70D772FBC00A97E53 /* rix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rix.cpp; path = adplug/rix.cpp; sourceTree = SOURCE_ROOT; };
+		7104FDA80D772FBC00A97E53 /* rix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rix.h; path = adplug/rix.h; sourceTree = SOURCE_ROOT; };
+		71147E3E14085E31003FB2DB /* surroundopl.cpp */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.cpp.cpp; name = surroundopl.cpp; path = adplug/surroundopl.cpp; sourceTree = "<group>"; };
+		71147E3F14085E31003FB2DB /* surroundopl.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = surroundopl.h; path = adplug/surroundopl.h; sourceTree = "<group>"; };
+		7138FD0B1424E4810060DE76 /* demuopl.h */ = {isa = PBXFileReference; fileEncoding = "-2147483623"; lastKnownFileType = sourcecode.c.h; name = demuopl.h; path = adplug/demuopl.h; sourceTree = "<group>"; };
+		7138FD0C1424E4810060DE76 /* dosbox_opl.cpp */ = {isa = PBXFileReference; fileEncoding = "-2147483623"; lastKnownFileType = sourcecode.cpp.cpp; name = dosbox_opl.cpp; path = adplug/dosbox_opl.cpp; sourceTree = "<group>"; };
+		7138FD0D1424E4810060DE76 /* dosbox_opl.h */ = {isa = PBXFileReference; fileEncoding = "-2147483623"; lastKnownFileType = sourcecode.c.h; name = dosbox_opl.h; path = adplug/dosbox_opl.h; sourceTree = "<group>"; };
+		716EB9C60D77340300D5DE1F /* sdlpal.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = sdlpal.icns; sourceTree = SOURCE_ROOT; };
+		71E23E7113F6D1AD001287B6 /* bit.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = bit.c; path = libmad/bit.c; sourceTree = "<group>"; };
+		71E23E7213F6D1AD001287B6 /* bit.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = bit.h; path = libmad/bit.h; sourceTree = "<group>"; };
+		71E23E7313F6D1AD001287B6 /* D.dat */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = text; name = D.dat; path = libmad/D.dat; sourceTree = "<group>"; };
+		71E23E7413F6D1AD001287B6 /* decoder.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = decoder.c; path = libmad/decoder.c; sourceTree = "<group>"; };
+		71E23E7513F6D1AD001287B6 /* decoder.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = decoder.h; path = libmad/decoder.h; sourceTree = "<group>"; };
+		71E23E7613F6D1AD001287B6 /* fixed.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = fixed.c; path = libmad/fixed.c; sourceTree = "<group>"; };
+		71E23E7713F6D1AD001287B6 /* fixed.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = fixed.h; path = libmad/fixed.h; sourceTree = "<group>"; };
+		71E23E7813F6D1AD001287B6 /* frame.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = frame.c; path = libmad/frame.c; sourceTree = "<group>"; };
+		71E23E7913F6D1AD001287B6 /* frame.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = frame.h; path = libmad/frame.h; sourceTree = "<group>"; };
+		71E23E7A13F6D1AD001287B6 /* huffman.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = huffman.c; path = libmad/huffman.c; sourceTree = "<group>"; };
+		71E23E7B13F6D1AD001287B6 /* huffman.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = huffman.h; path = libmad/huffman.h; sourceTree = "<group>"; };
+		71E23E7C13F6D1AD001287B6 /* imdct_s.dat */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = text; name = imdct_s.dat; path = libmad/imdct_s.dat; sourceTree = "<group>"; };
+		71E23E7D13F6D1AD001287B6 /* layer3.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = layer3.c; path = libmad/layer3.c; sourceTree = "<group>"; };
+		71E23E7E13F6D1AD001287B6 /* layer3.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = layer3.h; path = libmad/layer3.h; sourceTree = "<group>"; };
+		71E23E7F13F6D1AD001287B6 /* layer12.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = layer12.c; path = libmad/layer12.c; sourceTree = "<group>"; };
+		71E23E8013F6D1AD001287B6 /* layer12.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = layer12.h; path = libmad/layer12.h; sourceTree = "<group>"; };
+		71E23E8113F6D1AD001287B6 /* libmad_config.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = libmad_config.h; path = libmad/libmad_config.h; sourceTree = "<group>"; };
+		71E23E8213F6D1AD001287B6 /* libmad_global.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = libmad_global.h; path = libmad/libmad_global.h; sourceTree = "<group>"; };
+		71E23E8313F6D1AD001287B6 /* mad.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = mad.h; path = libmad/mad.h; sourceTree = "<group>"; };
+		71E23E8413F6D1AD001287B6 /* music_mad.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = music_mad.c; path = libmad/music_mad.c; sourceTree = "<group>"; };
+		71E23E8513F6D1AD001287B6 /* music_mad.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = music_mad.h; path = libmad/music_mad.h; sourceTree = "<group>"; };
+		71E23E8613F6D1AD001287B6 /* qc_table.dat */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = text; name = qc_table.dat; path = libmad/qc_table.dat; sourceTree = "<group>"; };
+		71E23E8713F6D1AD001287B6 /* rq_table.dat */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = text; name = rq_table.dat; path = libmad/rq_table.dat; sourceTree = "<group>"; };
+		71E23E8813F6D1AD001287B6 /* sf_table.dat */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = text; name = sf_table.dat; path = libmad/sf_table.dat; sourceTree = "<group>"; };
+		71E23E8913F6D1AD001287B6 /* stream.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = stream.c; path = libmad/stream.c; sourceTree = "<group>"; };
+		71E23E8A13F6D1AD001287B6 /* stream.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = stream.h; path = libmad/stream.h; sourceTree = "<group>"; };
+		71E23E8B13F6D1AD001287B6 /* synth.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = synth.c; path = libmad/synth.c; sourceTree = "<group>"; };
+		71E23E8C13F6D1AD001287B6 /* synth.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = synth.h; path = libmad/synth.h; sourceTree = "<group>"; };
+		71E23E8D13F6D1AD001287B6 /* timer.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = timer.c; path = libmad/timer.c; sourceTree = "<group>"; };
+		71E23E8E13F6D1AD001287B6 /* timer.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = timer.h; path = libmad/timer.h; sourceTree = "<group>"; };
+		71E23E8F13F6D1AD001287B6 /* version.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; name = version.c; path = libmad/version.c; sourceTree = "<group>"; };
+		71E23E9013F6D1AD001287B6 /* version.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; name = version.h; path = libmad/version.h; sourceTree = "<group>"; };
+		71E27E030D8C7E2F0048BA16 /* fight.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; path = fight.c; sourceTree = "<group>"; };
+		71E27E040D8C7E2F0048BA16 /* fight.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; path = fight.h; sourceTree = "<group>"; };
+		71F0F6D10DAA63B400F88C16 /* ending.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; path = ending.c; sourceTree = SOURCE_ROOT; };
+		71F0F6D20DAA63B400F88C16 /* ending.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; path = ending.h; sourceTree = SOURCE_ROOT; };
+		71F0F6D30DAA63B400F88C16 /* itemmenu.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; path = itemmenu.c; sourceTree = SOURCE_ROOT; };
+		71F0F6D40DAA63B400F88C16 /* itemmenu.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; path = itemmenu.h; sourceTree = SOURCE_ROOT; };
+		71F0F6D50DAA63B400F88C16 /* magicmenu.c */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.c; path = magicmenu.c; sourceTree = SOURCE_ROOT; };
+		71F0F6D60DAA63B400F88C16 /* magicmenu.h */ = {isa = PBXFileReference; fileEncoding = 0; lastKnownFileType = sourcecode.c.h; path = magicmenu.h; sourceTree = SOURCE_ROOT; };
+		8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+		8D1107320486CEB800E47090 /* Pal.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Pal.app; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		8D11072E0486CEB800E47090 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				002F39FA09D0881F00EBEB88 /* SDL.framework in Frameworks */,
+				8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		080E96DDFE201D6D7F000001 /* Classes */ = {
+			isa = PBXGroup;
+			children = (
+				002F3A2B09D0888800EBEB88 /* SDLMain_Cocoa.h */,
+				002F3A2C09D0888800EBEB88 /* SDLMain.m */,
+			);
+			name = Classes;
+			sourceTree = "<group>";
+		};
+		1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				002F39F909D0881F00EBEB88 /* SDL.framework */,
+				1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
+			);
+			name = "Linked Frameworks";
+			sourceTree = "<group>";
+		};
+		1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				29B97324FDCFA39411CA2CEA /* AppKit.framework */,
+				29B97325FDCFA39411CA2CEA /* Foundation.framework */,
+			);
+			name = "Other Frameworks";
+			sourceTree = "<group>";
+		};
+		19C28FACFE9D520D11CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				8D1107320486CEB800E47090 /* Pal.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		29B97314FDCFA39411CA2CEA /* Pal */ = {
+			isa = PBXGroup;
+			children = (
+				71E23E7013F6D188001287B6 /* libmad */,
+				7104FD990D772FAA00A97E53 /* adplug */,
+				080E96DDFE201D6D7F000001 /* Classes */,
+				29B97315FDCFA39411CA2CEA /* Other Sources */,
+				29B97317FDCFA39411CA2CEA /* Resources */,
+				29B97323FDCFA39411CA2CEA /* Frameworks */,
+				19C28FACFE9D520D11CA2CBB /* Products */,
+			);
+			name = Pal;
+			sourceTree = "<group>";
+		};
+		29B97315FDCFA39411CA2CEA /* Other Sources */ = {
+			isa = PBXGroup;
+			children = (
+				71F0F6D10DAA63B400F88C16 /* ending.c */,
+				71F0F6D20DAA63B400F88C16 /* ending.h */,
+				71F0F6D30DAA63B400F88C16 /* itemmenu.c */,
+				71F0F6D40DAA63B400F88C16 /* itemmenu.h */,
+				71F0F6D50DAA63B400F88C16 /* magicmenu.c */,
+				71F0F6D60DAA63B400F88C16 /* magicmenu.h */,
+				7104FD390D772F6300A97E53 /* ascii.h */,
+				7104FD3A0D772F6300A97E53 /* battle.c */,
+				7104FD3B0D772F6300A97E53 /* battle.h */,
+				7104FD3C0D772F6300A97E53 /* common.h */,
+				71E27E030D8C7E2F0048BA16 /* fight.c */,
+				71E27E040D8C7E2F0048BA16 /* fight.h */,
+				7104FD3D0D772F6300A97E53 /* font.c */,
+				7104FD3E0D772F6300A97E53 /* font.h */,
+				7104FD3F0D772F6300A97E53 /* game.c */,
+				7104FD400D772F6300A97E53 /* game.h */,
+				7104FD410D772F6300A97E53 /* getopt.c */,
+				7104FD420D772F6300A97E53 /* getopt.h */,
+				7104FD430D772F6300A97E53 /* global.c */,
+				7104FD440D772F6300A97E53 /* global.h */,
+				7104FD450D772F6300A97E53 /* input.c */,
+				7104FD460D772F6300A97E53 /* input.h */,
+				7104FD470D772F6300A97E53 /* main.h */,
+				7104FD480D772F6300A97E53 /* map.c */,
+				7104FD490D772F6300A97E53 /* map.h */,
+				7104FD4A0D772F6300A97E53 /* palcommon.c */,
+				7104FD4B0D772F6300A97E53 /* palcommon.h */,
+				7104FD4C0D772F6300A97E53 /* palette.c */,
+				7104FD4D0D772F6300A97E53 /* palette.h */,
+				7104FD4E0D772F6300A97E53 /* play.c */,
+				7104FD4F0D772F6300A97E53 /* play.h */,
+				7104FD500D772F6300A97E53 /* res.c */,
+				7104FD510D772F6300A97E53 /* res.h */,
+				7104FD520D772F6300A97E53 /* rixplay.cpp */,
+				7104FD530D772F6300A97E53 /* rixplay.h */,
+				7104FD540D772F6300A97E53 /* rngplay.c */,
+				7104FD550D772F6300A97E53 /* rngplay.h */,
+				7104FD560D772F6300A97E53 /* scene.c */,
+				7104FD570D772F6300A97E53 /* scene.h */,
+				7104FD580D772F6300A97E53 /* script.c */,
+				7104FD590D772F6300A97E53 /* script.h */,
+				7104FD5A0D772F6300A97E53 /* sound.c */,
+				7104FD5B0D772F6300A97E53 /* sound.h */,
+				7104FD5C0D772F6300A97E53 /* text.c */,
+				7104FD5D0D772F6300A97E53 /* text.h */,
+				7104FD5E0D772F6300A97E53 /* ui.c */,
+				7104FD5F0D772F6300A97E53 /* ui.h */,
+				7104FD600D772F6300A97E53 /* uibattle.c */,
+				7104FD610D772F6300A97E53 /* uibattle.h */,
+				7104FD620D772F6300A97E53 /* uigame.c */,
+				7104FD630D772F6300A97E53 /* uigame.h */,
+				7104FD640D772F6300A97E53 /* util.c */,
+				7104FD650D772F6300A97E53 /* util.h */,
+				7104FD660D772F6300A97E53 /* video.c */,
+				7104FD670D772F6300A97E53 /* video.h */,
+				7104FD680D772F6300A97E53 /* yj1.c */,
+				32CA4F630368D1EE00C91783 /* Pal_Prefix.pch */,
+				002F3A3E09D088BA00EBEB88 /* main.c */,
+			);
+			name = "Other Sources";
+			sourceTree = "<group>";
+		};
+		29B97317FDCFA39411CA2CEA /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				716EB9C60D77340300D5DE1F /* sdlpal.icns */,
+				8D1107310486CEB800E47090 /* Info.plist */,
+				089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
+			);
+			name = Resources;
+			sourceTree = "<group>";
+		};
+		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
+				1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		7104FD990D772FAA00A97E53 /* adplug */ = {
+			isa = PBXGroup;
+			children = (
+				7138FD0B1424E4810060DE76 /* demuopl.h */,
+				7138FD0C1424E4810060DE76 /* dosbox_opl.cpp */,
+				7138FD0D1424E4810060DE76 /* dosbox_opl.h */,
+				71147E3E14085E31003FB2DB /* surroundopl.cpp */,
+				71147E3F14085E31003FB2DB /* surroundopl.h */,
+				7104FD9A0D772FBC00A97E53 /* binfile.cpp */,
+				7104FD9B0D772FBC00A97E53 /* binfile.h */,
+				7104FD9C0D772FBC00A97E53 /* binio.cpp */,
+				7104FD9D0D772FBC00A97E53 /* binio.h */,
+				7104FD9E0D772FBC00A97E53 /* emuopl.cpp */,
+				7104FD9F0D772FBC00A97E53 /* emuopl.h */,
+				7104FDA00D772FBC00A97E53 /* fmopl.c */,
+				7104FDA10D772FBC00A97E53 /* fmopl.h */,
+				7104FDA20D772FBC00A97E53 /* fprovide.cpp */,
+				7104FDA30D772FBC00A97E53 /* fprovide.h */,
+				7104FDA40D772FBC00A97E53 /* opl.h */,
+				7104FDA50D772FBC00A97E53 /* player.cpp */,
+				7104FDA60D772FBC00A97E53 /* player.h */,
+				7104FDA70D772FBC00A97E53 /* rix.cpp */,
+				7104FDA80D772FBC00A97E53 /* rix.h */,
+			);
+			name = adplug;
+			sourceTree = "<group>";
+		};
+		71E23E7013F6D188001287B6 /* libmad */ = {
+			isa = PBXGroup;
+			children = (
+				71E23E7113F6D1AD001287B6 /* bit.c */,
+				71E23E7213F6D1AD001287B6 /* bit.h */,
+				71E23E7313F6D1AD001287B6 /* D.dat */,
+				71E23E7413F6D1AD001287B6 /* decoder.c */,
+				71E23E7513F6D1AD001287B6 /* decoder.h */,
+				71E23E7613F6D1AD001287B6 /* fixed.c */,
+				71E23E7713F6D1AD001287B6 /* fixed.h */,
+				71E23E7813F6D1AD001287B6 /* frame.c */,
+				71E23E7913F6D1AD001287B6 /* frame.h */,
+				71E23E7A13F6D1AD001287B6 /* huffman.c */,
+				71E23E7B13F6D1AD001287B6 /* huffman.h */,
+				71E23E7C13F6D1AD001287B6 /* imdct_s.dat */,
+				71E23E7D13F6D1AD001287B6 /* layer3.c */,
+				71E23E7E13F6D1AD001287B6 /* layer3.h */,
+				71E23E7F13F6D1AD001287B6 /* layer12.c */,
+				71E23E8013F6D1AD001287B6 /* layer12.h */,
+				71E23E8113F6D1AD001287B6 /* libmad_config.h */,
+				71E23E8213F6D1AD001287B6 /* libmad_global.h */,
+				71E23E8313F6D1AD001287B6 /* mad.h */,
+				71E23E8413F6D1AD001287B6 /* music_mad.c */,
+				71E23E8513F6D1AD001287B6 /* music_mad.h */,
+				71E23E8613F6D1AD001287B6 /* qc_table.dat */,
+				71E23E8713F6D1AD001287B6 /* rq_table.dat */,
+				71E23E8813F6D1AD001287B6 /* sf_table.dat */,
+				71E23E8913F6D1AD001287B6 /* stream.c */,
+				71E23E8A13F6D1AD001287B6 /* stream.h */,
+				71E23E8B13F6D1AD001287B6 /* synth.c */,
+				71E23E8C13F6D1AD001287B6 /* synth.h */,
+				71E23E8D13F6D1AD001287B6 /* timer.c */,
+				71E23E8E13F6D1AD001287B6 /* timer.h */,
+				71E23E8F13F6D1AD001287B6 /* version.c */,
+				71E23E9013F6D1AD001287B6 /* version.h */,
+			);
+			name = libmad;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		8D1107260486CEB800E47090 /* Pal */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Pal" */;
+			buildPhases = (
+				8D1107290486CEB800E47090 /* Resources */,
+				8D11072C0486CEB800E47090 /* Sources */,
+				8D11072E0486CEB800E47090 /* Frameworks */,
+				002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Pal;
+			productInstallPath = "$(HOME)/Applications";
+			productName = Pal;
+			productReference = 8D1107320486CEB800E47090 /* Pal.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		29B97313FDCFA39411CA2CEA /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Pal" */;
+			hasScannedForEncodings = 1;
+			mainGroup = 29B97314FDCFA39411CA2CEA /* Pal */;
+			projectDirPath = "";
+			targets = (
+				8D1107260486CEB800E47090 /* Pal */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		8D1107290486CEB800E47090 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
+				716EB9C70D77340300D5DE1F /* sdlpal.icns in Resources */,
+				71E23E9313F6D1AD001287B6 /* D.dat in Resources */,
+				71E23E9C13F6D1AD001287B6 /* imdct_s.dat in Resources */,
+				71E23EA613F6D1AD001287B6 /* qc_table.dat in Resources */,
+				71E23EA713F6D1AD001287B6 /* rq_table.dat in Resources */,
+				71E23EA813F6D1AD001287B6 /* sf_table.dat in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		8D11072C0486CEB800E47090 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				002F3A2E09D0888800EBEB88 /* SDLMain.m in Sources */,
+				002F3A3F09D088BA00EBEB88 /* main.c in Sources */,
+				7104FD6A0D772F6300A97E53 /* battle.c in Sources */,
+				7104FD6D0D772F6300A97E53 /* font.c in Sources */,
+				7104FD710D772F6300A97E53 /* getopt.c in Sources */,
+				7104FD730D772F6300A97E53 /* global.c in Sources */,
+				7104FD750D772F6300A97E53 /* input.c in Sources */,
+				7104FD780D772F6300A97E53 /* map.c in Sources */,
+				7104FD7A0D772F6300A97E53 /* palcommon.c in Sources */,
+				7104FD7C0D772F6300A97E53 /* palette.c in Sources */,
+				7104FD7E0D772F6300A97E53 /* play.c in Sources */,
+				7104FD800D772F6300A97E53 /* res.c in Sources */,
+				7104FD820D772F6300A97E53 /* rixplay.cpp in Sources */,
+				7104FD840D772F6300A97E53 /* rngplay.c in Sources */,
+				7104FD860D772F6300A97E53 /* scene.c in Sources */,
+				7104FD880D772F6300A97E53 /* script.c in Sources */,
+				7104FD8A0D772F6300A97E53 /* sound.c in Sources */,
+				7104FD8C0D772F6300A97E53 /* text.c in Sources */,
+				7104FD900D772F6300A97E53 /* uibattle.c in Sources */,
+				7104FD920D772F6300A97E53 /* uigame.c in Sources */,
+				7104FD940D772F6300A97E53 /* util.c in Sources */,
+				7104FD960D772F6300A97E53 /* video.c in Sources */,
+				7104FD980D772F6300A97E53 /* yj1.c in Sources */,
+				7104FDA90D772FBC00A97E53 /* binfile.cpp in Sources */,
+				7104FDAB0D772FBC00A97E53 /* binio.cpp in Sources */,
+				7104FDAD0D772FBC00A97E53 /* emuopl.cpp in Sources */,
+				7104FDAF0D772FBC00A97E53 /* fmopl.c in Sources */,
+				7104FDB10D772FBC00A97E53 /* fprovide.cpp in Sources */,
+				7104FDB40D772FBC00A97E53 /* player.cpp in Sources */,
+				7104FDB60D772FBC00A97E53 /* rix.cpp in Sources */,
+				716EB9BC0D77318900D5DE1F /* game.c in Sources */,
+				716EB9CA0D77347B00D5DE1F /* ui.c in Sources */,
+				71E27E050D8C7E2F0048BA16 /* fight.c in Sources */,
+				71F0F6D70DAA63B400F88C16 /* ending.c in Sources */,
+				71F0F6D90DAA63B500F88C16 /* itemmenu.c in Sources */,
+				71F0F6DB0DAA63B500F88C16 /* magicmenu.c in Sources */,
+				71E23E9113F6D1AD001287B6 /* bit.c in Sources */,
+				71E23E9413F6D1AD001287B6 /* decoder.c in Sources */,
+				71E23E9613F6D1AD001287B6 /* fixed.c in Sources */,
+				71E23E9813F6D1AD001287B6 /* frame.c in Sources */,
+				71E23E9A13F6D1AD001287B6 /* huffman.c in Sources */,
+				71E23E9D13F6D1AD001287B6 /* layer3.c in Sources */,
+				71E23E9F13F6D1AD001287B6 /* layer12.c in Sources */,
+				71E23EA413F6D1AD001287B6 /* music_mad.c in Sources */,
+				71E23EA913F6D1AD001287B6 /* stream.c in Sources */,
+				71E23EAB13F6D1AD001287B6 /* synth.c in Sources */,
+				71E23EAD13F6D1AD001287B6 /* timer.c in Sources */,
+				71E23EAF13F6D1AD001287B6 /* version.c in Sources */,
+				71147E4014085E31003FB2DB /* surroundopl.cpp in Sources */,
+				7138FD0F1424E4810060DE76 /* dosbox_opl.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				089C165DFE840E0CC02AAC07 /* English */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		C01FCF4B08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_MODEL_TUNING = G5;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INFOPLIST_FILE = Info.plist;
+				INSTALL_PATH = "$(HOME)/Applications";
+				PRODUCT_NAME = Pal;
+				WRAPPER_EXTENSION = app;
+				ZERO_LINK = YES;
+			};
+			name = Debug;
+		};
+		C01FCF4C08A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = (
+					ppc,
+					i386,
+				);
+				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+				GCC_MODEL_TUNING = G5;
+				INFOPLIST_FILE = Info.plist;
+				INSTALL_PATH = "$(HOME)/Applications";
+				PRODUCT_NAME = Pal;
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+		C01FCF4F08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = (
+					i386,
+					ppc,
+				);
+				DEAD_CODE_STRIPPING = NO;
+				FRAMEWORK_SEARCH_PATHS = (
+					/Library/Frameworks,
+					"$(FRAMEWORK_SEARCH_PATHS)",
+				);
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					/Library/Frameworks/SDL.framework/Headers,
+					"$(HEADER_SEARCH_PATHS)",
+				);
+				PREBINDING = NO;
+				SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+			};
+			name = Debug;
+		};
+		C01FCF5008A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = (
+					i386,
+					ppc,
+				);
+				DEAD_CODE_STRIPPING = YES;
+				FRAMEWORK_SEARCH_PATHS = (
+					/Library/Frameworks,
+					"$(FRAMEWORK_SEARCH_PATHS)",
+				);
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					/Library/Frameworks/SDL.framework/Headers,
+					"$(HEADER_SEARCH_PATHS)",
+				);
+				PREBINDING = NO;
+				SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Pal" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4B08A954540054247B /* Debug */,
+				C01FCF4C08A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Pal" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4F08A954540054247B /* Debug */,
+				C01FCF5008A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}

+ 76 - 0
adplug/NOTES/AUTHORS

@@ -0,0 +1,76 @@
+AdPlug is copyright (C) 1999 - 2007 Simon Peter <dn.tlp@gmx.net>, et al.
+All library code is written by Simon Peter, except the parts listed below.
+
+Additional Credits:
+-------------------
+Phil Hassey <philhassey@hotmail.com>:
+  - Player development for the following formats:
+    - MID: MIDI Audio File Format
+    - CMF: Creative Music File Format
+    - SCI: Sierra's AdLib Audio File Format
+    - LAA: LucasArts AdLib Audio File Format
+
+Marc Winterrowd <remove space and vowels from "marc winterrowd" and append
+                 "at yahoo" plus "dot com">:
+  - M: Origin Music player development
+
+Tatsuyuki Satoh <tatuyuki@tky.3web.ne.jp>:
+  - First YM3812 emulator development
+
+Ken Silverman <kjs@lems.brown.edu>:
+  - Second YM3812 emulator development
+
+Death Adder <death-adder@juno.com>:
+  - provided many file format specifications
+  - moral support ;)
+
+Mamiya <mamiya@users.sourceforge.net>:
+  - support for .SAT (early Surprise! Adlib Tracker) files
+
+Akintunde Omitowoju <oplx@yahoo.com>:
+  - ROL: AdLib Visual Composer player development
+
+Nikita V. Kalaganov <riven@ok.ru>:
+  - Player development:
+    - XAD: shell player and custom module formats
+  - Protracker loader development:
+    - SNG: Faust Music Creator
+    - MAD: Mlat Adlib Tracker
+    - CFF: BoomTracker 4.0
+    - DTM: DeFy Adlib Tracker
+  - Scream Tracker 3 loader development:
+    - DMO: Twin TrackPlayer
+  - XMS-Tracker detection support in AMD loader
+
+Sjoerd van der Berg <harekiet@zophar.net>:
+  - DRO: DOSBox Raw OPL player development
+
+Goetz Waschk <waschk@informatik.uni-rostock.de>:
+  - Mandrake Linux packages
+  - Red Hat RPM spec files
+
+Mike Gorchak <mike@malva.ua>:
+  - QNX packages
+  - QNX qpg file
+
+Tyler Montbriand <tsm@accesscomm.ca>:
+  - AMD64 (x86_64) fixes
+  - ROL: Added pitch handling
+
+Borg Number One [ Borg No. One ] <borg_no.one@gmx.net>:
+  - Many thanks for the huge amount of work to find the original
+    author (Andras Molnar) of the LOUDNESS Sound System and managing
+    to get the sources from him.
+
+Matthew Gambrell <mgambrell@gmail.com>:
+  - Enhancements to the DRO (DOSBox Raw OPL) format
+  - Added dual OPL2 and OPL3 support
+
+BSPAL <bspal.ys168.com>,
+Palxex <palxex@163.com>:
+  - RIX: Softstar RIX OPL Music Format player development
+
+Torbjorn Andersson,
+Johannes Schickel 'lordhoto' <lordhoto at scummvm dot org>:
+  - Development of original ADL (Westwood ADL File Format) player in
+    ScummVM, which has been adapted for AdPlug.

+ 509 - 0
adplug/NOTES/COPYING

@@ -0,0 +1,509 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard.  To achieve this, non-free programs must
+be allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+^L
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at least
+    three years, to give the same user the materials specified in
+    Subsection 6a, above, for a charge no more than the cost of
+    performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+^L
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+^L
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James
+  Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+

+ 6 - 0
adplug/NOTES/NOTES

@@ -0,0 +1,6 @@
+The source files are based on AdPlug 2.1. All players other than the
+RIX player are removed.
+
+-Wei Mingzhi
+
+9/17/2011: Added OPL code from DOSBOX.

+ 86 - 0
adplug/NOTES/README

@@ -0,0 +1,86 @@
+AdPlug - A free AdLib sound player library
+Copyright (C) 1999 - 2007 Simon Peter, et al.
+
+Website: http://adplug.sourceforge.net/
+
+Description:
+------------
+AdPlug is a free, multi-platform, hardware independent AdLib sound
+player library, mainly written in C++. AdPlug plays sound data,
+originally created for the AdLib (OPL2/3) audio board, on top of an
+OPL2/3 emulator or by using the real hardware. No OPL2/3 chips are
+required for playback.
+
+Supported platforms:
+--------------------
+AdPlug currently is tested to compile and run well on the following
+platforms and compilers:
+
+Platform                Operating System        Compiler
+--------                ----------------        --------
+IA32 - x86              Windows XP              MinGW 3.4
+                        MS-DOS 6.22             DJGPP 4.0
+                        Linux 2.6               GCC 4.1
+
+This list only incorporates platforms on which this release of AdPlug has
+been tested successfully. This and/or earlier versions of AdPlug may and did
+run on a variety of other platforms as well. It just means they haven't been
+explicitly tested for this release.
+
+The library builds as dynamic and/or static link library, depending on
+the facilities provided by the host OS. These are autodetected.
+
+Prerequisites:
+--------------
+AdPlug depends upon the following libraries:
+
+Library:	Version:
+--------	--------
+libbinio	>= 1.4
+
+libbinio can be obtained from http://libbinio.sourceforge.net/.
+
+Installation:
+-------------
+Please refer to the INSTALL file for installation instructions.
+
+CVS:
+----
+If you checked out from CVS, please first run:
+
+autoreconf --install
+
+to generate the build cruft and get the configure script. Oh, and did i
+mention you need recent versions of autoconf, automake and libtool?
+
+When building a CVS version, always supply the --enable-maintainer-mode
+option to the configure script!
+
+Debugging AdPlug:
+-----------------
+If you feel you have to debug AdPlug, you can compile it with debug logging
+support. This is disabled by default. To enable it, you have to define the
+DEBUG preprocessor macro. This is done by passing the '--enable-debug'
+commandline option to the 'configure' script to enable debugging.
+
+AdPlug logs to stderr by default. The output can be redirected anytime to a
+user specified logfile. This is done by using the 'CAdPlug::debug_output'
+method of the 'CAdPlug' class.
+
+The emulator license issue:
+---------------------------
+AdPlug uses MAME's fmopl OPL2 emulator. While this official distribution
+includes an old LGPL'd version of the emulator, which was developed by
+Tatsuyuki Satoh alone, who relicensed this version under the LGPL, there is
+a patch available at:
+
+http://www.informatik.uni-oldenburg.de/~dyna/adplug/
+
+that replaces the old version by the latest version from the MAME source
+distribution. The new version features improved emulation quality, but is
+licensed under the MAME license, which restricts commercial redistribution.
+
+The same goes for the OPL3 emulator, which requires the new version of
+the OPL2 emulator to build.
+
+	- Simon Peter <dn.tlp@gmx.net>

+ 253 - 0
adplug/binfile.cpp

@@ -0,0 +1,253 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * binfile.h - Binary file I/O
+ * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "binfile.h"
+
+/***** binfbase *****/
+
+binfbase::binfbase()
+      : f(NULL) {
+}
+
+binfbase::~binfbase() {
+   if (f != NULL) close();
+}
+
+void binfbase::close() {
+   if (f != NULL) {
+      if (fclose(f) == EOF) err |= Fatal;
+      else f = NULL;
+   } else
+      err |= NotOpen;
+}
+
+void binfbase::seek(long pos, Offset offs) {
+   int error = -1;
+
+   if (f == NULL) {
+      err |= NotOpen;
+      return;
+   }
+
+   switch (offs) {
+   case Set:
+      error = fseek(f, pos, SEEK_SET);
+      break;
+   case Add:
+      error = fseek(f, pos, SEEK_CUR);
+      break;
+   case End:
+      error = fseek(f, pos, SEEK_END);
+      break;
+   }
+
+   if (error == -1)
+      err |= Fatal;
+}
+
+long binfbase::pos() {
+   long pos;
+
+   if (f == NULL) {
+      err |= NotOpen;
+      return 0;
+   }
+
+   pos = ftell(f);
+
+   if (pos == -1) {
+      err |= Fatal;
+      return 0;
+   } else
+      return pos;
+}
+
+/***** binifstream *****/
+
+binifstream::binifstream() {
+}
+
+binifstream::binifstream(const char *filename, const Mode mode) {
+   open(filename, mode);
+}
+
+#if BINIO_ENABLE_STRING
+binifstream::binifstream(const std::string &filename, const Mode mode) {
+   open(filename, mode);
+}
+#endif
+
+binifstream::~binifstream() {
+}
+
+void binifstream::open(const char *filename, const Mode mode) {
+   f = fopen(filename, "rb");
+
+   if (f == NULL)
+      switch (errno) {
+      case ENOENT:
+         err |= NotFound;
+         break;
+      case EACCES:
+         err |= Denied;
+         break;
+      default:
+         err |= NotOpen;
+         break;
+      }
+}
+
+#if BINIO_ENABLE_STRING
+void binifstream::open(const std::string &filename, const Mode mode) {
+   open(filename.c_str(), mode);
+}
+#endif
+
+binifstream::Byte binifstream::getByte() {
+   int read;
+
+   if (f != NULL) {
+      read = fgetc(f);
+      if (read == EOF) err |= Eof;
+      return (Byte)read;
+   } else {
+      err |= NotOpen;
+      return 0;
+   }
+}
+
+/***** binofstream *****/
+
+binofstream::binofstream() {
+}
+
+binofstream::binofstream(const char *filename, const Mode mode) {
+   open(filename, mode);
+}
+
+#if BINIO_ENABLE_STRING
+binofstream::binofstream(const std::string &filename, const Mode mode) {
+   open(filename, mode);
+}
+#endif
+
+binofstream::~binofstream() {
+}
+
+void binofstream::open(const char *filename, const Mode mode) {
+   char modestr[] = "wb";
+
+   // Check if append mode is desired
+   if (mode & Append) modestr[0] = 'a';
+
+   f = fopen(filename, modestr);
+
+   if (f == NULL)
+      switch (errno) {
+      case EEXIST:
+      case EACCES:
+      case EROFS:
+         err |= Denied;
+         break;
+      case ENOENT:
+         err |= NotFound;
+         break;
+      default:
+         err |= NotOpen;
+         break;
+      }
+}
+
+#if BINIO_ENABLE_STRING
+void binofstream::open(const std::string &filename, const Mode mode) {
+   open(filename.c_str(), mode);
+}
+#endif
+
+void binofstream::putByte(Byte b) {
+   if (f == NULL) {
+      err |= NotOpen;
+      return;
+   }
+
+   if (fputc(b, f) == EOF)
+      err |= Fatal;
+}
+
+/***** binfstream *****/
+
+binfstream::binfstream() {
+}
+
+binfstream::binfstream(const char *filename, const Mode mode) {
+   open(filename, mode);
+}
+
+#if BINIO_ENABLE_STRING
+binfstream::binfstream(const std::string &filename, const Mode mode) {
+   open(filename, mode);
+}
+#endif
+
+binfstream::~binfstream() {
+}
+
+void binfstream::open(const char *filename, const Mode mode) {
+   char modestr[] = "w+b";	// Create & at beginning
+   int	ferror = 0;
+
+   // Apply desired mode
+   if (mode & NoCreate) {
+      if (!(mode & Append))
+         modestr[0] = 'r';	// NoCreate & at beginning
+   } else
+      if (mode & Append)	// Create & append
+         modestr[0] = 'a';
+
+   f = fopen(filename, modestr);
+
+   // NoCreate & append (emulated -- not possible with standard C fopen())
+   if (f != NULL && (mode & Append) && (mode & NoCreate))
+      ferror = fseek(f, 0, SEEK_END);
+
+   if (f == NULL || ferror == -1) {
+      switch (errno) {
+      case EEXIST:
+      case EACCES:
+      case EROFS:
+         err |= Denied;
+         break;
+      case ENOENT:
+         err |= NotFound;
+         break;
+      default:
+         err |= NotOpen;
+         break;
+      }
+   }
+}
+
+#if BINIO_ENABLE_STRING
+void binfstream::open(const std::string &filename, const Mode mode) {
+   open(filename.c_str(), mode);
+}
+#endif

+ 111 - 0
adplug/binfile.h

@@ -0,0 +1,111 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * binfile.h - Binary file I/O
+ * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_BINIO_BINFILE
+#define H_BINIO_BINFILE
+
+#include <stdio.h>
+
+#include "binio.h"
+
+#ifdef _MSC_VER
+#pragma warning (disable:4244)
+#pragma warning (disable:4996)
+#endif
+
+class binfbase: virtual public binio {
+public:
+   typedef enum {
+      Append	= 1 << 0,
+      NoCreate	= 1 << 1
+   } ModeFlags;
+
+   typedef int Mode;
+
+   binfbase();
+   virtual ~binfbase();
+
+   virtual void open(const char *filename, const Mode mode) = 0;
+#if BINIO_ENABLE_STRING
+   virtual void open(const std::string &filename, const Mode mode) = 0;
+#endif
+   void close();
+
+   virtual void seek(long pos, Offset offs = Set);
+   virtual long pos();
+
+protected:
+   FILE *f;
+};
+
+class binifstream: public binistream, virtual public binfbase {
+public:
+   binifstream();
+   binifstream(const char *filename, const Mode mode = NoCreate);
+#if BINIO_ENABLE_STRING
+   binifstream(const std::string &filename, const Mode mode = NoCreate);
+#endif
+
+   virtual ~binifstream();
+
+   virtual void open(const char *filename, const Mode mode = NoCreate);
+#if BINIO_ENABLE_STRING
+   virtual void open(const std::string &filename, const Mode mode = NoCreate);
+#endif
+
+protected:
+   virtual Byte getByte();
+};
+
+class binofstream: public binostream, virtual public binfbase {
+public:
+   binofstream();
+   binofstream(const char *filename, const Mode mode = 0);
+#if BINIO_ENABLE_STRING
+   binofstream(const std::string &filename, const Mode mode = 0);
+#endif
+
+   virtual ~binofstream();
+
+   virtual void open(const char *filename, const Mode mode = 0);
+#if BINIO_ENABLE_STRING
+   virtual void open(const std::string &filename, const Mode mode = 0);
+#endif
+
+protected:
+   virtual void putByte(Byte b);
+};
+
+class binfstream: public binifstream, public binofstream {
+public:
+   binfstream();
+   binfstream(const char *filename, const Mode mode = 0);
+#if BINIO_ENABLE_STRING
+   binfstream(const std::string &filename, const Mode mode = 0);
+#endif
+
+   virtual ~binfstream();
+
+   virtual void open(const char *filename, const Mode mode = 0);
+#if BINIO_ENABLE_STRING
+   virtual void open(const std::string &filename, const Mode mode = 0);
+#endif
+};
+
+#endif

+ 655 - 0
adplug/binio.cpp

@@ -0,0 +1,655 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * binio.cpp - Binary stream I/O classes
+ * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
+ */
+
+#include <string.h>
+
+#include "binio.h"
+
+#if BINIO_WITH_MATH
+
+#include <math.h>
+
+#ifdef __QNXNTO__
+#define pow std::powf
+#endif // __QNXNTO__
+
+// If 'math.h' doesn't define HUGE_VAL, we try to use HUGE instead.
+#ifndef HUGE_VAL
+# define HUGE_VAL HUGE
+#endif
+
+#endif
+
+/***** Defines *****/
+
+#if BINIO_ENABLE_STRING
+// String buffer size for std::string readString() method
+#define STRINGBUFSIZE	256
+#endif
+
+/***** binio *****/
+
+const binio::Flags binio::system_flags = binio::detect_system_flags();
+
+const binio::Flags binio::detect_system_flags() {
+   Flags f = 0;
+
+   // Endian test
+   union {
+      int word;
+      Byte byte;
+   } endian_test;
+
+   endian_test.word = 1;
+   if (endian_test.byte != 1) f |= BigEndian;
+
+   // IEEE-754 floating-point test
+   float fl = 6.5;
+   Byte	*dat = (Byte *)&fl;
+
+   if (sizeof(float) == 4 && sizeof(double) == 8) {
+      if (f & BigEndian) {
+         if (dat[0] == 0x40 && dat[1] == 0xD0 && !dat[2] && !dat[3])
+            f |= FloatIEEE;
+      } else {
+         if (dat[3] == 0x40 && dat[2] == 0xD0 && !dat[1] && !dat[0])
+            f |= FloatIEEE;
+      }
+   }
+   return f;
+}
+
+binio::binio()
+      : my_flags(system_flags), err(NoError) {
+}
+
+binio::~binio() {
+}
+
+void binio::setFlag(Flag f, bool set) {
+   if (set)
+      my_flags |= f;
+   else
+      my_flags &= !f;
+}
+
+bool binio::getFlag(Flag f) {
+   return (my_flags & f ? true : false);
+}
+
+binio::Error binio::error() {
+   Error e = err;
+
+   err = NoError;
+   return e;
+}
+
+bool binio::eof() {
+   return (err & Eof ? true : false);
+}
+
+/***** binistream *****/
+
+binistream::binistream() {
+}
+
+binistream::~binistream() {
+}
+
+binistream::Int binistream::readInt(unsigned int size) {
+   unsigned int	i;
+   Int		val = 0, in;
+
+   // Check if 'size' doesn't exceed our system's biggest type.
+   if (size > sizeof(Int)) {
+      err |= Unsupported;
+      return 0;
+   }
+
+   for (i = 0; i < size; i++) {
+      in = getByte();
+      if (getFlag(BigEndian))
+         val <<= 8;
+      else
+         in <<= i * 8;
+      val |= in;
+   }
+
+   return val;
+}
+
+binistream::Float binistream::readFloat(FType ft) {
+   if (getFlag(FloatIEEE)) {	// Read IEEE-754 floating-point value
+      unsigned int	i, size = 0;
+      Byte		in[8];
+      bool		swap;
+
+      // Determine appropriate size for given type.
+      switch (ft) {
+      case Single:
+         size = 4;
+         break;	// 32 bits
+      case Double:
+         size = 8;
+         break;	// 64 bits
+      }
+
+      // Determine byte ordering, depending on what we do next
+      if (system_flags & FloatIEEE)
+         swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
+      else
+         swap = !getFlag(BigEndian);
+
+      // Read the float byte by byte, converting endianess
+      for (i = 0; i < size; i++)
+         if (swap)
+            in[size - i - 1] = getByte();
+         else
+            in[i] = getByte();
+
+      if (system_flags & FloatIEEE) {
+         // Compatible system, let the hardware do the conversion
+         switch (ft) {
+         case Single:
+            return *reinterpret_cast<float *>(in);
+         case Double:
+            return *reinterpret_cast<double *>(in);
+         }
+      } else {	// Incompatible system, convert manually
+         switch (ft) {
+         case Single:
+            return ieee_single2float(in);
+         case Double:
+            return ieee_double2float(in);
+         }
+      }
+   }
+
+   // User tried to read a (yet) unsupported floating-point type. Bail out.
+   err |= Unsupported;
+   return 0.0;
+}
+
+binistream::Float binistream::ieee_single2float(Byte *data) {
+   signed int	sign = data[0] >> 7 ? -1 : 1;
+   unsigned int	exp = ((data[0] << 1) & 0xff) | ((data[1] >> 7) & 1),
+                      fracthi7 = data[1] & 0x7f;
+   Float		fract = fracthi7 * 65536.0 + data[2] * 256.0 + data[3];
+
+   // Signed and unsigned zero
+   if (!exp && !fracthi7 && !data[2] && !data[3]) return sign * 0.0;
+
+   // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
+   if (exp == 255) {
+      if (!fracthi7 && !data[2] && !data[3]) {
+#ifdef HUGE_VAL
+         if (sign == -1) return -HUGE_VAL;
+         else return HUGE_VAL;
+#else
+         err |= Unsupported;
+         if (sign == -1) return -1.0;
+         else return 1.0;
+#endif
+      } else {	  // Not a number (maybe unsupported on non-IEEE systems)
+#ifdef NAN
+         return NAN;
+#else
+         err |= Unsupported;
+         return 0.0;
+#endif
+      }
+   }
+
+   if (!exp)	// Unnormalized float values
+      return sign * pow(2.0f, -126.0f) * fract * pow(2.0f, -23.0f);
+   else		// Normalized float values
+      return sign * pow(2.0f, exp - 127.0f) * (fract * pow(2.0f, -23.0f) + 1);
+
+   err |= Fatal;
+   return 0.0;
+}
+
+binistream::Float binistream::ieee_double2float(Byte *data) {
+   signed int	sign = data[0] >> 7 ? -1 : 1;
+   unsigned int	exp = ((unsigned int)(data[0] & 0x7f) << 4) | (data[1] >> 4),
+                      fracthi4 = data[1] & 0xf;
+   Float		fract = fracthi4 * pow(2.0f, 48.0f) + data[2] * pow(2.0f, 40.0f) + data[3] *
+                  pow(2.0f, 32.0f) + data[4] * pow(2.0f, 24.0f) + data[5] * pow(2.0f, 16.0f) + data[6] *
+                  pow(2.0f, 8.0f) + data[7];
+
+   // Signed and unsigned zero
+   if (!exp && !fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] &&
+         !data[6] && !data[7]) return sign * 0.0;
+
+   // Signed and unsigned infinity  (maybe unsupported on non-IEEE systems)
+   if (exp == 2047) {
+      if (!fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] && !data[6] && !data[7]) {
+#ifdef HUGE_VAL
+         if (sign == -1) return -HUGE_VAL;
+         else return HUGE_VAL;
+#else
+         err |= Unsupported;
+         if (sign == -1) return -1.0;
+         else return 1.0;
+#endif
+      } else {	  // Not a number (maybe unsupported on non-IEEE systems)
+#ifdef NAN
+         return NAN;
+#else
+         err |= Unsupported;
+         return 0.0;
+#endif
+      }
+   }
+
+   if (!exp)	// Unnormalized float values
+      return sign * pow(2.0f, -1022.0f) * fract * pow(2.0f, -52.0f);
+   else		// Normalized float values
+      return sign * pow(2.0f, exp - 1023.0f) * (fract * pow(2.0f, -52.0f) + 1);
+
+   err |= Fatal;
+   return 0.0;
+}
+
+#if !BINIO_WITH_MATH
+binio::Float binio::pow(Float base, signed int exp)
+/* Our own, stripped-down version of pow() for not having to depend on 'math.h'.
+ * This one handles float values for the base and an integer exponent, both
+ * positive and negative.
+ */
+{
+   int	i;
+   Float	val = base;
+
+   if (!exp) return 1.0;
+
+   for (i = 1; i < (exp < 0 ? -exp : exp); i++)
+      val *= base;
+
+   if (exp < 0) val = 1.0 / val;
+
+   return val;
+}
+#endif
+
+unsigned long binistream::readString(char *str, unsigned long maxlen) {
+   unsigned long	i;
+
+   for (i = 0; i < maxlen; i++) {
+      str[i] = (char)getByte();
+      if (err) {
+         str[i] = '\0';
+         return i;
+      }
+   }
+
+   return maxlen;
+}
+
+unsigned long binistream::readString(char *str, unsigned long maxlen,
+                                     const char delim) {
+   unsigned long i;
+
+   for (i = 0; i < maxlen; i++) {
+      str[i] = (char)getByte();
+      if (str[i] == delim || err) {
+         str[i] = '\0';
+         return i;
+      }
+   }
+
+   str[maxlen] = '\0';
+   return maxlen;
+}
+
+#if BINIO_ENABLE_STRING
+std::string binistream::readString(const char delim) {
+   char buf[STRINGBUFSIZE + 1];
+   std::string tempstr;
+   unsigned long read;
+
+   do {
+      read = readString(buf, STRINGBUFSIZE, delim);
+      tempstr.append(buf, read);
+   } while (read == STRINGBUFSIZE);
+
+   return tempstr;
+}
+#endif
+
+binistream::Int binistream::peekInt(unsigned int size) {
+   Int val = readInt(size);
+   if (!err) seek(-(long)size, Add);
+   return val;
+}
+
+binistream::Float binistream::peekFloat(FType ft) {
+   Float val = readFloat(ft);
+
+   if (!err)
+      switch (ft) {
+      case Single:
+         seek(-4, Add);
+         break;
+      case Double:
+         seek(-8, Add);
+         break;
+      }
+
+   return val;
+}
+
+bool binistream::ateof() {
+   Error	olderr = err;	// Save current error state
+   bool	eof_then;
+
+   peekInt(1);
+   eof_then = eof();	// Get error state of next byte
+   err = olderr;		// Restore original error state
+   return eof_then;
+}
+
+void binistream::ignore(unsigned long amount) {
+   unsigned long i;
+
+   for (i = 0; i < amount; i++)
+      getByte();
+}
+
+/***** binostream *****/
+
+binostream::binostream() {
+}
+
+binostream::~binostream() {
+}
+
+void binostream::writeInt(Int val, unsigned int size) {
+   unsigned int	i;
+
+   // Check if 'size' doesn't exceed our system's biggest type.
+   if (size > sizeof(Int)) {
+      err |= Unsupported;
+      return;
+   }
+
+   for (i = 0; i < size; i++) {
+      if (getFlag(BigEndian))
+         putByte((val >> (size - i - 1) * 8) & 0xff);
+      else {
+         putByte(val & 0xff);
+         val >>= 8;
+      }
+   }
+}
+
+void binostream::writeFloat(Float f, FType ft) {
+   if (getFlag(FloatIEEE)) {	// Write IEEE-754 floating-point value
+      unsigned int	i, size = 0;
+      Byte		*out = NULL;
+      bool		swap;
+
+      if (system_flags & FloatIEEE) {
+         // compatible system, let the hardware do the conversion
+         float	outf = f;
+         double	outd = f;
+
+         // Hardware could be big or little endian, convert appropriately
+         swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
+
+         // Determine appropriate size for given type and convert by hardware
+         switch (ft) {
+         case Single:
+            size = 4;
+            out = (Byte *)&outf;
+            break;	// 32 bits
+         case Double:
+            size = 8;
+            out = (Byte *)&outd;
+            break;	// 64 bits
+         }
+      } else {
+#if BINIO_WITH_MATH
+         // incompatible system, do the conversion manually
+         Byte	buf[8];
+
+         // Our own value is always big endian, just check whether we have to
+         // convert for a different stream format.
+         swap = !getFlag(BigEndian);
+
+         // Convert system's float to requested IEEE-754 float
+         switch (ft) {
+         case Single:
+            size = 4;
+            float2ieee_single(f, buf);
+            break;
+         case Double:
+            size = 8;
+            float2ieee_double(f, buf);
+            break;
+         }
+
+         out = buf;	// Make the value ready for writing
+#else
+         // No necessary support routines to do the conversion, bail out!
+         err |= Unsupported;
+         return;
+#endif
+      }
+
+      // Write the float byte by byte, converting endianess
+      if (swap) out += size - 1;
+      for (i = 0; i < size; i++) {
+         putByte(*out);
+         if (swap) out--;
+         else out++;
+      }
+
+      return;	// We're done.
+   }
+
+   // User tried to write an unsupported floating-point type. Bail out.
+   err |= Unsupported;
+}
+
+#ifdef BINIO_WITH_MATH
+
+/*
+ * Single and double floating-point to IEEE-754 equivalent conversion functions
+ * courtesy of Ken Turkowski.
+ *
+ * Copyright (C) 1989-1991 Ken Turkowski. <turk@computer.org>
+ *
+ * All rights reserved.
+ *
+ * Warranty Information
+ *  Even though I have reviewed this software, I make no warranty
+ *  or representation, either express or implied, with respect to this
+ *  software, its quality, accuracy, merchantability, or fitness for a
+ *  particular purpose.  As a result, this software is provided "as is,"
+ *  and you, its user, are assuming the entire risk as to its quality
+ *  and accuracy.
+ *
+ * This code may be used and freely distributed as long as it includes
+ * this copyright notice and the above warranty information.
+ */
+
+/****************************************************************
+ * The following two routines make up for deficiencies in many
+ * compilers to convert properly between unsigned integers and
+ * floating-point.  Some compilers which have this bug are the
+ * THINK_C compiler for the Macintosh and the C compiler for the
+ * Silicon Graphics MIPS-based Iris.
+ ****************************************************************/
+
+#ifdef applec	/* The Apple C compiler works */
+# define FloatToUnsigned(f)	((unsigned long)(f))
+#else
+# define FloatToUnsigned(f)	((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
+#endif
+
+#define SEXP_MAX	255
+#define SEXP_OFFSET	127
+#define SEXP_SIZE	8
+#define SEXP_POSITION	(32-SEXP_SIZE-1)
+
+void binostream::float2ieee_single(Float num, Byte *bytes) {
+   long		sign;
+   register long	bits;
+
+   if (num < 0) {	/* Can't distinguish a negative zero */
+      sign = 0x80000000;
+      num *= -1;
+   } else {
+      sign = 0;
+   }
+
+   if (num == 0) {
+      bits = 0;
+   } else {
+      Float	fMant;
+      int		expon;
+
+      fMant = frexp(num, &expon);
+
+      if ((expon > (SEXP_MAX-SEXP_OFFSET+1)) || !(fMant < 1)) {
+         /* NaN's and infinities fail second test */
+         bits = sign | 0x7F800000;		/* +/- infinity */
+      }
+
+      else {
+         long mantissa;
+
+         if (expon < -(SEXP_OFFSET-2)) {	/* Smaller than normalized */
+            int shift = (SEXP_POSITION+1) + (SEXP_OFFSET-2) + expon;
+            if (shift < 0) {	/* Way too small: flush to zero */
+               bits = sign;
+            } else {			/* Nonzero denormalized number */
+               mantissa = (long)(fMant * (1L << shift));
+               bits = sign | mantissa;
+            }
+         }
+
+         else {				/* Normalized number */
+            mantissa = (long)floor(fMant * (1L << (SEXP_POSITION+1)));
+            mantissa -= (1L << SEXP_POSITION);			/* Hide MSB */
+            bits = sign | ((long)((expon + SEXP_OFFSET - 1)) << SEXP_POSITION) | mantissa;
+         }
+      }
+   }
+
+   bytes[0] = bits >> 24;	/* Copy to byte string */
+   bytes[1] = bits >> 16;
+   bytes[2] = bits >> 8;
+   bytes[3] = bits;
+}
+
+#define DEXP_MAX	2047
+#define DEXP_OFFSET	1023
+#define DEXP_SIZE	11
+#define DEXP_POSITION	(32-DEXP_SIZE-1)
+
+void binostream::float2ieee_double(Float num, Byte *bytes) {
+   long	sign;
+   long	first, second;
+
+   if (num < 0) {	/* Can't distinguish a negative zero */
+      sign = 0x80000000;
+      num *= -1;
+   } else {
+      sign = 0;
+   }
+
+   if (num == 0) {
+      first = 0;
+      second = 0;
+   } else {
+      Float	fMant, fsMant;
+      int		expon;
+
+      fMant = frexp(num, &expon);
+
+      if ((expon > (DEXP_MAX-DEXP_OFFSET+1)) || !(fMant < 1)) {
+         /* NaN's and infinities fail second test */
+         first = sign | 0x7FF00000;		/* +/- infinity */
+         second = 0;
+      }
+
+      else {
+         long mantissa;
+
+         if (expon < -(DEXP_OFFSET-2)) {	/* Smaller than normalized */
+            int shift = (DEXP_POSITION+1) + (DEXP_OFFSET-2) + expon;
+            if (shift < 0) {	/* Too small for something in the MS word */
+               first = sign;
+               shift += 32;
+               if (shift < 0) {	/* Way too small: flush to zero */
+                  second = 0;
+               } else {			/* Pretty small demorn */
+                  second = FloatToUnsigned(floor(ldexp(fMant, shift)));
+               }
+            } else {			/* Nonzero denormalized number */
+               fsMant = ldexp(fMant, shift);
+               mantissa = (long)floor(fsMant);
+               first = sign | mantissa;
+               second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
+            }
+         }
+
+         else {				/* Normalized number */
+            fsMant = ldexp(fMant, DEXP_POSITION+1);
+            mantissa = (long)floor(fsMant);
+            mantissa -= (1L << DEXP_POSITION);			/* Hide MSB */
+            fsMant -= (1L << DEXP_POSITION);
+            first = sign | ((long)((expon + DEXP_OFFSET - 1)) << DEXP_POSITION) | mantissa;
+            second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
+         }
+      }
+   }
+
+   bytes[0] = first >> 24;
+   bytes[1] = first >> 16;
+   bytes[2] = first >> 8;
+   bytes[3] = first;
+   bytes[4] = second >> 24;
+   bytes[5] = second >> 16;
+   bytes[6] = second >> 8;
+   bytes[7] = second;
+}
+
+#endif // BINIO_WITH_MATH
+
+unsigned long binostream::writeString(const char *str, unsigned long amount) {
+   unsigned int i;
+
+   if (!amount) amount = strlen(str);
+
+   for (i = 0; i < amount; i++) {
+      putByte(str[i]);
+      if (err) return i;
+   }
+
+   return amount;
+}
+
+#if BINIO_ENABLE_STRING
+unsigned long binostream::writeString(const std::string &str) {
+   return writeString(str.c_str());
+}
+#endif

+ 180 - 0
adplug/binio.h

@@ -0,0 +1,180 @@
+/* -*-C++-*-
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * binio.h - Binary stream I/O classes
+ * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_BINIO_BINIO
+#define H_BINIO_BINIO
+
+#ifdef _MSC_VER
+#pragma warning (disable:4244)
+#pragma warning (disable:4996)
+#pragma warning (disable:4267)
+#endif
+
+/***** Configuration *****/
+
+// BINIO_ENABLE_STRING - Build std::string supporting methods
+//
+// Set to 1 to build std::string supporting methods. You need the STL to
+// do this.
+#define BINIO_ENABLE_STRING	1
+
+// BINIO_ENABLE_IOSTREAM - Build iostream wrapper classes
+//
+// Set to 1 to build the iostream wrapper classes. You need the standard
+// C++ library to do this.
+#define BINIO_ENABLE_IOSTREAM	1
+
+// BINIO_ISO_STDLIB - Build with ISO C++ standard library compliance
+//
+// Set to 1 to build for the ISO standard C++ library (i.e. namespaces, STL and
+// templatized iostream). Set to 0 to build for the traditional C++ library.
+#define BINIO_ISO_STDLIB	1
+
+// BINIO_WITH_MATH - Build with 'math.h' dependency to allow float conversions
+//
+// Set to 1 to also build routines that depend on the 'math.h' standard C header
+// file (this sometimes also implies a 'libm' or 'libmath' dependency). These
+// routines are needed in order to write IEEE-754 floating-point numbers on a
+// system that doesn't support this format natively. For only reading these
+// numbers, however, these routines are not needed. If set to 0, writing
+// IEEE-754 numbers on an incompatible system will be disabled.
+//#define BINIO_WITH_MATH		1
+
+/***** Implementation *****/
+
+#ifdef _MSC_VER
+#	pragma warning(disable: 4250)
+#else
+#   define __int64 long long
+#endif
+
+#if BINIO_ENABLE_STRING
+#include <string>
+#endif
+
+class binio {
+public:
+   typedef enum {
+      BigEndian	= 1 << 0,
+      FloatIEEE	= 1 << 1
+   } Flag;
+
+   typedef enum {
+      NoError	= 0,
+      Fatal	= 1 << 0,
+      Unsupported	= 1 << 1,
+      NotOpen	= 1 << 2,
+      Denied	= 1 << 3,
+      NotFound	= 1 << 4,
+      Eof		= 1 << 5
+   } ErrorCode;
+
+   typedef enum { Set, Add, End } Offset;
+   typedef enum { Single, Double } FType;
+   typedef int Error;
+
+   binio();
+   virtual ~binio();
+
+   void setFlag(Flag f, bool set = true);
+   bool getFlag(Flag f);
+
+   Error error();
+   bool eof();
+
+   virtual void seek(long, Offset = Set) = 0;
+   virtual long pos() = 0;
+
+protected:
+   typedef __int64        Int;
+   typedef long double    Float;
+   typedef unsigned char  Byte; // has to be unsigned!
+
+   typedef int		Flags;
+
+   Flags			my_flags;
+   static const Flags	system_flags;
+   Error			err;
+
+   // Some math.h emulation functions...
+#if !BINIO_WITH_MATH
+   Float pow(Float base, signed int exp);
+   Float ldexp(Float x, signed int exp) {
+      return x * pow(2, exp);
+   }
+#endif
+
+private:
+   static const Flags detect_system_flags();
+};
+
+class binistream: virtual public binio {
+public:
+   binistream();
+   virtual ~binistream();
+
+   Int readInt(unsigned int size);
+   Float readFloat(FType ft);
+   unsigned long readString(char *str, unsigned long amount);
+   unsigned long readString(char *str, unsigned long maxlen, const char delim);
+#if BINIO_ENABLE_STRING
+   std::string readString(const char delim = '\0');
+#endif
+
+   Int peekInt(unsigned int size);
+   Float peekFloat(FType ft);
+
+   bool ateof();
+   void ignore(unsigned long amount = 1);
+
+protected:
+   virtual Byte getByte() = 0;
+
+private:
+   Float ieee_single2float(Byte *data);
+   Float ieee_double2float(Byte *data);
+};
+
+class binostream: virtual public binio {
+public:
+   binostream();
+   virtual ~binostream();
+
+   void writeInt(Int val, unsigned int size);
+   void writeFloat(Float f, FType ft);
+   unsigned long writeString(const char *str, unsigned long amount = 0);
+#if BINIO_ENABLE_STRING
+   unsigned long writeString(const std::string &str);
+#endif
+
+protected:
+   virtual void putByte(Byte) = 0;
+
+private:
+   void float2ieee_single(Float f, Byte *data);
+   void float2ieee_double(Float f, Byte *data);
+};
+
+class binstream: public binistream, public binostream {
+public:
+   binstream();
+   virtual ~binstream();
+};
+
+#endif

+ 75 - 0
adplug/demuopl.h

@@ -0,0 +1,75 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * demuopl.h - Emulated OPL using DOSBOX's emulator, by Wei Mingzhi
+ *             <whistler_wmz@users.sf.net>.
+ */
+
+#ifndef H_ADPLUG_DEMUOPL
+#define H_ADPLUG_DEMUOPL
+
+#include "opl.h"
+#include "dosbox_opl.h"
+
+#include <assert.h>
+
+class CDemuopl: public Copl
+{
+public:
+  CDemuopl(int rate, bool bit16, bool usestereo)
+	  :use16bit(bit16), stereo(usestereo)
+    {
+      adlib_init(rate);
+      currType = TYPE_OPL2;
+    };
+
+  void update(short *buf, int samples)
+    {
+      short *mixbuf0 = new short[samples*2],*mixbuf1 = new short[samples*2];
+      short *outbuf;
+      if(use16bit) outbuf = buf;
+      else outbuf = mixbuf1;
+      //if(use16bit) samples *= 2;
+      //if(stereo) samples *= 2;
+      adlib_getsample(outbuf, samples);
+      if(stereo)
+	for(int i=samples-1;i>=0;i--) {
+	  outbuf[i*2] = outbuf[i];
+	  outbuf[i*2+1] = outbuf[i];
+	}
+      //now reduce to 8bit if we need to
+      if(!use16bit)
+	for(int i=0;i<(stereo ? samples*2 : samples);i++)
+	  ((char *)buf)[i] = (outbuf[i] >> 8) ^ 0x80;
+      delete[] mixbuf0; delete[] mixbuf1;
+    }
+
+  // template methods
+  void write(int reg, int val)
+    {
+      if(currChip == 0)
+	adlib_write(reg, val);
+    };
+
+  void init() {};
+
+protected:
+  bool use16bit,stereo;
+};
+
+#endif

File diff suppressed because it is too large
+ 1488 - 0
adplug/dosbox_opl.cpp


+ 188 - 0
adplug/dosbox_opl.h

@@ -0,0 +1,188 @@
+/*
+ *  Copyright (C) 2002-2011  The DOSBox Team
+ *  OPL2/OPL3 emulation library
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ * 
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+/*
+ * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman
+ * Copyright (C) 1998-2001 Ken Silverman
+ * Ken Silverman's official web site: "http://www.advsys.net/ken"
+ */
+
+
+#define fltype double
+
+/*
+	define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here
+*/
+
+#ifdef _MSC_VER
+#include <windows.h>
+#define uintptr_t ULONG
+#define intptr_t LONG
+#define uint32_t DWORD
+#define int32_t INT
+#define uint16_t WORD
+#define int16_t SHORT
+#define uint8_t BYTE
+#define int8_t CHAR
+#else
+#include <stdint.h>
+#endif
+
+typedef uintptr_t	Bitu;
+typedef intptr_t	Bits;
+typedef uint32_t	Bit32u;
+typedef int32_t		Bit32s;
+typedef uint16_t	Bit16u;
+typedef int16_t		Bit16s;
+typedef uint8_t		Bit8u;
+typedef int8_t		Bit8s;
+
+
+
+/*
+	define attribution that inlines/forces inlining of a function (optional)
+*/
+#define OPL_INLINE INLINE
+
+
+#undef NUM_CHANNELS
+#if defined(OPLTYPE_IS_OPL3)
+#define NUM_CHANNELS	18
+#else
+#define NUM_CHANNELS	9
+#endif
+
+#define MAXOPERATORS	(NUM_CHANNELS*2)
+
+
+#define FL05	((fltype)0.5)
+#define FL2		((fltype)2.0)
+#define PI		((fltype)3.1415926535897932384626433832795)
+
+
+#define FIXEDPT			0x10000		// fixed-point calculations using 16+16
+#define FIXEDPT_LFO		0x1000000	// fixed-point calculations using 8+24
+
+#define WAVEPREC		1024		// waveform precision (10 bits)
+
+#define INTFREQU		((fltype)(14318180.0 / 288.0))		// clocking of the chip
+
+
+#define OF_TYPE_ATT			0
+#define OF_TYPE_DEC			1
+#define OF_TYPE_REL			2
+#define OF_TYPE_SUS			3
+#define OF_TYPE_SUS_NOKEEP	4
+#define OF_TYPE_OFF			5
+
+#define ARC_CONTROL			0x00
+#define ARC_TVS_KSR_MUL		0x20
+#define ARC_KSL_OUTLEV		0x40
+#define ARC_ATTR_DECR		0x60
+#define ARC_SUSL_RELR		0x80
+#define ARC_FREQ_NUM		0xa0
+#define ARC_KON_BNUM		0xb0
+#define ARC_PERC_MODE		0xbd
+#define ARC_FEEDBACK		0xc0
+#define ARC_WAVE_SEL		0xe0
+
+#define ARC_SECONDSET		0x100	// second operator set for OPL3
+
+
+#define OP_ACT_OFF			0x00
+#define OP_ACT_NORMAL		0x01	// regular channel activated (bitmasked)
+#define OP_ACT_PERC			0x02	// percussion channel activated (bitmasked)
+
+#define BLOCKBUF_SIZE		512
+
+
+// vibrato constants
+#define VIBTAB_SIZE			8
+#define VIBFAC				70/50000		// no braces, integer mul/div
+
+// tremolo constants and table
+#define TREMTAB_SIZE		53
+#define TREM_FREQ			((fltype)(3.7))			// tremolo at 3.7hz
+
+
+/* operator struct definition
+     For OPL2 all 9 channels consist of two operators each, carrier and modulator.
+     Channel x has operators x as modulator and operators (9+x) as carrier.
+     For OPL3 all 18 channels consist either of two operators (2op mode) or four
+     operators (4op mode) which is determined through register4 of the second
+     adlib register set.
+     Only the channels 0,1,2 (first set) and 9,10,11 (second set) can act as
+     4op channels. The two additional operators for a channel y come from the
+     2op channel y+3 so the operatorss y, (9+y), y+3, (9+y)+3 make up a 4op
+     channel.
+*/
+typedef struct operator_struct {
+	Bit32s cval, lastcval;			// current output/last output (used for feedback)
+	Bit32u tcount, wfpos, tinc;		// time (position in waveform) and time increment
+	fltype amp, step_amp;			// and amplification (envelope)
+	fltype vol;						// volume
+	fltype sustain_level;			// sustain level
+	Bit32s mfbi;					// feedback amount
+	fltype a0, a1, a2, a3;			// attack rate function coefficients
+	fltype decaymul, releasemul;	// decay/release rate functions
+	Bit32u op_state;				// current state of operator (attack/decay/sustain/release/off)
+	Bit32u toff;
+	Bit32s freq_high;				// highest three bits of the frequency, used for vibrato calculations
+	Bit16s* cur_wform;				// start of selected waveform
+	Bit32u cur_wmask;				// mask for selected waveform
+	Bit32u act_state;				// activity state (regular, percussion)
+	bool sus_keep;					// keep sustain level when decay finished
+	bool vibrato,tremolo;			// vibrato/tremolo enable bits
+	
+	// variables used to provide non-continuous envelopes
+	Bit32u generator_pos;			// for non-standard sample rates we need to determine how many samples have passed
+	Bits cur_env_step;				// current (standardized) sample position
+	Bits env_step_a,env_step_d,env_step_r;	// number of std samples of one step (for attack/decay/release mode)
+	Bit8u step_skip_pos_a;			// position of 8-cyclic step skipping (always 2^x to check against mask)
+	Bits env_step_skip_a;			// bitmask that determines if a step is skipped (respective bit is zero then)
+
+#if defined(OPLTYPE_IS_OPL3)
+	bool is_4op,is_4op_attached;	// base of a 4op channel/part of a 4op channel
+	Bit32s left_pan,right_pan;		// opl3 stereo panning amount
+#endif
+} op_type;
+
+// enable an operator
+void enable_operator(Bitu regbase, op_type* op_pt);
+
+// functions to change parameters of an operator
+void change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt);
+
+void change_attackrate(Bitu regbase, op_type* op_pt);
+void change_decayrate(Bitu regbase, op_type* op_pt);
+void change_releaserate(Bitu regbase, op_type* op_pt);
+void change_sustainlevel(Bitu regbase, op_type* op_pt);
+void change_waveform(Bitu regbase, op_type* op_pt);
+void change_keepsustain(Bitu regbase, op_type* op_pt);
+void change_vibrato(Bitu regbase, op_type* op_pt);
+void change_feedback(Bitu chanbase, op_type* op_pt);
+
+// general functions
+void adlib_init(Bit32u samplerate);
+void adlib_write(Bitu idx, Bit8u val);
+void adlib_getsample(Bit16s* sndptr, Bits numsamples);
+
+Bitu adlib_reg_read(Bitu port);
+void adlib_write_index(Bitu port, Bit8u val);

+ 146 - 0
adplug/emuopl.cpp

@@ -0,0 +1,146 @@
+/*
+ * AdPlug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2005 Simon Peter <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * emuopl.cpp - Emulated OPL, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#include "emuopl.h"
+
+CEmuopl::CEmuopl(int rate, bool bit16, bool usestereo)
+      : use16bit(bit16), stereo(usestereo), mixbufSamples(0) {
+   opl[0] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate);
+   opl[1] = OPLCreate(OPL_TYPE_YM3812, 3579545, rate);
+
+   currType = TYPE_OPL2;
+
+   init();
+}
+
+CEmuopl::~CEmuopl() {
+   OPLDestroy(opl[0]);
+   OPLDestroy(opl[1]);
+
+   if (mixbufSamples) {
+      delete [] mixbuf0;
+      delete [] mixbuf1;
+   }
+}
+
+void CEmuopl::update(short *buf, int samples) {
+   int i;
+
+   //ensure that our mix buffers are adequately sized
+   if (mixbufSamples < samples) {
+      if (mixbufSamples) {
+         delete[] mixbuf0;
+         delete[] mixbuf1;
+      }
+      mixbufSamples = samples;
+
+      //*2 = make room for stereo, if we need it
+      mixbuf0 = new short[samples*2];
+      mixbuf1 = new short[samples*2];
+   }
+
+   //data should be rendered to outbuf
+   //tempbuf should be used as a temporary buffer
+   //if we are supposed to generate 16bit output,
+   //then outbuf may point directly to the actual waveform output "buf"
+   //if we are supposed to generate 8bit output,
+   //then outbuf cannot point to "buf" (because there will not be enough room)
+   //and so it must point to a mixbuf instead--
+   //it will be reduced to 8bit and put in "buf" later
+   short *outbuf;
+   short *tempbuf=mixbuf0;
+   short *tempbuf2=mixbuf1;
+   if (use16bit) outbuf = buf;
+   else outbuf = mixbuf1;
+   //...there is a potentially confusing situation where mixbuf1 can be aliased.
+   //beware. it is a little loony.
+
+   //all of the following rendering code produces 16bit output
+
+   switch (currType) {
+   case TYPE_OPL2:
+      //for opl2 mode:
+      //render chip0 to the output buffer
+      YM3812UpdateOne(opl[0],outbuf,samples);
+
+      //if we are supposed to output stereo,
+      //then we need to dup the mono channel
+      if (stereo)
+         for (i=samples-1;i>=0;i--) {
+            outbuf[i*2] = outbuf[i];
+            outbuf[i*2+1] = outbuf[i];
+         }
+      break;
+
+   case TYPE_OPL3:	// unsupported
+      break;
+
+   case TYPE_DUAL_OPL2:
+      //for dual opl2 mode:
+      //render each chip to a different tempbuffer
+      YM3812UpdateOne(opl[0],tempbuf2,samples);
+      YM3812UpdateOne(opl[1],tempbuf,samples);
+
+      //output stereo:
+      //then we need to interleave the two buffers
+      if (stereo) {
+         //first, spread tempbuf's samples across left channel
+         //left channel
+         for (i=0;i<samples;i++)
+            outbuf[i*2] = tempbuf2[i];
+         //next, insert the samples from tempbuf2 into right channel
+         for (i=0;i<samples;i++)
+            outbuf[i*2+1] = tempbuf[i];
+      } else
+         //output mono:
+         //then we need to mix the two buffers into buf
+         for (i=0;i<samples;i++)
+            outbuf[i] = (tempbuf[i]>>1) + (tempbuf2[i]>>1);
+      break;
+   }
+
+   //now reduce to 8bit if we need to
+   if (!use16bit)
+      for (i=0;i<(stereo ? samples*2 : samples);i++)
+         ((char *)buf)[i] = (outbuf[i] >> 8) ^ 0x80;
+}
+
+void CEmuopl::write(int reg, int val) {
+   switch (currType) {
+   case TYPE_OPL2:
+   case TYPE_DUAL_OPL2:
+      OPLWrite(opl[currChip], 0, reg);
+      OPLWrite(opl[currChip], 1, val);
+      break;
+   case TYPE_OPL3:	// unsupported
+      break;
+   }
+}
+
+void CEmuopl::init() {
+   OPLResetChip(opl[0]);
+   OPLResetChip(opl[1]);
+   currChip = 0;
+}
+
+void CEmuopl::settype(ChipType type) {
+   currType = type;
+}

+ 48 - 0
adplug/emuopl.h

@@ -0,0 +1,48 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2005 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * emuopl.h - Emulated OPL, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_ADPLUG_EMUOPL
+#define H_ADPLUG_EMUOPL
+
+#include "opl.h"
+extern "C" {
+#include "fmopl.h"
+}
+
+class CEmuopl: public Copl {
+public:
+   CEmuopl(int rate, bool bit16, bool usestereo);	// rate = sample rate
+   virtual ~CEmuopl();
+
+   void update(short *buf, int samples);			// fill buffer
+   void write(int reg, int val);
+
+   void init();
+   void settype(ChipType type);
+
+private:
+   bool		use16bit, stereo;
+   FM_OPL	*opl[2];				// OPL2 emulator data
+   short		*mixbuf0, *mixbuf1;
+   int		mixbufSamples;
+};
+
+#endif

File diff suppressed because it is too large
+ 1263 - 0
adplug/fmopl.c


+ 180 - 0
adplug/fmopl.h

@@ -0,0 +1,180 @@
+#ifndef __FMOPL_H_
+#define __FMOPL_H_
+
+#ifdef _MSC_VER
+#pragma warning (disable:4018)
+#pragma warning (disable:4244)
+#pragma warning (disable:4996)
+#endif
+
+/* --- select emulation chips --- */
+#define BUILD_YM3812 (HAS_YM3812)
+//#define BUILD_YM3526 (HAS_YM3526)
+//#define BUILD_Y8950  (HAS_Y8950)
+
+/* --- system optimize --- */
+/* select bit size of output : 8 or 16 */
+#define OPL_OUTPUT_BIT 16
+
+/* compiler dependence */
+#ifndef OSD_CPU_H
+#define OSD_CPU_H
+typedef unsigned char	UINT8;   /* unsigned  8bit */
+typedef unsigned short	UINT16;  /* unsigned 16bit */
+typedef unsigned int	UINT32;  /* unsigned 32bit */
+typedef signed char		INT8;    /* signed  8bit   */
+typedef signed short	INT16;   /* signed 16bit   */
+typedef signed int		INT32;   /* signed 32bit   */
+#endif
+
+#if (OPL_OUTPUT_BIT==16)
+typedef INT16 OPLSAMPLE;
+#endif
+#if (OPL_OUTPUT_BIT==8)
+typedef unsigned char  OPLSAMPLE;
+#endif
+
+
+#if BUILD_Y8950
+#include "ymdeltat.h"
+#endif
+
+typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
+typedef void (*OPL_IRQHANDLER)(int param,int irq);
+typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
+typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
+typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
+
+/* !!!!! here is private section , do not access there member direct !!!!! */
+
+#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
+#define OPL_TYPE_ADPCM     0x02  /* DELTA-T ADPCM unit */
+#define OPL_TYPE_KEYBOARD  0x04  /* keyboard interface */
+#define OPL_TYPE_IO        0x08  /* I/O port */
+
+/* Saving is necessary for member of the 'R' mark for suspend/resume */
+/* ---------- OPL one of slot  ---------- */
+typedef struct fm_opl_slot {
+   INT32 TL;		/* total level     :TL << 8            */
+   INT32 TLL;		/* adjusted now TL                     */
+   UINT8  KSR;		/* key scale rate  :(shift down bit)   */
+   INT32 *AR;		/* attack rate     :&AR_TABLE[AR<<2]   */
+   INT32 *DR;		/* decay rate      :&DR_TALBE[DR<<2]   */
+   INT32 SL;		/* sustin level    :SL_TALBE[SL]       */
+   INT32 *RR;		/* release rate    :&DR_TABLE[RR<<2]   */
+   UINT8 ksl;		/* keyscale level  :(shift down bits)  */
+   UINT8 ksr;		/* key scale rate  :kcode>>KSR         */
+   UINT32 mul;		/* multiple        :ML_TABLE[ML]       */
+   UINT32 Cnt;		/* frequency count :                   */
+   UINT32 Incr;	/* frequency step  :                   */
+   /* envelope generator state */
+   UINT8 eg_typ;	/* envelope type flag                  */
+   UINT8 evm;		/* envelope phase                      */
+   INT32 evc;		/* envelope counter                    */
+   INT32 eve;		/* envelope counter end point          */
+   INT32 evs;		/* envelope counter step               */
+   INT32 evsa;	/* envelope step for AR :AR[ksr]           */
+   INT32 evsd;	/* envelope step for DR :DR[ksr]           */
+   INT32 evsr;	/* envelope step for RR :RR[ksr]           */
+   /* LFO */
+   UINT8 ams;		/* ams flag                            */
+   UINT8 vib;		/* vibrate flag                        */
+   /* wave selector */
+   INT32 **wavetable;
+}OPL_SLOT;
+
+/* ---------- OPL one of channel  ---------- */
+typedef struct fm_opl_channel {
+   OPL_SLOT SLOT[2];
+   UINT8 CON;			/* connection type                     */
+   UINT8 FB;			/* feed back       :(shift down bit)   */
+   INT32 *connect1;	/* slot1 output pointer                */
+   INT32 *connect2;	/* slot2 output pointer                */
+   INT32 op1_out[2];	/* slot1 output for selfeedback        */
+   /* phase generator state */
+   UINT32  block_fnum;	/* block+fnum      :                   */
+   UINT8 kcode;		/* key code        : KeyScaleCode      */
+   UINT32  fc;			/* Freq. Increment base                */
+   UINT32  ksl_base;	/* KeyScaleLevel Base step             */
+   UINT8 keyon;		/* key on/off flag                     */
+} OPL_CH;
+
+/* OPL state */
+typedef struct fm_opl_f {
+   UINT8 type;			/* chip type                         */
+   int clock;			/* master clock  (Hz)                */
+   int rate;			/* sampling rate (Hz)                */
+   double freqbase;	/* frequency base                    */
+   double TimerBase;	/* Timer base time (==sampling time) */
+   UINT8 address;		/* address register                  */
+   UINT8 status;		/* status flag                       */
+   UINT8 statusmask;	/* status mask                       */
+   UINT32 mode;		/* Reg.08 : CSM , notesel,etc.       */
+   /* Timer */
+   int T[2];			/* timer counter                     */
+   UINT8 st[2];		/* timer enable                      */
+   /* FM channel slots */
+   OPL_CH *P_CH;		/* pointer of CH                     */
+   int	max_ch;			/* maximum channel                   */
+   /* Rythm sention */
+   UINT8 rythm;		/* Rythm mode , key flag */
+#if BUILD_Y8950
+   /* Delta-T ADPCM unit (Y8950) */
+   YM_DELTAT *deltat;			/* DELTA-T ADPCM       */
+#endif
+   /* Keyboard / I/O interface unit (Y8950) */
+   UINT8 portDirection;
+   UINT8 portLatch;
+   OPL_PORTHANDLER_R porthandler_r;
+   OPL_PORTHANDLER_W porthandler_w;
+   int port_param;
+   OPL_PORTHANDLER_R keyboardhandler_r;
+   OPL_PORTHANDLER_W keyboardhandler_w;
+   int keyboard_param;
+   /* time tables */
+   INT32 AR_TABLE[75];	/* atttack rate tables */
+   INT32 DR_TABLE[75];	/* decay rate tables   */
+   UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
+   /* LFO */
+   INT32 *ams_table;
+   INT32 *vib_table;
+   INT32 amsCnt;
+   INT32 amsIncr;
+   INT32 vibCnt;
+   INT32 vibIncr;
+   /* wave selector enable flag */
+   UINT8 wavesel;
+   /* external event callback handler */
+   OPL_TIMERHANDLER  TimerHandler;		/* TIMER handler   */
+   int TimerParam;						/* TIMER parameter */
+   OPL_IRQHANDLER    IRQHandler;		/* IRQ handler    */
+   int IRQParam;						/* IRQ parameter  */
+   OPL_UPDATEHANDLER UpdateHandler;	/* stream update handler   */
+   int UpdateParam;					/* stream update parameter */
+} FM_OPL;
+
+/* ---------- Generic interface section ---------- */
+#define OPL_TYPE_YM3526 (0)
+#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
+#define OPL_TYPE_Y8950  (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
+
+FM_OPL *OPLCreate(int type, int clock, int rate);
+void OPLDestroy(FM_OPL *OPL);
+void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
+void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
+void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
+/* Y8950 port handlers */
+void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
+void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
+
+void OPLResetChip(FM_OPL *OPL);
+int OPLWrite(FM_OPL *OPL,int a,int v);
+unsigned char OPLRead(FM_OPL *OPL,int a);
+int OPLTimerOver(FM_OPL *OPL,int c);
+
+/* YM3626/YM3812 local section */
+void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
+
+void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
+
+#endif

+ 83 - 0
adplug/fprovide.cpp

@@ -0,0 +1,83 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2002 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * fprovide.cpp - File provider class framework, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#include <string.h>
+#include "binio.h"
+#include "binfile.h"
+
+#include "fprovide.h"
+
+#ifdef __SYMBIAN32__
+	#define stricmp strcasecmp
+#else 
+	#ifndef _WIN32
+		#define stricmp strcasecmp
+	#endif
+#endif
+/***** CFileProvider *****/
+
+bool CFileProvider::extension(const std::string &filename,
+                              const std::string &extension) {
+   const char *fname = filename.c_str(), *ext = extension.c_str();
+
+   if (strlen(fname) < strlen(ext) ||
+         stricmp(fname + strlen(fname) - strlen(ext), ext))
+      return false;
+   else
+      return true;
+}
+
+unsigned long CFileProvider::filesize(binistream *f) {
+   unsigned long oldpos = f->pos(), size;
+
+   f->seek(0, binio::End);
+   size = f->pos();
+   f->seek(oldpos, binio::Set);
+
+   return size;
+}
+
+/***** CProvider_Filesystem *****/
+
+binistream *CProvider_Filesystem::open(std::string filename) const {
+   binifstream *f = new binifstream(filename);
+
+   if (!f) return 0;
+   if (f->error()) {
+      delete f;
+      return 0;
+   }
+
+   // Open all files as little endian with IEEE floats by default
+   f->setFlag(binio::BigEndian, false);
+   f->setFlag(binio::FloatIEEE);
+
+   return f;
+}
+
+void CProvider_Filesystem::close(binistream *f) const {
+   binifstream *ff = (binifstream *)f;
+
+   if (f) {
+      ff->close();
+      delete ff;
+   }
+}

+ 47 - 0
adplug/fprovide.h

@@ -0,0 +1,47 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * fprovide.h - File provider class framework, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_ADPLUG_FILEPROVIDER
+#define H_ADPLUG_FILEPROVIDER
+
+#include <string>
+#include "binio.h"
+
+class CFileProvider {
+public:
+   virtual ~CFileProvider() {
+   }
+
+   virtual binistream *open(std::string) const = 0;
+   virtual void close(binistream *) const = 0;
+
+   static bool extension(const std::string &filename,
+                         const std::string &extension);
+   static unsigned long filesize(binistream *f);
+};
+
+class CProvider_Filesystem: public CFileProvider {
+public:
+   virtual binistream *open(std::string filename) const;
+   virtual void close(binistream *f) const;
+};
+
+#endif

+ 63 - 0
adplug/opl.h

@@ -0,0 +1,63 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * opl.h - OPL base class, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_ADPLUG_OPL
+#define H_ADPLUG_OPL
+
+class Copl {
+public:
+   typedef enum {
+      TYPE_OPL2, TYPE_OPL3, TYPE_DUAL_OPL2
+   } ChipType;
+
+   Copl()
+         : currChip(0), currType(TYPE_OPL2) {
+   }
+
+   virtual ~Copl() {
+   }
+
+   virtual void write(int reg, int val) {} // combined register select + data write
+   virtual void setchip(int n) { // select OPL chip
+      if (n < 2)
+         currChip = n;
+   }
+
+   virtual int getchip() { // returns current OPL chip
+      return currChip;
+   }
+
+   virtual void init(void) {} // reinitialize OPL chip(s)
+
+   // return this OPL chip's type
+   ChipType gettype() {
+      return currType;
+   }
+
+   // Emulation only: fill buffer
+   virtual void update(short *buf, int samples) {}
+
+protected:
+   int		currChip;		// currently selected OPL chip number
+   ChipType	currType;		// this OPL chip's type
+};
+
+#endif

+ 65 - 0
adplug/player.cpp

@@ -0,0 +1,65 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * player.cpp - Replayer base class, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#include "player.h"
+#include "opl.h"
+
+/***** CPlayer *****/
+
+const unsigned short CPlayer::note_table[12] =
+   {363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 686};
+
+const unsigned char CPlayer::op_table[9] =
+   {0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12};
+
+CPlayer::CPlayer(Copl *newopl)
+      : opl(newopl) {
+}
+
+CPlayer::~CPlayer() {
+}
+
+unsigned long CPlayer::songlength(int subsong) {
+   Copl    tempopl;
+   Copl   *saveopl = opl;
+   float   slength = 0.0f;
+
+   // save original OPL from being overwritten
+   opl = &tempopl;
+
+   // get song length
+   rewind(subsong);
+   while (update() && slength < 600000)	// song length limit: 10 minutes
+      slength += 1000.0f / getrefresh();
+   rewind(subsong);
+
+   // restore original OPL and return
+   opl = saveopl;
+   return (unsigned long)slength;
+}
+
+void CPlayer::seek(unsigned long ms) {
+   float pos = 0.0f;
+
+   rewind();
+   while (pos < ms && update())		// seek to new position
+      pos += 1000/getrefresh();
+}

+ 92 - 0
adplug/player.h

@@ -0,0 +1,92 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * player.h - Replayer base class, by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#ifndef H_ADPLUG_PLAYER
+#define H_ADPLUG_PLAYER
+
+#include <string>
+
+#include "fprovide.h"
+#include "opl.h"
+
+class CPlayer {
+public:
+   CPlayer(Copl *newopl);
+   virtual ~CPlayer();
+
+   /***** Operational methods *****/
+   void seek(unsigned long ms);
+
+   virtual bool load(const std::string &filename,	// loads file
+                     const CFileProvider &fp = CProvider_Filesystem()) = 0;
+   virtual bool update() = 0;			// executes replay code for 1 tick
+   virtual void rewind(int subsong = -1) = 0;	// rewinds to specified subsong
+   virtual float getrefresh() = 0;			// returns needed timer refresh rate
+
+   /***** Informational methods *****/
+   unsigned long songlength(int subsong = -1);
+
+   virtual std::string gettype() = 0;	// returns file type
+   virtual std::string gettitle() {	// returns song title
+      return std::string();
+   }
+   virtual std::string getauthor() {	// returns song author name
+      return std::string();
+   }
+   virtual std::string getdesc() {	// returns song description
+      return std::string();
+   }
+   virtual unsigned int getpatterns() {	// returns number of patterns
+      return 0;
+   }
+   virtual unsigned int getpattern() {	// returns currently playing pattern
+      return 0;
+   }
+   virtual unsigned int getorders() {	// returns size of orderlist
+      return 0;
+   }
+   virtual unsigned int getorder() {	// returns currently playing song position
+      return 0;
+   }
+   virtual unsigned int getrow() {	// returns currently playing row
+      return 0;
+   }
+   virtual unsigned int getspeed() {	// returns current song speed
+      return 0;
+   }
+   virtual unsigned int getsubsongs() {	// returns number of subsongs
+      return 1;
+   }
+   virtual unsigned int getinstruments() {	// returns number of instruments
+      return 0;
+   }
+   virtual std::string getinstrument(unsigned int n) {	// returns n-th instrument name
+      return std::string();
+   }
+
+protected:
+   Copl		*opl;	// our OPL chip
+
+   static const unsigned short	note_table[12];	// standard adlib note table
+   static const unsigned char	op_table[9];	// the 9 operators as expected by the OPL
+};
+
+#endif

+ 518 - 0
adplug/rix.cpp

@@ -0,0 +1,518 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * rix.cpp - Softstar RIX OPL Format Player by palxex <palxex.ys168.com>
+ *                                             BSPAL <BSPAL.ys168.com>
+ */
+
+#include <cstring>
+#include <cstdlib>
+#include "rix.h"
+
+using namespace std;
+
+#if !defined(_WIN32) || defined(__SYMBIAN32__)
+   #define stricmp strcasecmp
+#endif
+
+#if defined(__hppa__) || \
+   defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
+   (defined(__MIPS__) && defined(__MISPEB__)) || \
+   defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
+   defined(__sparc__)
+   // big endian
+   #define RIX_SWAP32(a) (((a) << 24) | (((a) << 8) & 0x00FF0000) | (((a) >> 8) & 0x0000FF00) | ((a) >> 24))
+#else
+   // little endian
+   #define RIX_SWAP32(a) (a)
+#endif
+
+const uint8_t CrixPlayer::adflag[] = {0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,1,1,1};
+const uint8_t CrixPlayer::reg_data[] = {0,1,2,3,4,5,8,9,10,11,12,13,16,17,18,19,20,21};
+const uint8_t CrixPlayer::ad_C0_offs[] = {0,1,2,0,1,2,3,4,5,3,4,5,6,7,8,6,7,8};
+const uint8_t CrixPlayer::modify[] = {0,3,1,4,2,5,6,9,7,10,8,11,12,15,13,16,14,17,12,\
+					    15,16,0,14,0,17,0,13,0};
+const uint8_t CrixPlayer::bd_reg_data[] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x08,0x04,0x02,0x01,
+  0x00,0x01,0x01,0x03,0x0F,0x05,0x00,0x01,0x03,0x0F,0x00,
+  0x00,0x00,0x01,0x00,0x00,0x01,0x01,0x0F,0x07,0x00,0x02,
+  0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0A,
+  0x04,0x00,0x08,0x0C,0x0B,0x00,0x00,0x00,0x01,0x00,0x00,
+  0x00,0x00,0x0D,0x04,0x00,0x06,0x0F,0x00,0x00,0x00,0x00,
+  0x01,0x00,0x00,0x0C,0x00,0x0F,0x0B,0x00,0x08,0x05,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x0F,0x0B,0x00,
+  0x07,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
+  0x0F,0x0B,0x00,0x05,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x01,0x00,0x0F,0x0B,0x00,0x07,0x05,0x00,0x00,0x00,
+  0x00,0x00,0x00};
+uint8_t CrixPlayer::for40reg[] = {0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
+					0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F};
+const uint16_t CrixPlayer::mus_time = 0x4268;
+
+/*** public methods *************************************/
+
+CPlayer *CrixPlayer::factory(Copl *newopl)
+{
+  return new CrixPlayer(newopl);
+}
+
+CrixPlayer::CrixPlayer(Copl *newopl)
+  : CPlayer(newopl), flag_mkf(0), file_buffer(0), rix_buf(0)
+{
+}
+
+CrixPlayer::~CrixPlayer()
+{
+  if(file_buffer)
+    delete [] file_buffer;
+}
+
+bool CrixPlayer::load(const std::string &filename, const CFileProvider &fp)
+{
+  binistream *f = fp.open(filename); if(!f) return false;
+  uint32_t i=0;
+
+  if(stricmp(filename.substr(filename.length()-4,4).c_str(),".mkf")==0)
+  {
+	  flag_mkf=1;
+	  f->seek(0);
+	  int offset=f->readInt(4);
+	  f->seek(offset);
+  }
+  if(f->readInt(2)!=0x55aa){ fp.close(f);return false; }
+  file_buffer = new uint8_t [fp.filesize(f) + 1];
+  f->seek(0);
+  while(!f->eof())
+	file_buffer[i++]=f->readInt(1);
+  length=i;
+  fp.close(f);
+  if(!flag_mkf)
+	  rix_buf=file_buffer;
+  rewind(0);
+  return true;
+}
+
+bool CrixPlayer::update()
+{
+	int_08h_entry();
+	return !play_end;
+}
+
+void CrixPlayer::rewind(int subsong)
+{
+  I = 0; T = 0;
+  mus_block = 0;
+  ins_block = 0;
+  rhythm = 0;
+  music_on = 0;
+  pause_flag = 0;
+  band = 0;
+  band_low = 0;
+  e0_reg_flag = 0;
+  bd_modify = 0;
+  sustain = 0;
+  play_end = 0;
+  pos = index = 0; 
+
+  memset(f_buffer,   0,     sizeof(f_buffer));
+  memset(a0b0_data2, 0,     sizeof(a0b0_data2));
+  memset(a0b0_data3, 0,     sizeof(a0b0_data3));
+  memset(a0b0_data4, 0,     sizeof(a0b0_data4));
+  memset(a0b0_data5, 0,     sizeof(a0b0_data5));
+  memset(addrs_head, 0,     sizeof(addrs_head));
+  memset(insbuf,     0,     sizeof(insbuf));
+  memset(displace,   0,     sizeof(displace));
+  memset(reg_bufs,   0,     sizeof(reg_bufs));
+  memset(for40reg,   0x7F,  sizeof(for40reg));
+
+  if(flag_mkf)
+  {
+	  uint32_t *buf_index=(uint32_t *)file_buffer;
+	  int offset1=RIX_SWAP32(buf_index[subsong]),offset2;
+	  while((offset2=RIX_SWAP32(buf_index[++subsong]))==offset1);
+	  length=offset2-offset1+1;
+	  rix_buf=file_buffer+offset1;
+  }
+  opl->init();
+  opl->write(1,32);	// go to OPL2 mode
+  set_new_int();
+  data_initial();
+}
+
+unsigned int CrixPlayer::getsubsongs()
+{
+	if(flag_mkf)
+	{
+		uint32_t *buf_index=(uint32_t *)file_buffer;
+		int songs=RIX_SWAP32(buf_index[0])/4,i=0;
+		for(i=0;i<songs;i++)
+			if(buf_index[i+1]==buf_index[i])
+				songs--;
+		return songs;
+	}
+	else
+		return 1;
+}
+
+float CrixPlayer::getrefresh()
+{
+	return 70.0f;
+}
+
+/*------------------Implemention----------------------------*/
+inline void CrixPlayer::set_new_int()
+{
+//   if(!ad_initial()) exit(1);
+  ad_initial();
+}
+/*----------------------------------------------------------*/
+inline void CrixPlayer::Pause()
+{
+  register uint16_t i;
+  pause_flag = 1;
+  for(i=0;i<11;i++)
+    switch_ad_bd(i);
+}
+/*----------------------------------------------------------*/
+inline void CrixPlayer::ad_a0b0l_reg_(uint16_t index,uint16_t p2,uint16_t p3)
+{
+//   uint16_t i = p2+a0b0_data2[index];
+  a0b0_data4[index] = p3;
+  a0b0_data3[index] = p2;
+}
+inline void CrixPlayer::data_initial()
+{
+  rhythm = rix_buf[2];
+  mus_block = (rix_buf[0x0D]<<8)+rix_buf[0x0C];
+  ins_block = (rix_buf[0x09]<<8)+rix_buf[0x08];
+  I = mus_block+1;
+  if(rhythm != 0)
+    {
+      //		ad_a0b0_reg(6);
+      //		ad_a0b0_reg(7);
+      //		ad_a0b0_reg(8);
+      ad_a0b0l_reg_(8,0x18,0);
+      ad_a0b0l_reg_(7,0x1F,0);
+    }
+  bd_modify = 0;
+  //	ad_bd_reg();
+  band = 0; music_on = 1;
+}
+/*----------------------------------------------------------*/
+inline uint16_t CrixPlayer::ad_initial()
+{
+  uint16_t i,j,k = 0;
+  for(i=0;i<25;i++) 
+  {
+		uint32_t res = ((uint32_t)i*24+10000)*52088/250000*0x24000/0x1B503;
+		f_buffer[i*12]=((uint16_t)res+4)>>3;
+		for(int t=1;t<12;t++)
+		{
+			res*=1.06;
+			f_buffer[i*12+t]=((uint16_t)res+4)>>3;
+		}
+  }
+  for(i=0;i<8;i++)
+    for(j=0;j<12;j++)
+      {
+			a0b0_data5[k] = i;
+			addrs_head[k] = j;
+			k++;
+      }
+  //ad_bd_reg();
+  //ad_08_reg();
+  //for(i=0;i<9;i++) ad_a0b0_reg(i);
+  e0_reg_flag = 0x20;
+  //for(i=0;i<18;i++) ad_bop(0xE0+reg_data[i],0);
+  //ad_bop(1,e0_reg_flag);
+  return 1;//ad_test();
+}
+/*----------------------------------------------------------*/
+inline void CrixPlayer::ad_bop(uint16_t reg,uint16_t value)
+{
+  //if(reg == 2 || reg == 3)
+  //  AdPlug_LogWrite("switch OPL2/3 mode!\n");
+  opl->write(reg & 0xff, value & 0xff);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::int_08h_entry()   
+  {   
+    uint16_t band_sus = 1;   
+    while(band_sus)   
+      {   
+        if(sustain <= 0)   
+          {
+            band_sus = rix_proc();   
+            if(band_sus) sustain += band_sus; 
+            else
+              {   
+                play_end=1;   
+                break;   
+              }   
+          }   
+        else   
+          {   
+            if(band_sus) sustain -= 14; /* aging */   
+            break;   
+          }   
+      }   
+  }   
+/*--------------------------------------------------------------*/ 
+inline uint16_t CrixPlayer::rix_proc()
+{
+  uint8_t ctrl = 0;
+  if(music_on == 0||pause_flag == 1) return 0;
+  band = 0;
+  while(rix_buf[I] != 0x80 && I<length-1)
+    {
+      band_low = rix_buf[I-1];
+      ctrl = rix_buf[I]; I+=2;
+      switch(ctrl&0xF0)
+	{
+	case 0x90:  rix_get_ins(); rix_90_pro(ctrl&0x0F); break;
+	case 0xA0:  rix_A0_pro(ctrl&0x0F,((uint16_t)band_low)<<6); break;
+	case 0xB0:  rix_B0_pro(ctrl&0x0F,band_low); break;
+	case 0xC0:  switch_ad_bd(ctrl&0x0F);
+	  if(band_low != 0) rix_C0_pro(ctrl&0x0F,band_low);
+	  break;
+	default:    band = (ctrl<<8)+band_low; break;
+	}
+      if(band != 0) return band;
+    }
+  music_ctrl();
+  I = mus_block+1;
+  band = 0; music_on = 1;
+  return 0;
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::rix_get_ins()
+{
+  int		i;
+  uint8_t	*baddr = (&rix_buf[ins_block])+(band_low<<6);
+
+  for(i = 0; i < 28; i++)
+    insbuf[i] = (baddr[i * 2 + 1] << 8) + baddr[i * 2];
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::rix_90_pro(uint16_t ctrl_l)
+{
+  if(rhythm == 0 || ctrl_l < 6)
+    {
+      ins_to_reg(modify[ctrl_l*2],insbuf,insbuf[26]);
+      ins_to_reg(modify[ctrl_l*2+1],insbuf+13,insbuf[27]);
+      return;
+    }
+  else if(ctrl_l > 6)
+		{
+		  ins_to_reg(modify[ctrl_l*2+6],insbuf,insbuf[26]);
+		  return;
+		}
+  else
+		{
+		  ins_to_reg(12,insbuf,insbuf[26]);
+		  ins_to_reg(15,insbuf+13,insbuf[27]);
+		  return;
+		}
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::rix_A0_pro(uint16_t ctrl_l,uint16_t index)
+{
+  if(rhythm == 0 || ctrl_l <= 6)
+    {
+      prepare_a0b0(ctrl_l,index>0x3FFF?0x3FFF:index);
+      ad_a0b0l_reg(ctrl_l,a0b0_data3[ctrl_l],a0b0_data4[ctrl_l]);
+    }
+  else return;
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::prepare_a0b0(uint16_t index,uint16_t v)  /* important !*/
+{
+  short high = 0,low = 0; uint32_t res;
+  int res1 = (v-0x2000)*0x19;
+  if(res1 == (int)0xff) return;
+  low = res1/0x2000;
+  if(low < 0)
+    {
+      low = 0x18-low; high = (signed short)low<0?0xFFFF:0;
+      res = high; res<<=16; res+=low;
+      low = ((signed short)res)/(signed short)0xFFE7;
+      a0b0_data2[index] = low;
+      low = res;
+      res = low - 0x18;
+      high = (signed short)res%0x19;
+      low = (signed short)res/0x19;
+      if(high != 0) {low = 0x19; low = low-high;}
+    }
+  else
+    {
+      res = high = low;
+      low = (signed short)res/(signed short)0x19;
+      a0b0_data2[index] = low;
+      res = high;
+      low = (signed short)res%(signed short)0x19;
+    }
+  low = (signed short)low*(signed short)0x18;
+  displace[index] = low;
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_a0b0l_reg(uint16_t index,uint16_t p2,uint16_t p3)
+{
+  uint16_t data; uint16_t i = p2+a0b0_data2[index];
+  a0b0_data4[index] = p3;
+  a0b0_data3[index] = p2;
+  i = ((signed short)i<=0x5F?i:0x5F);
+  i = ((signed short)i>=0?i:0);
+  data = f_buffer[addrs_head[i]+displace[index]/2];
+  ad_bop(0xA0+index,data);
+  data = a0b0_data5[i]*4+(p3<1?0:0x20)+((data>>8)&3);
+  ad_bop(0xB0+index,data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::rix_B0_pro(uint16_t ctrl_l,uint16_t index)
+{
+  register int temp = 0;
+  if(rhythm == 0 || ctrl_l < 6) temp = modify[ctrl_l*2+1];
+  else
+    {
+      temp = ctrl_l > 6?ctrl_l*2:ctrl_l*2+1;
+      temp = modify[temp+6];
+    }
+  for40reg[temp] = index>0x7F?0x7F:index;
+  ad_40_reg(temp);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::rix_C0_pro(uint16_t ctrl_l,uint16_t index)
+{
+  register uint16_t i = index>=12?index-12:0;
+  if(ctrl_l < 6 || rhythm == 0)
+    {
+      ad_a0b0l_reg(ctrl_l,i,1);
+      return;
+    }
+  else
+    {
+      if(ctrl_l != 6)
+	{
+	  if(ctrl_l == 8)
+	    {
+	      ad_a0b0l_reg(ctrl_l,i,0);
+	      ad_a0b0l_reg(7,i+7,0);
+	    }
+	}
+      else ad_a0b0l_reg(ctrl_l,i,0);
+      bd_modify |= bd_reg_data[ctrl_l];
+      ad_bd_reg();
+      return;
+    }
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::switch_ad_bd(uint16_t index)
+{
+
+  if(rhythm == 0 || index < 6) ad_a0b0l_reg(index,a0b0_data3[index],0);
+  else
+    {
+      bd_modify &= (~bd_reg_data[index]),
+	ad_bd_reg();
+    }
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ins_to_reg(uint16_t index,uint16_t* insb,uint16_t value)
+{
+  register uint16_t i;
+  for(i=0;i<13;i++) reg_bufs[index].v[i] = insb[i];
+  reg_bufs[index].v[13] = value&3;
+  ad_bd_reg(),ad_08_reg(),
+    ad_40_reg(index),ad_C0_reg(index),ad_60_reg(index),
+    ad_80_reg(index),ad_20_reg(index),ad_E0_reg(index);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_E0_reg(uint16_t index)
+{
+  uint16_t data = e0_reg_flag == 0?0:(reg_bufs[index].v[13]&3);
+  ad_bop(0xE0+reg_data[index],data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_20_reg(uint16_t index)
+{
+  uint16_t data = (reg_bufs[index].v[9] < 1?0:0x80);
+  data += (reg_bufs[index].v[10] < 1?0:0x40);
+  data += (reg_bufs[index].v[5] < 1?0:0x20);
+  data += (reg_bufs[index].v[11] < 1?0:0x10);
+  data += (reg_bufs[index].v[1]&0x0F);
+  ad_bop(0x20+reg_data[index],data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_80_reg(uint16_t index)
+{
+  uint16_t data = (reg_bufs[index].v[7]&0x0F),temp = reg_bufs[index].v[4];
+  data |= (temp << 4);
+  ad_bop(0x80+reg_data[index],data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_60_reg(uint16_t index)
+{
+  uint16_t data = reg_bufs[index].v[6]&0x0F,temp = reg_bufs[index].v[3];
+  data |= (temp << 4);
+  ad_bop(0x60+reg_data[index],data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_C0_reg(uint16_t index)
+{
+  uint16_t data = reg_bufs[index].v[2];
+  if(adflag[index] == 1) return;
+  data *= 2,
+    data |= (reg_bufs[index].v[12] < 1?1:0);
+  ad_bop(0xC0+ad_C0_offs[index],data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_40_reg(uint16_t index)
+{
+  uint32_t res = 0;
+  uint16_t data = 0,temp = reg_bufs[index].v[0];
+  data = 0x3F - (0x3F & reg_bufs[index].v[8]),
+    data *= for40reg[index],
+    data *= 2,
+    data += 0x7F,
+    res = data;
+  data = res/0xFE,
+    data -= 0x3F,
+    data = -data,
+    data |= temp<<6;
+  ad_bop(0x40+reg_data[index],data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_bd_reg()
+{
+  uint16_t data = rhythm < 1? 0:0x20;
+  data |= bd_modify;
+  ad_bop(0xBD,data);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::ad_a0b0_reg(uint16_t index)
+{
+  ad_bop(0xA0+index,0);
+  ad_bop(0xB0+index,0);
+}
+/*--------------------------------------------------------------*/
+inline void CrixPlayer::music_ctrl()
+{
+  register int i;
+  for(i=0;i<11;i++)
+    switch_ad_bd(i);
+}

+ 121 - 0
adplug/rix.h

@@ -0,0 +1,121 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * rix.h - Softstar RIX OPL Format Player by palxex <palxex.ys168.com>
+ *                                           BSPAL <BSPAL.ys168.com>
+ */
+
+#include "player.h"
+
+#ifdef _MSC_VER
+#include <windows.h>
+#define uint8_t BYTE
+#define uint16_t WORD
+#define uint32_t DWORD
+#else
+#include <stdint.h>
+#endif
+
+class CrixPlayer: public CPlayer
+{
+ public:
+  static CPlayer *factory(Copl *newopl);
+
+  CrixPlayer(Copl *newopl);
+  ~CrixPlayer();
+
+  bool load(const std::string &filename, const CFileProvider &fp);
+  bool update();
+  void rewind(int subsong);
+  float getrefresh();
+  unsigned int getsubsongs();
+
+  std::string gettype()
+    { return std::string("Softstar RIX OPL Music Format"); };
+
+ protected:	
+  typedef struct {
+    uint8_t v[14];
+  } ADDT;
+
+  int flag_mkf;
+  uint8_t *file_buffer;
+  uint8_t *rix_buf;  /* rix files' f_buffer */
+  uint16_t f_buffer[300];//9C0h-C18h
+  uint16_t a0b0_data2[11];
+  uint8_t a0b0_data3[18];
+  uint8_t a0b0_data4[18];
+  uint8_t a0b0_data5[96];
+  uint8_t addrs_head[96];
+  uint16_t insbuf[28];
+  uint16_t displace[11];
+  ADDT reg_bufs[18];
+  uint32_t pos,length;
+  uint8_t index;
+
+  static const uint8_t adflag[18];
+  static const uint8_t reg_data[18];
+  static const uint8_t ad_C0_offs[18];
+  static const uint8_t modify[28];
+  static const uint8_t bd_reg_data[124];
+  static uint8_t for40reg[18];
+  static const uint16_t mus_time;
+  uint32_t I,T;
+  uint16_t mus_block;
+  uint16_t ins_block;
+  uint8_t rhythm;
+  uint8_t music_on;
+  uint8_t pause_flag;
+  uint16_t band;
+  uint8_t band_low;
+  uint16_t e0_reg_flag;
+  uint8_t bd_modify;
+  int sustain;
+  int play_end;
+
+#define ad_08_reg() ad_bop(8,0)    /**/
+  inline void ad_20_reg(uint16_t);              /**/
+  inline void ad_40_reg(uint16_t);              /**/
+  inline void ad_60_reg(uint16_t);              /**/
+  inline void ad_80_reg(uint16_t);              /**/
+  inline void ad_a0b0_reg(uint16_t);            /**/
+  inline void ad_a0b0l_reg(uint16_t,uint16_t,uint16_t); /**/
+  inline void ad_a0b0l_reg_(uint16_t,uint16_t,uint16_t); /**/
+  inline void ad_bd_reg();                  /**/
+  inline void ad_bop(uint16_t,uint16_t);                     /**/
+  inline void ad_C0_reg(uint16_t);              /**/
+  inline void ad_E0_reg(uint16_t);              /**/
+  inline uint16_t ad_initial();                 /**/
+  inline uint16_t ad_test();                    /**/
+  inline void crc_trans(uint16_t,uint16_t);         /**/
+  inline void data_initial();               /* done */
+  inline void init();                       /**/
+  inline void ins_to_reg(uint16_t,uint16_t*,uint16_t);  /**/
+  inline void int_08h_entry();    /**/
+  inline void music_ctrl();                 /**/
+  inline void Pause();                      /**/
+  inline void prepare_a0b0(uint16_t,uint16_t);      /**/
+  inline void rix_90_pro(uint16_t);             /**/
+  inline void rix_A0_pro(uint16_t,uint16_t);        /**/
+  inline void rix_B0_pro(uint16_t,uint16_t);        /**/
+  inline void rix_C0_pro(uint16_t,uint16_t);        /**/
+  inline void rix_get_ins();                /**/
+  inline uint16_t rix_proc();                   /**/
+  inline void set_new_int();
+  inline void switch_ad_bd(uint16_t);           /**/
+};

+ 203 - 0
adplug/surroundopl.cpp

@@ -0,0 +1,203 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2010 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * surroundopl.cpp - Wrapper class to provide a surround/harmonic effect
+ *   for another OPL emulator, by Adam Nielsen <malvineous@shikadi.net>
+ *
+ * Stereo harmonic algorithm by Adam Nielsen <malvineous@shikadi.net>
+ * Please give credit if you use this algorithm elsewhere :-)
+ */
+
+#include <math.h> // for pow()
+#include "surroundopl.h"
+//#include "debug.h"
+
+CSurroundopl::CSurroundopl(Copl *a, Copl *b, bool use16bit)
+	: use16bit(use16bit),
+		bufsize(4096),
+		a(a), b(b)
+{
+	currType = TYPE_OPL2;
+	this->lbuf = new short[this->bufsize];
+	this->rbuf = new short[this->bufsize];
+};
+
+CSurroundopl::~CSurroundopl()
+{
+	delete[] this->rbuf;
+	delete[] this->lbuf;
+	delete a;
+	delete b;
+}
+
+void CSurroundopl::update(short *buf, int samples)
+{
+	if (samples * 2 > this->bufsize) {
+		// Need to realloc the buffer
+		delete[] this->rbuf;
+		delete[] this->lbuf;
+		this->bufsize = samples * 2;
+		this->lbuf = new short[this->bufsize];
+		this->rbuf = new short[this->bufsize];
+	}
+
+	a->update(this->lbuf, samples);
+	b->update(this->rbuf, samples);
+
+	// Copy the two mono OPL buffers into the stereo buffer
+	for (int i = 0; i < samples; i++) {
+		if (this->use16bit) {
+			buf[i * 2] = this->lbuf[i];
+			buf[i * 2 + 1] = this->rbuf[i];
+		} else {
+			((char *)buf)[i * 2] = ((char *)this->lbuf)[i];
+			((char *)buf)[i * 2 + 1] = ((char *)this->rbuf)[i];
+		}
+	}
+
+}
+
+// template methods
+void CSurroundopl::write(int reg, int val)
+{
+	a->write(reg, val);
+
+	// Transpose the other channel to produce the harmonic effect
+
+	int iChannel = -1;
+	int iRegister = reg; // temp
+	int iValue = val; // temp
+	if ((iRegister >> 4 == 0xA) || (iRegister >> 4 == 0xB)) iChannel = iRegister & 0x0F;
+
+	// Remember the FM state, so that the harmonic effect can access
+	// previously assigned register values.
+	/*if (((iRegister >> 4 == 0xB) && (iValue & 0x20) && !(this->iFMReg[iRegister] & 0x20)) ||
+		(iRegister == 0xBD) && (
+			((iValue & 0x01) && !(this->iFMReg[0xBD] & 0x01))
+		)) {
+		this->iFMReg[iRegister] = iValue;
+	}*/
+	this->iFMReg[iRegister] = iValue;
+
+	if ((iChannel >= 0)) {// && (i == 1)) {
+		unsigned char iBlock = (this->iFMReg[0xB0 + iChannel] >> 2) & 0x07;
+		unsigned short iFNum = ((this->iFMReg[0xB0 + iChannel] & 0x03) << 8) | this->iFMReg[0xA0 + iChannel];
+		//double dbOriginalFreq = 50000.0 * (double)iFNum * pow(2, iBlock - 20);
+		double dbOriginalFreq = 49716.0 * (double)iFNum * pow(2.0, iBlock - 20);
+
+		unsigned char iNewBlock = iBlock;
+		unsigned short iNewFNum;
+
+		// Adjust the frequency and calculate the new FNum
+		//double dbNewFNum = (dbOriginalFreq+(dbOriginalFreq/FREQ_OFFSET)) / (50000.0 * pow(2.0, iNewBlock - 20));
+		//#define calcFNum() ((dbOriginalFreq+(dbOriginalFreq/FREQ_OFFSET)) / (50000.0 * pow(2.0, iNewBlock - 20)))
+		#define calcFNum() ((dbOriginalFreq+(dbOriginalFreq/FREQ_OFFSET)) / (49716.0 * pow(2.0, iNewBlock - 20)))
+		double dbNewFNum = calcFNum();
+
+		// Make sure it's in range for the OPL chip
+		if (dbNewFNum > 1023 - NEWBLOCK_LIMIT) {
+			// It's too high, so move up one block (octave) and recalculate
+
+			if (iNewBlock > 6) {
+				// Uh oh, we're already at the highest octave!
+//				AdPlug_LogWrite("OPL WARN: FNum %d/B#%d would need block 8+ after being transposed (new FNum is %d)\n",
+//					iFNum, iBlock, (int)dbNewFNum);
+				// The best we can do here is to just play the same note out of the second OPL, so at least it shouldn't
+				// sound *too* bad (hopefully it will just miss out on the nice harmonic.)
+				iNewBlock = iBlock;
+				iNewFNum = iFNum;
+			} else {
+				iNewBlock++;
+				iNewFNum = (unsigned short)calcFNum();
+			}
+		} else if (dbNewFNum < 0 + NEWBLOCK_LIMIT) {
+			// It's too low, so move down one block (octave) and recalculate
+
+			if (iNewBlock == 0) {
+				// Uh oh, we're already at the lowest octave!
+//				AdPlug_LogWrite("OPL WARN: FNum %d/B#%d would need block -1 after being transposed (new FNum is %d)!\n",
+//					iFNum, iBlock, (int)dbNewFNum);
+				// The best we can do here is to just play the same note out of the second OPL, so at least it shouldn't
+				// sound *too* bad (hopefully it will just miss out on the nice harmonic.)
+				iNewBlock = iBlock;
+				iNewFNum = iFNum;
+			} else {
+				iNewBlock--;
+				iNewFNum = (unsigned short)calcFNum();
+			}
+		} else {
+			// Original calculation is within range, use that
+			iNewFNum = (unsigned short)dbNewFNum;
+		}
+
+		// Sanity check
+		if (iNewFNum > 1023) {
+			// Uh oh, the new FNum is still out of range! (This shouldn't happen)
+//			AdPlug_LogWrite("OPL ERR: Original note (FNum %d/B#%d is still out of range after change to FNum %d/B#%d!\n",
+//				iFNum, iBlock, iNewFNum, iNewBlock);
+			// The best we can do here is to just play the same note out of the second OPL, so at least it shouldn't
+			// sound *too* bad (hopefully it will just miss out on the nice harmonic.)
+			iNewBlock = iBlock;
+			iNewFNum = iFNum;
+		}
+
+		if ((iRegister >= 0xB0) && (iRegister <= 0xB8)) {
+
+			// Overwrite the supplied value with the new F-Number and Block.
+			iValue = (iValue & ~0x1F) | (iNewBlock << 2) | ((iNewFNum >> 8) & 0x03);
+
+			this->iCurrentTweakedBlock[iChannel] = iNewBlock; // save it so we don't have to update register 0xB0 later on
+			this->iCurrentFNum[iChannel] = (unsigned char)iNewFNum;
+
+			if (this->iTweakedFMReg[0xA0 + iChannel] != (iNewFNum & 0xFF)) {
+				// Need to write out low bits
+				unsigned char iAdditionalReg = 0xA0 + iChannel;
+				unsigned char iAdditionalValue = iNewFNum & 0xFF;
+				b->write(iAdditionalReg, iAdditionalValue);
+				this->iTweakedFMReg[iAdditionalReg] = iAdditionalValue;
+			}
+		} else if ((iRegister >= 0xA0) && (iRegister <= 0xA8)) {
+
+			// Overwrite the supplied value with the new F-Number.
+			iValue = iNewFNum & 0xFF;
+
+			// See if we need to update the block number, which is stored in a different register
+			unsigned char iNewB0Value = (this->iFMReg[0xB0 + iChannel] & ~0x1F) | (iNewBlock << 2) | ((iNewFNum >> 8) & 0x03);
+			if (
+				(iNewB0Value & 0x20) && // but only update if there's a note currently playing (otherwise we can just wait
+				(this->iTweakedFMReg[0xB0 + iChannel] != iNewB0Value)   // until the next noteon and update it then)
+			) {
+//				AdPlug_LogWrite("OPL INFO: CH%d - FNum %d/B#%d -> FNum %d/B#%d == keyon register update!\n",
+//					iChannel, iFNum, iBlock, iNewFNum, iNewBlock);
+					// The note is already playing, so we need to adjust the upper bits too
+					unsigned char iAdditionalReg = 0xB0 + iChannel;
+					b->write(iAdditionalReg, iNewB0Value);
+					this->iTweakedFMReg[iAdditionalReg] = iNewB0Value;
+			} // else the note is not playing, the upper bits will be set when the note is next played
+
+		} // if (register 0xB0 or 0xA0)
+
+	} // if (a register we're interested in)
+
+	// Now write to the original register with a possibly modified value
+	b->write(iRegister, iValue);
+	this->iTweakedFMReg[iRegister] = iValue;
+
+};
+
+void CSurroundopl::init() {};

+ 69 - 0
adplug/surroundopl.h

@@ -0,0 +1,69 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2010 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * surroundopl.h - Wrapper class to provide a surround/harmonic effect
+ *   for another OPL emulator, by Adam Nielsen <malvineous@shikadi.net>
+ *
+ * Stereo harmonic algorithm by Adam Nielsen <malvineous@shikadi.net>
+ * Please give credit if you use this algorithm elsewhere :-)
+ */
+
+#ifndef H_ADPLUG_SURROUNDOPL
+#define H_ADPLUG_SURROUNDOPL
+
+//#include <stdint.h> // for uintxx_t
+#include "opl.h"
+
+// The right-channel is increased in frequency by itself divided by this amount.
+// The right value should not noticeably change the pitch, but it should provide
+// a nice stereo harmonic effect.
+#define FREQ_OFFSET 128.0//96.0
+
+// Number of FNums away from the upper/lower limit before switching to the next
+// block (octave.)  By rights it should be zero, but for some reason this seems
+// to cut it to close and the transposed OPL doesn't hit the right note all the
+// time.  Setting it higher means it will switch blocks sooner and that seems
+// to help.  Don't set it too high or it'll get stuck in an infinite loop if
+// one block is too high and the adjacent block is too low ;-)
+#define NEWBLOCK_LIMIT  32
+
+class CSurroundopl: public Copl
+{
+	private:
+		bool use16bit;
+		short bufsize;
+		short *lbuf, *rbuf;
+		Copl *a, *b;
+		unsigned char iFMReg[256];
+		unsigned char iTweakedFMReg[256];
+		unsigned char iCurrentTweakedBlock[9]; // Current value of the Block in the tweaked OPL chip
+		unsigned char iCurrentFNum[9];         // Current value of the FNum in the tweaked OPL chip
+
+	public:
+
+		CSurroundopl(Copl *a, Copl *b, bool use16bit);
+		~CSurroundopl();
+
+		void update(short *buf, int samples);
+		void write(int reg, int val);
+
+		void init();
+
+};
+
+#endif

+ 607 - 0
libmad/D.dat

@@ -0,0 +1,607 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: D.dat,v 1.9 2004/01/23 09:41:32 rob Exp $
+ */
+
+/*
+ * These are the coefficients for the subband synthesis window. This is a
+ * reordered version of Table B.3 from ISO/IEC 11172-3.
+ *
+ * Every value is parameterized so that shift optimizations can be made at
+ * compile-time. For example, every value can be right-shifted 12 bits to
+ * minimize multiply instruction times without any loss of accuracy.
+ */
+
+  {  PRESHIFT(0x00000000) /*  0.000000000 */,	/*  0 */
+    -PRESHIFT(0x0001d000) /* -0.000442505 */,
+     PRESHIFT(0x000d5000) /*  0.003250122 */,
+    -PRESHIFT(0x001cb000) /* -0.007003784 */,
+     PRESHIFT(0x007f5000) /*  0.031082153 */,
+    -PRESHIFT(0x01421000) /* -0.078628540 */,
+     PRESHIFT(0x019ae000) /*  0.100311279 */,
+    -PRESHIFT(0x09271000) /* -0.572036743 */,
+     PRESHIFT(0x1251e000) /*  1.144989014 */,
+     PRESHIFT(0x09271000) /*  0.572036743 */,
+     PRESHIFT(0x019ae000) /*  0.100311279 */,
+     PRESHIFT(0x01421000) /*  0.078628540 */,
+     PRESHIFT(0x007f5000) /*  0.031082153 */,
+     PRESHIFT(0x001cb000) /*  0.007003784 */,
+     PRESHIFT(0x000d5000) /*  0.003250122 */,
+     PRESHIFT(0x0001d000) /*  0.000442505 */,
+
+     PRESHIFT(0x00000000) /*  0.000000000 */,
+    -PRESHIFT(0x0001d000) /* -0.000442505 */,
+     PRESHIFT(0x000d5000) /*  0.003250122 */,
+    -PRESHIFT(0x001cb000) /* -0.007003784 */,
+     PRESHIFT(0x007f5000) /*  0.031082153 */,
+    -PRESHIFT(0x01421000) /* -0.078628540 */,
+     PRESHIFT(0x019ae000) /*  0.100311279 */,
+    -PRESHIFT(0x09271000) /* -0.572036743 */,
+     PRESHIFT(0x1251e000) /*  1.144989014 */,
+     PRESHIFT(0x09271000) /*  0.572036743 */,
+     PRESHIFT(0x019ae000) /*  0.100311279 */,
+     PRESHIFT(0x01421000) /*  0.078628540 */,
+     PRESHIFT(0x007f5000) /*  0.031082153 */,
+     PRESHIFT(0x001cb000) /*  0.007003784 */,
+     PRESHIFT(0x000d5000) /*  0.003250122 */,
+     PRESHIFT(0x0001d000) /*  0.000442505 */ },
+
+  { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  1 */
+    -PRESHIFT(0x0001f000) /* -0.000473022 */,
+     PRESHIFT(0x000da000) /*  0.003326416 */,
+    -PRESHIFT(0x00207000) /* -0.007919312 */,
+     PRESHIFT(0x007d0000) /*  0.030517578 */,
+    -PRESHIFT(0x0158d000) /* -0.084182739 */,
+     PRESHIFT(0x01747000) /*  0.090927124 */,
+    -PRESHIFT(0x099a8000) /* -0.600219727 */,
+     PRESHIFT(0x124f0000) /*  1.144287109 */,
+     PRESHIFT(0x08b38000) /*  0.543823242 */,
+     PRESHIFT(0x01bde000) /*  0.108856201 */,
+     PRESHIFT(0x012b4000) /*  0.073059082 */,
+     PRESHIFT(0x0080f000) /*  0.031478882 */,
+     PRESHIFT(0x00191000) /*  0.006118774 */,
+     PRESHIFT(0x000d0000) /*  0.003173828 */,
+     PRESHIFT(0x0001a000) /*  0.000396729 */,
+
+    -PRESHIFT(0x00001000) /* -0.000015259 */,
+    -PRESHIFT(0x0001f000) /* -0.000473022 */,
+     PRESHIFT(0x000da000) /*  0.003326416 */,
+    -PRESHIFT(0x00207000) /* -0.007919312 */,
+     PRESHIFT(0x007d0000) /*  0.030517578 */,
+    -PRESHIFT(0x0158d000) /* -0.084182739 */,
+     PRESHIFT(0x01747000) /*  0.090927124 */,
+    -PRESHIFT(0x099a8000) /* -0.600219727 */,
+     PRESHIFT(0x124f0000) /*  1.144287109 */,
+     PRESHIFT(0x08b38000) /*  0.543823242 */,
+     PRESHIFT(0x01bde000) /*  0.108856201 */,
+     PRESHIFT(0x012b4000) /*  0.073059082 */,
+     PRESHIFT(0x0080f000) /*  0.031478882 */,
+     PRESHIFT(0x00191000) /*  0.006118774 */,
+     PRESHIFT(0x000d0000) /*  0.003173828 */,
+     PRESHIFT(0x0001a000) /*  0.000396729 */ },
+
+  { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  2 */
+    -PRESHIFT(0x00023000) /* -0.000534058 */,
+     PRESHIFT(0x000de000) /*  0.003387451 */,
+    -PRESHIFT(0x00245000) /* -0.008865356 */,
+     PRESHIFT(0x007a0000) /*  0.029785156 */,
+    -PRESHIFT(0x016f7000) /* -0.089706421 */,
+     PRESHIFT(0x014a8000) /*  0.080688477 */,
+    -PRESHIFT(0x0a0d8000) /* -0.628295898 */,
+     PRESHIFT(0x12468000) /*  1.142211914 */,
+     PRESHIFT(0x083ff000) /*  0.515609741 */,
+     PRESHIFT(0x01dd8000) /*  0.116577148 */,
+     PRESHIFT(0x01149000) /*  0.067520142 */,
+     PRESHIFT(0x00820000) /*  0.031738281 */,
+     PRESHIFT(0x0015b000) /*  0.005294800 */,
+     PRESHIFT(0x000ca000) /*  0.003082275 */,
+     PRESHIFT(0x00018000) /*  0.000366211 */,
+
+    -PRESHIFT(0x00001000) /* -0.000015259 */,
+    -PRESHIFT(0x00023000) /* -0.000534058 */,
+     PRESHIFT(0x000de000) /*  0.003387451 */,
+    -PRESHIFT(0x00245000) /* -0.008865356 */,
+     PRESHIFT(0x007a0000) /*  0.029785156 */,
+    -PRESHIFT(0x016f7000) /* -0.089706421 */,
+     PRESHIFT(0x014a8000) /*  0.080688477 */,
+    -PRESHIFT(0x0a0d8000) /* -0.628295898 */,
+     PRESHIFT(0x12468000) /*  1.142211914 */,
+     PRESHIFT(0x083ff000) /*  0.515609741 */,
+     PRESHIFT(0x01dd8000) /*  0.116577148 */,
+     PRESHIFT(0x01149000) /*  0.067520142 */,
+     PRESHIFT(0x00820000) /*  0.031738281 */,
+     PRESHIFT(0x0015b000) /*  0.005294800 */,
+     PRESHIFT(0x000ca000) /*  0.003082275 */,
+     PRESHIFT(0x00018000) /*  0.000366211 */ },
+
+  { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  3 */
+    -PRESHIFT(0x00026000) /* -0.000579834 */,
+     PRESHIFT(0x000e1000) /*  0.003433228 */,
+    -PRESHIFT(0x00285000) /* -0.009841919 */,
+     PRESHIFT(0x00765000) /*  0.028884888 */,
+    -PRESHIFT(0x0185d000) /* -0.095169067 */,
+     PRESHIFT(0x011d1000) /*  0.069595337 */,
+    -PRESHIFT(0x0a7fe000) /* -0.656219482 */,
+     PRESHIFT(0x12386000) /*  1.138763428 */,
+     PRESHIFT(0x07ccb000) /*  0.487472534 */,
+     PRESHIFT(0x01f9c000) /*  0.123474121 */,
+     PRESHIFT(0x00fdf000) /*  0.061996460 */,
+     PRESHIFT(0x00827000) /*  0.031845093 */,
+     PRESHIFT(0x00126000) /*  0.004486084 */,
+     PRESHIFT(0x000c4000) /*  0.002990723 */,
+     PRESHIFT(0x00015000) /*  0.000320435 */,
+
+    -PRESHIFT(0x00001000) /* -0.000015259 */,
+    -PRESHIFT(0x00026000) /* -0.000579834 */,
+     PRESHIFT(0x000e1000) /*  0.003433228 */,
+    -PRESHIFT(0x00285000) /* -0.009841919 */,
+     PRESHIFT(0x00765000) /*  0.028884888 */,
+    -PRESHIFT(0x0185d000) /* -0.095169067 */,
+     PRESHIFT(0x011d1000) /*  0.069595337 */,
+    -PRESHIFT(0x0a7fe000) /* -0.656219482 */,
+     PRESHIFT(0x12386000) /*  1.138763428 */,
+     PRESHIFT(0x07ccb000) /*  0.487472534 */,
+     PRESHIFT(0x01f9c000) /*  0.123474121 */,
+     PRESHIFT(0x00fdf000) /*  0.061996460 */,
+     PRESHIFT(0x00827000) /*  0.031845093 */,
+     PRESHIFT(0x00126000) /*  0.004486084 */,
+     PRESHIFT(0x000c4000) /*  0.002990723 */,
+     PRESHIFT(0x00015000) /*  0.000320435 */ },
+
+  { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  4 */
+    -PRESHIFT(0x00029000) /* -0.000625610 */,
+     PRESHIFT(0x000e3000) /*  0.003463745 */,
+    -PRESHIFT(0x002c7000) /* -0.010848999 */,
+     PRESHIFT(0x0071e000) /*  0.027801514 */,
+    -PRESHIFT(0x019bd000) /* -0.100540161 */,
+     PRESHIFT(0x00ec0000) /*  0.057617187 */,
+    -PRESHIFT(0x0af15000) /* -0.683914185 */,
+     PRESHIFT(0x12249000) /*  1.133926392 */,
+     PRESHIFT(0x075a0000) /*  0.459472656 */,
+     PRESHIFT(0x0212c000) /*  0.129577637 */,
+     PRESHIFT(0x00e79000) /*  0.056533813 */,
+     PRESHIFT(0x00825000) /*  0.031814575 */,
+     PRESHIFT(0x000f4000) /*  0.003723145 */,
+     PRESHIFT(0x000be000) /*  0.002899170 */,
+     PRESHIFT(0x00013000) /*  0.000289917 */,
+
+    -PRESHIFT(0x00001000) /* -0.000015259 */,
+    -PRESHIFT(0x00029000) /* -0.000625610 */,
+     PRESHIFT(0x000e3000) /*  0.003463745 */,
+    -PRESHIFT(0x002c7000) /* -0.010848999 */,
+     PRESHIFT(0x0071e000) /*  0.027801514 */,
+    -PRESHIFT(0x019bd000) /* -0.100540161 */,
+     PRESHIFT(0x00ec0000) /*  0.057617187 */,
+    -PRESHIFT(0x0af15000) /* -0.683914185 */,
+     PRESHIFT(0x12249000) /*  1.133926392 */,
+     PRESHIFT(0x075a0000) /*  0.459472656 */,
+     PRESHIFT(0x0212c000) /*  0.129577637 */,
+     PRESHIFT(0x00e79000) /*  0.056533813 */,
+     PRESHIFT(0x00825000) /*  0.031814575 */,
+     PRESHIFT(0x000f4000) /*  0.003723145 */,
+     PRESHIFT(0x000be000) /*  0.002899170 */,
+     PRESHIFT(0x00013000) /*  0.000289917 */ },
+
+  { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  5 */
+    -PRESHIFT(0x0002d000) /* -0.000686646 */,
+     PRESHIFT(0x000e4000) /*  0.003479004 */,
+    -PRESHIFT(0x0030b000) /* -0.011886597 */,
+     PRESHIFT(0x006cb000) /*  0.026535034 */,
+    -PRESHIFT(0x01b17000) /* -0.105819702 */,
+     PRESHIFT(0x00b77000) /*  0.044784546 */,
+    -PRESHIFT(0x0b619000) /* -0.711318970 */,
+     PRESHIFT(0x120b4000) /*  1.127746582 */,
+     PRESHIFT(0x06e81000) /*  0.431655884 */,
+     PRESHIFT(0x02288000) /*  0.134887695 */,
+     PRESHIFT(0x00d17000) /*  0.051132202 */,
+     PRESHIFT(0x0081b000) /*  0.031661987 */,
+     PRESHIFT(0x000c5000) /*  0.003005981 */,
+     PRESHIFT(0x000b7000) /*  0.002792358 */,
+     PRESHIFT(0x00011000) /*  0.000259399 */,
+
+    -PRESHIFT(0x00001000) /* -0.000015259 */,
+    -PRESHIFT(0x0002d000) /* -0.000686646 */,
+     PRESHIFT(0x000e4000) /*  0.003479004 */,
+    -PRESHIFT(0x0030b000) /* -0.011886597 */,
+     PRESHIFT(0x006cb000) /*  0.026535034 */,
+    -PRESHIFT(0x01b17000) /* -0.105819702 */,
+     PRESHIFT(0x00b77000) /*  0.044784546 */,
+    -PRESHIFT(0x0b619000) /* -0.711318970 */,
+     PRESHIFT(0x120b4000) /*  1.127746582 */,
+     PRESHIFT(0x06e81000) /*  0.431655884 */,
+     PRESHIFT(0x02288000) /*  0.134887695 */,
+     PRESHIFT(0x00d17000) /*  0.051132202 */,
+     PRESHIFT(0x0081b000) /*  0.031661987 */,
+     PRESHIFT(0x000c5000) /*  0.003005981 */,
+     PRESHIFT(0x000b7000) /*  0.002792358 */,
+     PRESHIFT(0x00011000) /*  0.000259399 */ },
+
+  { -PRESHIFT(0x00001000) /* -0.000015259 */,	/*  6 */
+    -PRESHIFT(0x00031000) /* -0.000747681 */,
+     PRESHIFT(0x000e4000) /*  0.003479004 */,
+    -PRESHIFT(0x00350000) /* -0.012939453 */,
+     PRESHIFT(0x0066c000) /*  0.025085449 */,
+    -PRESHIFT(0x01c67000) /* -0.110946655 */,
+     PRESHIFT(0x007f5000) /*  0.031082153 */,
+    -PRESHIFT(0x0bd06000) /* -0.738372803 */,
+     PRESHIFT(0x11ec7000) /*  1.120223999 */,
+     PRESHIFT(0x06772000) /*  0.404083252 */,
+     PRESHIFT(0x023b3000) /*  0.139450073 */,
+     PRESHIFT(0x00bbc000) /*  0.045837402 */,
+     PRESHIFT(0x00809000) /*  0.031387329 */,
+     PRESHIFT(0x00099000) /*  0.002334595 */,
+     PRESHIFT(0x000b0000) /*  0.002685547 */,
+     PRESHIFT(0x00010000) /*  0.000244141 */,
+
+    -PRESHIFT(0x00001000) /* -0.000015259 */,
+    -PRESHIFT(0x00031000) /* -0.000747681 */,
+     PRESHIFT(0x000e4000) /*  0.003479004 */,
+    -PRESHIFT(0x00350000) /* -0.012939453 */,
+     PRESHIFT(0x0066c000) /*  0.025085449 */,
+    -PRESHIFT(0x01c67000) /* -0.110946655 */,
+     PRESHIFT(0x007f5000) /*  0.031082153 */,
+    -PRESHIFT(0x0bd06000) /* -0.738372803 */,
+     PRESHIFT(0x11ec7000) /*  1.120223999 */,
+     PRESHIFT(0x06772000) /*  0.404083252 */,
+     PRESHIFT(0x023b3000) /*  0.139450073 */,
+     PRESHIFT(0x00bbc000) /*  0.045837402 */,
+     PRESHIFT(0x00809000) /*  0.031387329 */,
+     PRESHIFT(0x00099000) /*  0.002334595 */,
+     PRESHIFT(0x000b0000) /*  0.002685547 */,
+     PRESHIFT(0x00010000) /*  0.000244141 */ },
+
+  { -PRESHIFT(0x00002000) /* -0.000030518 */,	/*  7 */
+    -PRESHIFT(0x00035000) /* -0.000808716 */,
+     PRESHIFT(0x000e3000) /*  0.003463745 */,
+    -PRESHIFT(0x00397000) /* -0.014022827 */,
+     PRESHIFT(0x005ff000) /*  0.023422241 */,
+    -PRESHIFT(0x01dad000) /* -0.115921021 */,
+     PRESHIFT(0x0043a000) /*  0.016510010 */,
+    -PRESHIFT(0x0c3d9000) /* -0.765029907 */,
+     PRESHIFT(0x11c83000) /*  1.111373901 */,
+     PRESHIFT(0x06076000) /*  0.376800537 */,
+     PRESHIFT(0x024ad000) /*  0.143264771 */,
+     PRESHIFT(0x00a67000) /*  0.040634155 */,
+     PRESHIFT(0x007f0000) /*  0.031005859 */,
+     PRESHIFT(0x0006f000) /*  0.001693726 */,
+     PRESHIFT(0x000a9000) /*  0.002578735 */,
+     PRESHIFT(0x0000e000) /*  0.000213623 */,
+
+    -PRESHIFT(0x00002000) /* -0.000030518 */,
+    -PRESHIFT(0x00035000) /* -0.000808716 */,
+     PRESHIFT(0x000e3000) /*  0.003463745 */,
+    -PRESHIFT(0x00397000) /* -0.014022827 */,
+     PRESHIFT(0x005ff000) /*  0.023422241 */,
+    -PRESHIFT(0x01dad000) /* -0.115921021 */,
+     PRESHIFT(0x0043a000) /*  0.016510010 */,
+    -PRESHIFT(0x0c3d9000) /* -0.765029907 */,
+     PRESHIFT(0x11c83000) /*  1.111373901 */,
+     PRESHIFT(0x06076000) /*  0.376800537 */,
+     PRESHIFT(0x024ad000) /*  0.143264771 */,
+     PRESHIFT(0x00a67000) /*  0.040634155 */,
+     PRESHIFT(0x007f0000) /*  0.031005859 */,
+     PRESHIFT(0x0006f000) /*  0.001693726 */,
+     PRESHIFT(0x000a9000) /*  0.002578735 */,
+     PRESHIFT(0x0000e000) /*  0.000213623 */ },
+
+  { -PRESHIFT(0x00002000) /* -0.000030518 */,	/*  8 */
+    -PRESHIFT(0x0003a000) /* -0.000885010 */,
+     PRESHIFT(0x000e0000) /*  0.003417969 */,
+    -PRESHIFT(0x003df000) /* -0.015121460 */,
+     PRESHIFT(0x00586000) /*  0.021575928 */,
+    -PRESHIFT(0x01ee6000) /* -0.120697021 */,
+     PRESHIFT(0x00046000) /*  0.001068115 */,
+    -PRESHIFT(0x0ca8d000) /* -0.791213989 */,
+     PRESHIFT(0x119e9000) /*  1.101211548 */,
+     PRESHIFT(0x05991000) /*  0.349868774 */,
+     PRESHIFT(0x02578000) /*  0.146362305 */,
+     PRESHIFT(0x0091a000) /*  0.035552979 */,
+     PRESHIFT(0x007d1000) /*  0.030532837 */,
+     PRESHIFT(0x00048000) /*  0.001098633 */,
+     PRESHIFT(0x000a1000) /*  0.002456665 */,
+     PRESHIFT(0x0000d000) /*  0.000198364 */,
+
+    -PRESHIFT(0x00002000) /* -0.000030518 */,
+    -PRESHIFT(0x0003a000) /* -0.000885010 */,
+     PRESHIFT(0x000e0000) /*  0.003417969 */,
+    -PRESHIFT(0x003df000) /* -0.015121460 */,
+     PRESHIFT(0x00586000) /*  0.021575928 */,
+    -PRESHIFT(0x01ee6000) /* -0.120697021 */,
+     PRESHIFT(0x00046000) /*  0.001068115 */,
+    -PRESHIFT(0x0ca8d000) /* -0.791213989 */,
+     PRESHIFT(0x119e9000) /*  1.101211548 */,
+     PRESHIFT(0x05991000) /*  0.349868774 */,
+     PRESHIFT(0x02578000) /*  0.146362305 */,
+     PRESHIFT(0x0091a000) /*  0.035552979 */,
+     PRESHIFT(0x007d1000) /*  0.030532837 */,
+     PRESHIFT(0x00048000) /*  0.001098633 */,
+     PRESHIFT(0x000a1000) /*  0.002456665 */,
+     PRESHIFT(0x0000d000) /*  0.000198364 */ },
+
+  { -PRESHIFT(0x00002000) /* -0.000030518 */,	/*  9 */
+    -PRESHIFT(0x0003f000) /* -0.000961304 */,
+     PRESHIFT(0x000dd000) /*  0.003372192 */,
+    -PRESHIFT(0x00428000) /* -0.016235352 */,
+     PRESHIFT(0x00500000) /*  0.019531250 */,
+    -PRESHIFT(0x02011000) /* -0.125259399 */,
+    -PRESHIFT(0x003e6000) /* -0.015228271 */,
+    -PRESHIFT(0x0d11e000) /* -0.816864014 */,
+     PRESHIFT(0x116fc000) /*  1.089782715 */,
+     PRESHIFT(0x052c5000) /*  0.323318481 */,
+     PRESHIFT(0x02616000) /*  0.148773193 */,
+     PRESHIFT(0x007d6000) /*  0.030609131 */,
+     PRESHIFT(0x007aa000) /*  0.029937744 */,
+     PRESHIFT(0x00024000) /*  0.000549316 */,
+     PRESHIFT(0x0009a000) /*  0.002349854 */,
+     PRESHIFT(0x0000b000) /*  0.000167847 */,
+
+    -PRESHIFT(0x00002000) /* -0.000030518 */,
+    -PRESHIFT(0x0003f000) /* -0.000961304 */,
+     PRESHIFT(0x000dd000) /*  0.003372192 */,
+    -PRESHIFT(0x00428000) /* -0.016235352 */,
+     PRESHIFT(0x00500000) /*  0.019531250 */,
+    -PRESHIFT(0x02011000) /* -0.125259399 */,
+    -PRESHIFT(0x003e6000) /* -0.015228271 */,
+    -PRESHIFT(0x0d11e000) /* -0.816864014 */,
+     PRESHIFT(0x116fc000) /*  1.089782715 */,
+     PRESHIFT(0x052c5000) /*  0.323318481 */,
+     PRESHIFT(0x02616000) /*  0.148773193 */,
+     PRESHIFT(0x007d6000) /*  0.030609131 */,
+     PRESHIFT(0x007aa000) /*  0.029937744 */,
+     PRESHIFT(0x00024000) /*  0.000549316 */,
+     PRESHIFT(0x0009a000) /*  0.002349854 */,
+     PRESHIFT(0x0000b000) /*  0.000167847 */ },
+
+  { -PRESHIFT(0x00002000) /* -0.000030518 */,	/* 10 */
+    -PRESHIFT(0x00044000) /* -0.001037598 */,
+     PRESHIFT(0x000d7000) /*  0.003280640 */,
+    -PRESHIFT(0x00471000) /* -0.017349243 */,
+     PRESHIFT(0x0046b000) /*  0.017257690 */,
+    -PRESHIFT(0x0212b000) /* -0.129562378 */,
+    -PRESHIFT(0x0084a000) /* -0.032379150 */,
+    -PRESHIFT(0x0d78a000) /* -0.841949463 */,
+     PRESHIFT(0x113be000) /*  1.077117920 */,
+     PRESHIFT(0x04c16000) /*  0.297210693 */,
+     PRESHIFT(0x02687000) /*  0.150497437 */,
+     PRESHIFT(0x0069c000) /*  0.025817871 */,
+     PRESHIFT(0x0077f000) /*  0.029281616 */,
+     PRESHIFT(0x00002000) /*  0.000030518 */,
+     PRESHIFT(0x00093000) /*  0.002243042 */,
+     PRESHIFT(0x0000a000) /*  0.000152588 */,
+
+    -PRESHIFT(0x00002000) /* -0.000030518 */,
+    -PRESHIFT(0x00044000) /* -0.001037598 */,
+     PRESHIFT(0x000d7000) /*  0.003280640 */,
+    -PRESHIFT(0x00471000) /* -0.017349243 */,
+     PRESHIFT(0x0046b000) /*  0.017257690 */,
+    -PRESHIFT(0x0212b000) /* -0.129562378 */,
+    -PRESHIFT(0x0084a000) /* -0.032379150 */,
+    -PRESHIFT(0x0d78a000) /* -0.841949463 */,
+     PRESHIFT(0x113be000) /*  1.077117920 */,
+     PRESHIFT(0x04c16000) /*  0.297210693 */,
+     PRESHIFT(0x02687000) /*  0.150497437 */,
+     PRESHIFT(0x0069c000) /*  0.025817871 */,
+     PRESHIFT(0x0077f000) /*  0.029281616 */,
+     PRESHIFT(0x00002000) /*  0.000030518 */,
+     PRESHIFT(0x00093000) /*  0.002243042 */,
+     PRESHIFT(0x0000a000) /*  0.000152588 */ },
+
+  { -PRESHIFT(0x00003000) /* -0.000045776 */,	/* 11 */
+    -PRESHIFT(0x00049000) /* -0.001113892 */,
+     PRESHIFT(0x000d0000) /*  0.003173828 */,
+    -PRESHIFT(0x004ba000) /* -0.018463135 */,
+     PRESHIFT(0x003ca000) /*  0.014801025 */,
+    -PRESHIFT(0x02233000) /* -0.133590698 */,
+    -PRESHIFT(0x00ce4000) /* -0.050354004 */,
+    -PRESHIFT(0x0ddca000) /* -0.866363525 */,
+     PRESHIFT(0x1102f000) /*  1.063217163 */,
+     PRESHIFT(0x04587000) /*  0.271591187 */,
+     PRESHIFT(0x026cf000) /*  0.151596069 */,
+     PRESHIFT(0x0056c000) /*  0.021179199 */,
+     PRESHIFT(0x0074e000) /*  0.028533936 */,
+    -PRESHIFT(0x0001d000) /* -0.000442505 */,
+     PRESHIFT(0x0008b000) /*  0.002120972 */,
+     PRESHIFT(0x00009000) /*  0.000137329 */,
+
+    -PRESHIFT(0x00003000) /* -0.000045776 */,
+    -PRESHIFT(0x00049000) /* -0.001113892 */,
+     PRESHIFT(0x000d0000) /*  0.003173828 */,
+    -PRESHIFT(0x004ba000) /* -0.018463135 */,
+     PRESHIFT(0x003ca000) /*  0.014801025 */,
+    -PRESHIFT(0x02233000) /* -0.133590698 */,
+    -PRESHIFT(0x00ce4000) /* -0.050354004 */,
+    -PRESHIFT(0x0ddca000) /* -0.866363525 */,
+     PRESHIFT(0x1102f000) /*  1.063217163 */,
+     PRESHIFT(0x04587000) /*  0.271591187 */,
+     PRESHIFT(0x026cf000) /*  0.151596069 */,
+     PRESHIFT(0x0056c000) /*  0.021179199 */,
+     PRESHIFT(0x0074e000) /*  0.028533936 */,
+    -PRESHIFT(0x0001d000) /* -0.000442505 */,
+     PRESHIFT(0x0008b000) /*  0.002120972 */,
+     PRESHIFT(0x00009000) /*  0.000137329 */ },
+
+  { -PRESHIFT(0x00003000) /* -0.000045776 */,	/* 12 */
+    -PRESHIFT(0x0004f000) /* -0.001205444 */,
+     PRESHIFT(0x000c8000) /*  0.003051758 */,
+    -PRESHIFT(0x00503000) /* -0.019577026 */,
+     PRESHIFT(0x0031a000) /*  0.012115479 */,
+    -PRESHIFT(0x02326000) /* -0.137298584 */,
+    -PRESHIFT(0x011b5000) /* -0.069168091 */,
+    -PRESHIFT(0x0e3dd000) /* -0.890090942 */,
+     PRESHIFT(0x10c54000) /*  1.048156738 */,
+     PRESHIFT(0x03f1b000) /*  0.246505737 */,
+     PRESHIFT(0x026ee000) /*  0.152069092 */,
+     PRESHIFT(0x00447000) /*  0.016708374 */,
+     PRESHIFT(0x00719000) /*  0.027725220 */,
+    -PRESHIFT(0x00039000) /* -0.000869751 */,
+     PRESHIFT(0x00084000) /*  0.002014160 */,
+     PRESHIFT(0x00008000) /*  0.000122070 */,
+
+    -PRESHIFT(0x00003000) /* -0.000045776 */,
+    -PRESHIFT(0x0004f000) /* -0.001205444 */,
+     PRESHIFT(0x000c8000) /*  0.003051758 */,
+    -PRESHIFT(0x00503000) /* -0.019577026 */,
+     PRESHIFT(0x0031a000) /*  0.012115479 */,
+    -PRESHIFT(0x02326000) /* -0.137298584 */,
+    -PRESHIFT(0x011b5000) /* -0.069168091 */,
+    -PRESHIFT(0x0e3dd000) /* -0.890090942 */,
+     PRESHIFT(0x10c54000) /*  1.048156738 */,
+     PRESHIFT(0x03f1b000) /*  0.246505737 */,
+     PRESHIFT(0x026ee000) /*  0.152069092 */,
+     PRESHIFT(0x00447000) /*  0.016708374 */,
+     PRESHIFT(0x00719000) /*  0.027725220 */,
+    -PRESHIFT(0x00039000) /* -0.000869751 */,
+     PRESHIFT(0x00084000) /*  0.002014160 */,
+     PRESHIFT(0x00008000) /*  0.000122070 */ },
+
+  { -PRESHIFT(0x00004000) /* -0.000061035 */,	/* 13 */
+    -PRESHIFT(0x00055000) /* -0.001296997 */,
+     PRESHIFT(0x000bd000) /*  0.002883911 */,
+    -PRESHIFT(0x0054c000) /* -0.020690918 */,
+     PRESHIFT(0x0025d000) /*  0.009231567 */,
+    -PRESHIFT(0x02403000) /* -0.140670776 */,
+    -PRESHIFT(0x016ba000) /* -0.088775635 */,
+    -PRESHIFT(0x0e9be000) /* -0.913055420 */,
+     PRESHIFT(0x1082d000) /*  1.031936646 */,
+     PRESHIFT(0x038d4000) /*  0.221984863 */,
+     PRESHIFT(0x026e7000) /*  0.151962280 */,
+     PRESHIFT(0x0032e000) /*  0.012420654 */,
+     PRESHIFT(0x006df000) /*  0.026840210 */,
+    -PRESHIFT(0x00053000) /* -0.001266479 */,
+     PRESHIFT(0x0007d000) /*  0.001907349 */,
+     PRESHIFT(0x00007000) /*  0.000106812 */,
+
+    -PRESHIFT(0x00004000) /* -0.000061035 */,
+    -PRESHIFT(0x00055000) /* -0.001296997 */,
+     PRESHIFT(0x000bd000) /*  0.002883911 */,
+    -PRESHIFT(0x0054c000) /* -0.020690918 */,
+     PRESHIFT(0x0025d000) /*  0.009231567 */,
+    -PRESHIFT(0x02403000) /* -0.140670776 */,
+    -PRESHIFT(0x016ba000) /* -0.088775635 */,
+    -PRESHIFT(0x0e9be000) /* -0.913055420 */,
+     PRESHIFT(0x1082d000) /*  1.031936646 */,
+     PRESHIFT(0x038d4000) /*  0.221984863 */,
+     PRESHIFT(0x026e7000) /*  0.151962280 */,
+     PRESHIFT(0x0032e000) /*  0.012420654 */,
+     PRESHIFT(0x006df000) /*  0.026840210 */,
+    -PRESHIFT(0x00053000) /* -0.001266479 */,
+     PRESHIFT(0x0007d000) /*  0.001907349 */,
+     PRESHIFT(0x00007000) /*  0.000106812 */ },
+
+  { -PRESHIFT(0x00004000) /* -0.000061035 */,	/* 14 */
+    -PRESHIFT(0x0005b000) /* -0.001388550 */,
+     PRESHIFT(0x000b1000) /*  0.002700806 */,
+    -PRESHIFT(0x00594000) /* -0.021789551 */,
+     PRESHIFT(0x00192000) /*  0.006134033 */,
+    -PRESHIFT(0x024c8000) /* -0.143676758 */,
+    -PRESHIFT(0x01bf2000) /* -0.109161377 */,
+    -PRESHIFT(0x0ef69000) /* -0.935195923 */,
+     PRESHIFT(0x103be000) /*  1.014617920 */,
+     PRESHIFT(0x032b4000) /*  0.198059082 */,
+     PRESHIFT(0x026bc000) /*  0.151306152 */,
+     PRESHIFT(0x00221000) /*  0.008316040 */,
+     PRESHIFT(0x006a2000) /*  0.025909424 */,
+    -PRESHIFT(0x0006a000) /* -0.001617432 */,
+     PRESHIFT(0x00075000) /*  0.001785278 */,
+     PRESHIFT(0x00007000) /*  0.000106812 */,
+
+    -PRESHIFT(0x00004000) /* -0.000061035 */,
+    -PRESHIFT(0x0005b000) /* -0.001388550 */,
+     PRESHIFT(0x000b1000) /*  0.002700806 */,
+    -PRESHIFT(0x00594000) /* -0.021789551 */,
+     PRESHIFT(0x00192000) /*  0.006134033 */,
+    -PRESHIFT(0x024c8000) /* -0.143676758 */,
+    -PRESHIFT(0x01bf2000) /* -0.109161377 */,
+    -PRESHIFT(0x0ef69000) /* -0.935195923 */,
+     PRESHIFT(0x103be000) /*  1.014617920 */,
+     PRESHIFT(0x032b4000) /*  0.198059082 */,
+     PRESHIFT(0x026bc000) /*  0.151306152 */,
+     PRESHIFT(0x00221000) /*  0.008316040 */,
+     PRESHIFT(0x006a2000) /*  0.025909424 */,
+    -PRESHIFT(0x0006a000) /* -0.001617432 */,
+     PRESHIFT(0x00075000) /*  0.001785278 */,
+     PRESHIFT(0x00007000) /*  0.000106812 */ },
+
+  { -PRESHIFT(0x00005000) /* -0.000076294 */,	/* 15 */
+    -PRESHIFT(0x00061000) /* -0.001480103 */,
+     PRESHIFT(0x000a3000) /*  0.002487183 */,
+    -PRESHIFT(0x005da000) /* -0.022857666 */,
+     PRESHIFT(0x000b9000) /*  0.002822876 */,
+    -PRESHIFT(0x02571000) /* -0.146255493 */,
+    -PRESHIFT(0x0215c000) /* -0.130310059 */,
+    -PRESHIFT(0x0f4dc000) /* -0.956481934 */,
+     PRESHIFT(0x0ff0a000) /*  0.996246338 */,
+     PRESHIFT(0x02cbf000) /*  0.174789429 */,
+     PRESHIFT(0x0266e000) /*  0.150115967 */,
+     PRESHIFT(0x00120000) /*  0.004394531 */,
+     PRESHIFT(0x00662000) /*  0.024932861 */,
+    -PRESHIFT(0x0007f000) /* -0.001937866 */,
+     PRESHIFT(0x0006f000) /*  0.001693726 */,
+     PRESHIFT(0x00006000) /*  0.000091553 */,
+
+    -PRESHIFT(0x00005000) /* -0.000076294 */,
+    -PRESHIFT(0x00061000) /* -0.001480103 */,
+     PRESHIFT(0x000a3000) /*  0.002487183 */,
+    -PRESHIFT(0x005da000) /* -0.022857666 */,
+     PRESHIFT(0x000b9000) /*  0.002822876 */,
+    -PRESHIFT(0x02571000) /* -0.146255493 */,
+    -PRESHIFT(0x0215c000) /* -0.130310059 */,
+    -PRESHIFT(0x0f4dc000) /* -0.956481934 */,
+     PRESHIFT(0x0ff0a000) /*  0.996246338 */,
+     PRESHIFT(0x02cbf000) /*  0.174789429 */,
+     PRESHIFT(0x0266e000) /*  0.150115967 */,
+     PRESHIFT(0x00120000) /*  0.004394531 */,
+     PRESHIFT(0x00662000) /*  0.024932861 */,
+    -PRESHIFT(0x0007f000) /* -0.001937866 */,
+     PRESHIFT(0x0006f000) /*  0.001693726 */,
+     PRESHIFT(0x00006000) /*  0.000091553 */ },
+
+  { -PRESHIFT(0x00005000) /* -0.000076294 */,	/* 16 */
+    -PRESHIFT(0x00068000) /* -0.001586914 */,
+     PRESHIFT(0x00092000) /*  0.002227783 */,
+    -PRESHIFT(0x0061f000) /* -0.023910522 */,
+    -PRESHIFT(0x0002d000) /* -0.000686646 */,
+    -PRESHIFT(0x025ff000) /* -0.148422241 */,
+    -PRESHIFT(0x026f7000) /* -0.152206421 */,
+    -PRESHIFT(0x0fa13000) /* -0.976852417 */,
+     PRESHIFT(0x0fa13000) /*  0.976852417 */,
+     PRESHIFT(0x026f7000) /*  0.152206421 */,
+     PRESHIFT(0x025ff000) /*  0.148422241 */,
+     PRESHIFT(0x0002d000) /*  0.000686646 */,
+     PRESHIFT(0x0061f000) /*  0.023910522 */,
+    -PRESHIFT(0x00092000) /* -0.002227783 */,
+     PRESHIFT(0x00068000) /*  0.001586914 */,
+     PRESHIFT(0x00005000) /*  0.000076294 */,
+
+    -PRESHIFT(0x00005000) /* -0.000076294 */,
+    -PRESHIFT(0x00068000) /* -0.001586914 */,
+     PRESHIFT(0x00092000) /*  0.002227783 */,
+    -PRESHIFT(0x0061f000) /* -0.023910522 */,
+    -PRESHIFT(0x0002d000) /* -0.000686646 */,
+    -PRESHIFT(0x025ff000) /* -0.148422241 */,
+    -PRESHIFT(0x026f7000) /* -0.152206421 */,
+    -PRESHIFT(0x0fa13000) /* -0.976852417 */,
+     PRESHIFT(0x0fa13000) /*  0.976852417 */,
+     PRESHIFT(0x026f7000) /*  0.152206421 */,
+     PRESHIFT(0x025ff000) /*  0.148422241 */,
+     PRESHIFT(0x0002d000) /*  0.000686646 */,
+     PRESHIFT(0x0061f000) /*  0.023910522 */,
+    -PRESHIFT(0x00092000) /* -0.002227783 */,
+     PRESHIFT(0x00068000) /*  0.001586914 */,
+     PRESHIFT(0x00005000) /*  0.000076294 */ }

+ 235 - 0
libmad/bit.c

@@ -0,0 +1,235 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: bit.c,v 1.12 2004/01/23 09:41:32 rob Exp $
+ */
+
+#include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# ifdef HAVE_LIMITS_H
+#  include <limits.h>
+# else
+#  define CHAR_BIT  8
+# endif
+
+# include "bit.h"
+
+/*
+ * This is the lookup table for computing the CRC-check word.
+ * As described in section 2.4.3.1 and depicted in Figure A.9
+ * of ISO/IEC 11172-3, the generator polynomial is:
+ *
+ * G(X) = X^16 + X^15 + X^2 + 1
+ */
+static
+unsigned short const crc_table[256] = {
+  0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+  0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+  0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+  0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+  0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+  0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+  0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+  0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+
+  0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+  0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+  0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+  0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+  0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+  0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+  0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+  0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+
+  0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+  0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+  0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+  0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+  0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+  0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+  0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+  0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+
+  0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+  0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+  0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+  0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+  0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+  0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+  0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+  0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
+};
+
+# define CRC_POLY  0x8005
+
+/*
+ * NAME:	bit->init()
+ * DESCRIPTION:	initialize bit pointer struct
+ */
+void mad_bit_init(struct mad_bitptr *bitptr, unsigned char const *byte)
+{
+  bitptr->byte  = byte;
+  bitptr->cache = 0;
+  bitptr->left  = CHAR_BIT;
+}
+
+/*
+ * NAME:	bit->length()
+ * DESCRIPTION:	return number of bits between start and end points
+ */
+unsigned int mad_bit_length(struct mad_bitptr const *begin,
+			    struct mad_bitptr const *end)
+{
+  return begin->left +
+    CHAR_BIT * (end->byte - (begin->byte + 1)) + (CHAR_BIT - end->left);
+}
+
+/*
+ * NAME:	bit->nextbyte()
+ * DESCRIPTION:	return pointer to next unprocessed byte
+ */
+unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *bitptr)
+{
+  return bitptr->left == CHAR_BIT ? bitptr->byte : bitptr->byte + 1;
+}
+
+/*
+ * NAME:	bit->skip()
+ * DESCRIPTION:	advance bit pointer
+ */
+void mad_bit_skip(struct mad_bitptr *bitptr, unsigned int len)
+{
+  bitptr->byte += len / CHAR_BIT;
+  bitptr->left -= len % CHAR_BIT;
+
+  if (bitptr->left > CHAR_BIT) {
+    bitptr->byte++;
+    bitptr->left += CHAR_BIT;
+  }
+
+  if (bitptr->left < CHAR_BIT)
+    bitptr->cache = *bitptr->byte;
+}
+
+/*
+ * NAME:	bit->read()
+ * DESCRIPTION:	read an arbitrary number of bits and return their UIMSBF value
+ */
+unsigned long mad_bit_read(struct mad_bitptr *bitptr, unsigned int len)
+{
+  register unsigned long value;
+
+  if (bitptr->left == CHAR_BIT)
+    bitptr->cache = *bitptr->byte;
+
+  if (len < bitptr->left) {
+    value = (bitptr->cache & ((1 << bitptr->left) - 1)) >>
+      (bitptr->left - len);
+    bitptr->left -= len;
+
+    return value;
+  }
+
+  /* remaining bits in current byte */
+
+  value = bitptr->cache & ((1 << bitptr->left) - 1);
+  len  -= bitptr->left;
+
+  bitptr->byte++;
+  bitptr->left = CHAR_BIT;
+
+  /* more bytes */
+
+  while (len >= CHAR_BIT) {
+    value = (value << CHAR_BIT) | *bitptr->byte++;
+    len  -= CHAR_BIT;
+  }
+
+  if (len > 0) {
+    bitptr->cache = *bitptr->byte;
+
+    value = (value << len) | (bitptr->cache >> (CHAR_BIT - len));
+    bitptr->left -= len;
+  }
+
+  return value;
+}
+
+# if 0
+/*
+ * NAME:	bit->write()
+ * DESCRIPTION:	write an arbitrary number of bits
+ */
+void mad_bit_write(struct mad_bitptr *bitptr, unsigned int len,
+		   unsigned long value)
+{
+  unsigned char *ptr;
+
+  ptr = (unsigned char *) bitptr->byte;
+
+  /* ... */
+}
+# endif
+
+/*
+ * NAME:	bit->crc()
+ * DESCRIPTION:	compute CRC-check word
+ */
+unsigned short mad_bit_crc(struct mad_bitptr bitptr, unsigned int len,
+			   unsigned short init)
+{
+  register unsigned int crc;
+
+  for (crc = init; len >= 32; len -= 32) {
+    register unsigned long data;
+
+    data = mad_bit_read(&bitptr, 32);
+
+    crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 24)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >> 16)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >>  8)) & 0xff];
+    crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (data >>  0)) & 0xff];
+  }
+
+  switch (len / 8) {
+  case 3: crc = (crc << 8) ^
+	    crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff];
+  case 2: crc = (crc << 8) ^
+	    crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff];
+  case 1: crc = (crc << 8) ^
+	    crc_table[((crc >> 8) ^ mad_bit_read(&bitptr, 8)) & 0xff];
+
+  len %= 8;
+
+  case 0: break;
+  }
+
+  while (len--) {
+    register unsigned int msb;
+
+    msb = mad_bit_read(&bitptr, 1) ^ (crc >> 15);
+
+    crc <<= 1;
+    if (msb & 1)
+      crc ^= CRC_POLY;
+  }
+
+  return crc & 0xffff;
+}

+ 47 - 0
libmad/bit.h

@@ -0,0 +1,47 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_BIT_H
+# define LIBMAD_BIT_H
+
+struct mad_bitptr {
+  unsigned char const *byte;
+  unsigned short cache;
+  unsigned short left;
+};
+
+void mad_bit_init(struct mad_bitptr *, unsigned char const *);
+
+# define mad_bit_finish(bitptr)		/* nothing */
+
+unsigned int mad_bit_length(struct mad_bitptr const *,
+			    struct mad_bitptr const *);
+
+# define mad_bit_bitsleft(bitptr)  ((bitptr)->left)
+unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *);
+
+void mad_bit_skip(struct mad_bitptr *, unsigned int);
+unsigned long mad_bit_read(struct mad_bitptr *, unsigned int);
+void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long);
+
+unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short);
+
+# endif

+ 580 - 0
libmad/decoder.c

@@ -0,0 +1,580 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: decoder.c,v 1.22 2004/01/23 09:41:32 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+# endif
+
+# ifdef HAVE_SYS_WAIT_H
+#  include <sys/wait.h>
+# endif
+
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+# ifdef HAVE_FCNTL_H
+#  include <fcntl.h>
+# endif
+
+# include <stdlib.h>
+
+# ifdef HAVE_ERRNO_H
+#  include <errno.h>
+# endif
+
+# include "stream.h"
+# include "frame.h"
+# include "synth.h"
+# include "decoder.h"
+
+/*
+ * NAME:	decoder->init()
+ * DESCRIPTION:	initialize a decoder object with callback routines
+ */
+void mad_decoder_init(struct mad_decoder *decoder, void *data,
+		      enum mad_flow (*input_func)(void *,
+						  struct mad_stream *),
+		      enum mad_flow (*header_func)(void *,
+						   struct mad_header const *),
+		      enum mad_flow (*filter_func)(void *,
+						   struct mad_stream const *,
+						   struct mad_frame *),
+		      enum mad_flow (*output_func)(void *,
+						   struct mad_header const *,
+						   struct mad_pcm *),
+		      enum mad_flow (*error_func)(void *,
+						  struct mad_stream *,
+						  struct mad_frame *),
+		      enum mad_flow (*message_func)(void *,
+						    void *, unsigned int *))
+{
+  decoder->mode         = -1;
+
+  decoder->options      = 0;
+
+  decoder->async.pid    = 0;
+  decoder->async.in     = -1;
+  decoder->async.out    = -1;
+
+  decoder->sync         = 0;
+
+  decoder->cb_data      = data;
+
+  decoder->input_func   = input_func;
+  decoder->header_func  = header_func;
+  decoder->filter_func  = filter_func;
+  decoder->output_func  = output_func;
+  decoder->error_func   = error_func;
+  decoder->message_func = message_func;
+}
+
+int mad_decoder_finish(struct mad_decoder *decoder)
+{
+# if defined(USE_ASYNC)
+  if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) {
+    pid_t pid;
+    int status;
+
+    close(decoder->async.in);
+
+    do
+      pid = waitpid(decoder->async.pid, &status, 0);
+    while (pid == -1 && errno == EINTR);
+
+    decoder->mode = -1;
+
+    close(decoder->async.out);
+
+    decoder->async.pid = 0;
+    decoder->async.in  = -1;
+    decoder->async.out = -1;
+
+    if (pid == -1)
+      return -1;
+
+    return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0;
+  }
+# endif
+
+  return 0;
+}
+
+# if defined(USE_ASYNC)
+static
+enum mad_flow send_io(int fd, void const *data, size_t len)
+{
+  char const *ptr = data;
+  ssize_t count;
+
+  while (len) {
+    do
+      count = write(fd, ptr, len);
+    while (count == -1 && errno == EINTR);
+
+    if (count == -1)
+      return MAD_FLOW_BREAK;
+
+    len -= count;
+    ptr += count;
+  }
+
+  return MAD_FLOW_CONTINUE;
+}
+
+static
+enum mad_flow receive_io(int fd, void *buffer, size_t len)
+{
+  char *ptr = buffer;
+  ssize_t count;
+
+  while (len) {
+    do
+      count = read(fd, ptr, len);
+    while (count == -1 && errno == EINTR);
+
+    if (count == -1)
+      return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK;
+    else if (count == 0)
+      return MAD_FLOW_STOP;
+
+    len -= count;
+    ptr += count;
+  }
+
+  return MAD_FLOW_CONTINUE;
+}
+
+static
+enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len)
+{
+  int flags, blocking;
+  enum mad_flow result;
+
+  flags = fcntl(fd, F_GETFL);
+  if (flags == -1)
+    return MAD_FLOW_BREAK;
+
+  blocking = flags & ~O_NONBLOCK;
+
+  if (blocking != flags &&
+      fcntl(fd, F_SETFL, blocking) == -1)
+    return MAD_FLOW_BREAK;
+
+  result = receive_io(fd, buffer, len);
+
+  if (flags != blocking &&
+      fcntl(fd, F_SETFL, flags) == -1)
+    return MAD_FLOW_BREAK;
+
+  return result;
+}
+
+static
+enum mad_flow send(int fd, void const *message, unsigned int size)
+{
+  enum mad_flow result;
+
+  /* send size */
+
+  result = send_io(fd, &size, sizeof(size));
+
+  /* send message */
+
+  if (result == MAD_FLOW_CONTINUE)
+    result = send_io(fd, message, size);
+
+  return result;
+}
+
+static
+enum mad_flow receive(int fd, void **message, unsigned int *size)
+{
+  enum mad_flow result;
+  unsigned int actual;
+
+  if (*message == 0)
+    *size = 0;
+
+  /* receive size */
+
+  result = receive_io(fd, &actual, sizeof(actual));
+
+  /* receive message */
+
+  if (result == MAD_FLOW_CONTINUE) {
+    if (actual > *size)
+      actual -= *size;
+    else {
+      *size  = actual;
+      actual = 0;
+    }
+
+    if (*size > 0) {
+      if (*message == 0) {
+	*message = malloc(*size);
+	if (*message == 0)
+	  return MAD_FLOW_BREAK;
+      }
+
+      result = receive_io_blocking(fd, *message, *size);
+    }
+
+    /* throw away remainder of message */
+
+    while (actual && result == MAD_FLOW_CONTINUE) {
+      char sink[256];
+      unsigned int len;
+
+      len = actual > sizeof(sink) ? sizeof(sink) : actual;
+
+      result = receive_io_blocking(fd, sink, len);
+
+      actual -= len;
+    }
+  }
+
+  return result;
+}
+
+static
+enum mad_flow check_message(struct mad_decoder *decoder)
+{
+  enum mad_flow result;
+  void *message = 0;
+  unsigned int size;
+
+  result = receive(decoder->async.in, &message, &size);
+
+  if (result == MAD_FLOW_CONTINUE) {
+    if (decoder->message_func == 0)
+      size = 0;
+    else {
+      result = decoder->message_func(decoder->cb_data, message, &size);
+
+      if (result == MAD_FLOW_IGNORE ||
+	  result == MAD_FLOW_BREAK)
+	size = 0;
+    }
+
+    if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE)
+      result = MAD_FLOW_BREAK;
+  }
+
+  if (message)
+    free(message);
+
+  return result;
+}
+# endif
+
+static
+enum mad_flow error_default(void *data, struct mad_stream *stream,
+			    struct mad_frame *frame)
+{
+  int *bad_last_frame = data;
+
+  switch (stream->error) {
+  case MAD_ERROR_BADCRC:
+    if (*bad_last_frame)
+      mad_frame_mute(frame);
+    else
+      *bad_last_frame = 1;
+
+    return MAD_FLOW_IGNORE;
+
+  default:
+    return MAD_FLOW_CONTINUE;
+  }
+}
+
+static
+int run_sync(struct mad_decoder *decoder)
+{
+  enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
+  void *error_data;
+  int bad_last_frame = 0;
+  struct mad_stream *stream;
+  struct mad_frame *frame;
+  struct mad_synth *synth;
+  int result = 0;
+
+  if (decoder->input_func == 0)
+    return 0;
+
+  if (decoder->error_func) {
+    error_func = decoder->error_func;
+    error_data = decoder->cb_data;
+  }
+  else {
+    error_func = error_default;
+    error_data = &bad_last_frame;
+  }
+
+  stream = &decoder->sync->stream;
+  frame  = &decoder->sync->frame;
+  synth  = &decoder->sync->synth;
+
+  mad_stream_init(stream);
+  mad_frame_init(frame);
+  mad_synth_init(synth);
+
+  mad_stream_options(stream, decoder->options);
+
+  do {
+    switch (decoder->input_func(decoder->cb_data, stream)) {
+    case MAD_FLOW_STOP:
+      goto done;
+    case MAD_FLOW_BREAK:
+      goto fail;
+    case MAD_FLOW_IGNORE:
+      continue;
+    case MAD_FLOW_CONTINUE:
+      break;
+    }
+
+    while (1) {
+# if defined(USE_ASYNC)
+      if (decoder->mode == MAD_DECODER_MODE_ASYNC) {
+	switch (check_message(decoder)) {
+	case MAD_FLOW_IGNORE:
+	case MAD_FLOW_CONTINUE:
+	  break;
+	case MAD_FLOW_BREAK:
+	  goto fail;
+	case MAD_FLOW_STOP:
+	  goto done;
+	}
+      }
+# endif
+
+      if (decoder->header_func) {
+	if (mad_header_decode(&frame->header, stream) == -1) {
+	  if (!MAD_RECOVERABLE(stream->error))
+	    break;
+
+	  switch (error_func(error_data, stream, frame)) {
+	  case MAD_FLOW_STOP:
+	    goto done;
+	  case MAD_FLOW_BREAK:
+	    goto fail;
+	  case MAD_FLOW_IGNORE:
+	  case MAD_FLOW_CONTINUE:
+	  default:
+	    continue;
+	  }
+	}
+
+	switch (decoder->header_func(decoder->cb_data, &frame->header)) {
+	case MAD_FLOW_STOP:
+	  goto done;
+	case MAD_FLOW_BREAK:
+	  goto fail;
+	case MAD_FLOW_IGNORE:
+	  continue;
+	case MAD_FLOW_CONTINUE:
+	  break;
+	}
+      }
+
+      if (mad_frame_decode(frame, stream) == -1) {
+	if (!MAD_RECOVERABLE(stream->error))
+	  break;
+
+	switch (error_func(error_data, stream, frame)) {
+	case MAD_FLOW_STOP:
+	  goto done;
+	case MAD_FLOW_BREAK:
+	  goto fail;
+	case MAD_FLOW_IGNORE:
+	  break;
+	case MAD_FLOW_CONTINUE:
+	default:
+	  continue;
+	}
+      }
+      else
+	bad_last_frame = 0;
+
+      if (decoder->filter_func) {
+	switch (decoder->filter_func(decoder->cb_data, stream, frame)) {
+	case MAD_FLOW_STOP:
+	  goto done;
+	case MAD_FLOW_BREAK:
+	  goto fail;
+	case MAD_FLOW_IGNORE:
+	  continue;
+	case MAD_FLOW_CONTINUE:
+	  break;
+	}
+      }
+
+      mad_synth_frame(synth, frame);
+
+      if (decoder->output_func) {
+	switch (decoder->output_func(decoder->cb_data,
+				     &frame->header, &synth->pcm)) {
+	case MAD_FLOW_STOP:
+	  goto done;
+	case MAD_FLOW_BREAK:
+	  goto fail;
+	case MAD_FLOW_IGNORE:
+	case MAD_FLOW_CONTINUE:
+	  break;
+	}
+      }
+    }
+  }
+  while (stream->error == MAD_ERROR_BUFLEN);
+
+ fail:
+  result = -1;
+
+ done:
+  mad_synth_finish(synth);
+  mad_frame_finish(frame);
+  mad_stream_finish(stream);
+
+  return result;
+}
+
+# if defined(USE_ASYNC)
+static
+int run_async(struct mad_decoder *decoder)
+{
+  pid_t pid;
+  int ptoc[2], ctop[2], flags;
+
+  if (pipe(ptoc) == -1)
+    return -1;
+
+  if (pipe(ctop) == -1) {
+    close(ptoc[0]);
+    close(ptoc[1]);
+    return -1;
+  }
+
+  flags = fcntl(ptoc[0], F_GETFL);
+  if (flags == -1 ||
+      fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) {
+    close(ctop[0]);
+    close(ctop[1]);
+    close(ptoc[0]);
+    close(ptoc[1]);
+    return -1;
+  }
+
+  pid = fork();
+  if (pid == -1) {
+    close(ctop[0]);
+    close(ctop[1]);
+    close(ptoc[0]);
+    close(ptoc[1]);
+    return -1;
+  }
+
+  decoder->async.pid = pid;
+
+  if (pid) {
+    /* parent */
+
+    close(ptoc[0]);
+    close(ctop[1]);
+
+    decoder->async.in  = ctop[0];
+    decoder->async.out = ptoc[1];
+
+    return 0;
+  }
+
+  /* child */
+
+  close(ptoc[1]);
+  close(ctop[0]);
+
+  decoder->async.in  = ptoc[0];
+  decoder->async.out = ctop[1];
+
+  _exit(run_sync(decoder));
+
+  /* not reached */
+  return -1;
+}
+# endif
+
+/*
+ * NAME:	decoder->run()
+ * DESCRIPTION:	run the decoder thread either synchronously or asynchronously
+ */
+int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode)
+{
+  int result;
+  int (*run)(struct mad_decoder *) = 0;
+
+  switch (decoder->mode = mode) {
+  case MAD_DECODER_MODE_SYNC:
+    run = run_sync;
+    break;
+
+  case MAD_DECODER_MODE_ASYNC:
+# if defined(USE_ASYNC)
+    run = run_async;
+# endif
+    break;
+  }
+
+  if (run == 0)
+    return -1;
+
+  decoder->sync = malloc(sizeof(*decoder->sync));
+  if (decoder->sync == 0)
+    return -1;
+
+  result = run(decoder);
+
+  free(decoder->sync);
+  decoder->sync = 0;
+
+  return result;
+}
+
+/*
+ * NAME:	decoder->message()
+ * DESCRIPTION:	send a message to and receive a reply from the decoder process
+ */
+int mad_decoder_message(struct mad_decoder *decoder,
+			void *message, unsigned int *len)
+{
+# if defined(USE_ASYNC)
+  if (decoder->mode != MAD_DECODER_MODE_ASYNC ||
+      send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE ||
+      receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE)
+    return -1;
+
+  return 0;
+# else
+  return -1;
+# endif
+}

+ 91 - 0
libmad/decoder.h

@@ -0,0 +1,91 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_DECODER_H
+# define LIBMAD_DECODER_H
+
+# include "stream.h"
+# include "frame.h"
+# include "synth.h"
+
+enum mad_decoder_mode {
+  MAD_DECODER_MODE_SYNC  = 0,
+  MAD_DECODER_MODE_ASYNC
+};
+
+enum mad_flow {
+  MAD_FLOW_CONTINUE = 0x0000,	/* continue normally */
+  MAD_FLOW_STOP     = 0x0010,	/* stop decoding normally */
+  MAD_FLOW_BREAK    = 0x0011,	/* stop decoding and signal an error */
+  MAD_FLOW_IGNORE   = 0x0020	/* ignore the current frame */
+};
+
+struct mad_decoder {
+  enum mad_decoder_mode mode;
+
+  int options;
+
+  struct {
+    long pid;
+    int in;
+    int out;
+  } async;
+
+  struct {
+    struct mad_stream stream;
+    struct mad_frame frame;
+    struct mad_synth synth;
+  } *sync;
+
+  void *cb_data;
+
+  enum mad_flow (*input_func)(void *, struct mad_stream *);
+  enum mad_flow (*header_func)(void *, struct mad_header const *);
+  enum mad_flow (*filter_func)(void *,
+			       struct mad_stream const *, struct mad_frame *);
+  enum mad_flow (*output_func)(void *,
+			       struct mad_header const *, struct mad_pcm *);
+  enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
+  enum mad_flow (*message_func)(void *, void *, unsigned int *);
+};
+
+void mad_decoder_init(struct mad_decoder *, void *,
+		      enum mad_flow (*)(void *, struct mad_stream *),
+		      enum mad_flow (*)(void *, struct mad_header const *),
+		      enum mad_flow (*)(void *,
+					struct mad_stream const *,
+					struct mad_frame *),
+		      enum mad_flow (*)(void *,
+					struct mad_header const *,
+					struct mad_pcm *),
+		      enum mad_flow (*)(void *,
+					struct mad_stream *,
+					struct mad_frame *),
+		      enum mad_flow (*)(void *, void *, unsigned int *));
+int mad_decoder_finish(struct mad_decoder *);
+
+# define mad_decoder_options(decoder, opts)  \
+    ((void) ((decoder)->options = (opts)))
+
+int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode);
+int mad_decoder_message(struct mad_decoder *, void *, unsigned int *);
+
+# endif

+ 79 - 0
libmad/fixed.c

@@ -0,0 +1,79 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: fixed.c,v 1.13 2004/01/23 09:41:32 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# include "fixed.h"
+
+/*
+ * NAME:	fixed->abs()
+ * DESCRIPTION:	return absolute value of a fixed-point number
+ */
+mad_fixed_t mad_f_abs(mad_fixed_t x)
+{
+  return x < 0 ? -x : x;
+}
+
+/*
+ * NAME:	fixed->div()
+ * DESCRIPTION:	perform division using fixed-point math
+ */
+mad_fixed_t mad_f_div(mad_fixed_t x, mad_fixed_t y)
+{
+  mad_fixed_t q, r;
+  unsigned int bits;
+
+  q = mad_f_abs(x / y);
+
+  if (x < 0) {
+    x = -x;
+    y = -y;
+  }
+
+  r = x % y;
+
+  if (y < 0) {
+    x = -x;
+    y = -y;
+  }
+
+  if (q > mad_f_intpart(MAD_F_MAX) &&
+      !(q == -mad_f_intpart(MAD_F_MIN) && r == 0 && (x < 0) != (y < 0)))
+    return 0;
+
+  for (bits = MAD_F_FRACBITS; bits && r; --bits) {
+    q <<= 1, r <<= 1;
+    if (r >= y)
+      r -= y, ++q;
+  }
+
+  /* round */
+  if (2 * r >= y)
+    ++q;
+
+  /* fix sign */
+  if ((x < 0) != (y < 0))
+    q = -q;
+
+  return q << bits;
+}

+ 499 - 0
libmad/fixed.h

@@ -0,0 +1,499 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp $
+ */
+
+# ifndef LIBMAD_FIXED_H
+# define LIBMAD_FIXED_H
+
+# if SIZEOF_INT >= 4
+typedef   signed int mad_fixed_t;
+
+typedef   signed int mad_fixed64hi_t;
+typedef unsigned int mad_fixed64lo_t;
+# else
+typedef   signed long mad_fixed_t;
+
+typedef   signed long mad_fixed64hi_t;
+typedef unsigned long mad_fixed64lo_t;
+# endif
+
+# if defined(_MSC_VER)
+#  define mad_fixed64_t  signed __int64
+# elif 1 || defined(__GNUC__)
+#  define mad_fixed64_t  signed long long
+# endif
+
+# if defined(FPM_FLOAT)
+typedef double mad_sample_t;
+# else
+typedef mad_fixed_t mad_sample_t;
+# endif
+
+/*
+ * Fixed-point format: 0xABBBBBBB
+ * A == whole part      (sign + 3 bits)
+ * B == fractional part (28 bits)
+ *
+ * Values are signed two's complement, so the effective range is:
+ * 0x80000000 to 0x7fffffff
+ *       -8.0 to +7.9999999962747097015380859375
+ *
+ * The smallest representable value is:
+ * 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9)
+ *
+ * 28 bits of fractional accuracy represent about
+ * 8.6 digits of decimal accuracy.
+ *
+ * Fixed-point numbers can be added or subtracted as normal
+ * integers, but multiplication requires shifting the 64-bit result
+ * from 56 fractional bits back to 28 (and rounding.)
+ *
+ * Changing the definition of MAD_F_FRACBITS is only partially
+ * supported, and must be done with care.
+ */
+
+# define MAD_F_FRACBITS		28
+
+# if MAD_F_FRACBITS == 28
+#  define MAD_F(x)		((mad_fixed_t) (x##L))
+# else
+#  if MAD_F_FRACBITS < 28
+#   warning "MAD_F_FRACBITS < 28"
+#   define MAD_F(x)		((mad_fixed_t)  \
+				 (((x##L) +  \
+				   (1L << (28 - MAD_F_FRACBITS - 1))) >>  \
+				  (28 - MAD_F_FRACBITS)))
+#  elif MAD_F_FRACBITS > 28
+#   error "MAD_F_FRACBITS > 28 not currently supported"
+#   define MAD_F(x)		((mad_fixed_t)  \
+				 ((x##L) << (MAD_F_FRACBITS - 28)))
+#  endif
+# endif
+
+# define MAD_F_MIN		((mad_fixed_t) -0x80000000L)
+# define MAD_F_MAX		((mad_fixed_t) +0x7fffffffL)
+
+# define MAD_F_ONE		MAD_F(0x10000000)
+
+# define mad_f_tofixed(x)	((mad_fixed_t)  \
+				 ((x) * (double) (1L << MAD_F_FRACBITS) + 0.5))
+# define mad_f_todouble(x)	((double)  \
+				 ((x) / (double) (1L << MAD_F_FRACBITS)))
+
+# define mad_f_intpart(x)	((x) >> MAD_F_FRACBITS)
+# define mad_f_fracpart(x)	((x) & ((1L << MAD_F_FRACBITS) - 1))
+				/* (x should be positive) */
+
+# define mad_f_fromint(x)	((x) << MAD_F_FRACBITS)
+
+# define mad_f_add(x, y)	((x) + (y))
+# define mad_f_sub(x, y)	((x) - (y))
+
+# if defined(FPM_FLOAT)
+#  error "FPM_FLOAT not yet supported"
+
+#  undef MAD_F
+#  define MAD_F(x)		mad_f_todouble(x)
+
+#  define mad_f_mul(x, y)	((x) * (y))
+#  define mad_f_scale64
+
+#  undef ASO_ZEROCHECK
+
+# elif defined(FPM_64BIT)
+
+/*
+ * This version should be the most accurate if 64-bit types are supported by
+ * the compiler, although it may not be the most efficient.
+ */
+#  if defined(OPT_ACCURACY)
+#   define mad_f_mul(x, y)  \
+    ((mad_fixed_t)  \
+     ((((mad_fixed64_t) (x) * (y)) +  \
+       (1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS))
+#  else
+#   define mad_f_mul(x, y)  \
+    ((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS))
+#  endif
+
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+
+/* --- Intel --------------------------------------------------------------- */
+
+# elif defined(FPM_INTEL)
+
+#  if defined(_MSC_VER)
+#   pragma warning(push)
+#   pragma warning(disable: 4035)  /* no return value */
+static __forceinline
+mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y)
+{
+  enum {
+    fracbits = MAD_F_FRACBITS
+  };
+
+  __asm {
+    mov eax, x
+    imul y
+    shrd eax, edx, fracbits
+  }
+
+  /* implicit return of eax */
+}
+#   pragma warning(pop)
+
+#   define mad_f_mul		mad_f_mul_inline
+#   define mad_f_scale64
+#  else
+/*
+ * This Intel version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#   define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("imull %3"  \
+	 : "=a" (lo), "=d" (hi)  \
+	 : "%a" (x), "rm" (y)  \
+	 : "cc")
+
+#   if defined(OPT_ACCURACY)
+/*
+ * This gives best accuracy but is not very fast.
+ */
+#    define MAD_F_MLA(hi, lo, x, y)  \
+    ({ mad_fixed64hi_t __hi;  \
+       mad_fixed64lo_t __lo;  \
+       MAD_F_MLX(__hi, __lo, (x), (y));  \
+       asm ("addl %2,%0\n\t"  \
+	    "adcl %3,%1"  \
+	    : "=rm" (lo), "=rm" (hi)  \
+	    : "r" (__lo), "r" (__hi), "0" (lo), "1" (hi)  \
+	    : "cc");  \
+    })
+#   endif  /* OPT_ACCURACY */
+
+#   if defined(OPT_ACCURACY)
+/*
+ * Surprisingly, this is faster than SHRD followed by ADC.
+ */
+#    define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed64hi_t __hi_;  \
+       mad_fixed64lo_t __lo_;  \
+       mad_fixed_t __result;  \
+       asm ("addl %4,%2\n\t"  \
+	    "adcl %5,%3"  \
+	    : "=rm" (__lo_), "=rm" (__hi_)  \
+	    : "0" (lo), "1" (hi),  \
+	      "ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0)  \
+	    : "cc");  \
+       asm ("shrdl %3,%2,%1"  \
+	    : "=rm" (__result)  \
+	    : "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+#   elif defined(OPT_INTEL)
+/*
+ * Alternate Intel scaling that may or may not perform better.
+ */
+#    define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("shrl %3,%1\n\t"  \
+	    "shll %4,%2\n\t"  \
+	    "orl %2,%1"  \
+	    : "=rm" (__result)  \
+	    : "0" (lo), "r" (hi),  \
+	      "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+#   else
+#    define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("shrdl %3,%2,%1"  \
+	    : "=rm" (__result)  \
+	    : "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+#   endif  /* OPT_ACCURACY */
+
+#   define MAD_F_SCALEBITS  MAD_F_FRACBITS
+#  endif
+
+/* --- ARM ----------------------------------------------------------------- */
+
+# elif defined(FPM_ARM)
+
+/* 
+ * This ARM V4 version is as accurate as FPM_64BIT but much faster. The
+ * least significant bit is properly rounded at no CPU cycle cost!
+ */
+# if 1
+/*
+ * This is faster than the default implementation via MAD_F_MLX() and
+ * mad_f_scale64().
+ */
+#  define mad_f_mul(x, y)  \
+    ({ mad_fixed64hi_t __hi;  \
+       mad_fixed64lo_t __lo;  \
+       mad_fixed_t __result;  \
+       asm ("smull	%0, %1, %3, %4\n\t"  \
+	    "movs	%0, %0, lsr %5\n\t"  \
+	    "adc	%2, %0, %1, lsl %6"  \
+	    : "=&r" (__lo), "=&r" (__hi), "=r" (__result)  \
+	    : "%r" (x), "r" (y),  \
+	      "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+# endif
+
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("smull	%0, %1, %2, %3"  \
+	 : "=&r" (lo), "=&r" (hi)  \
+	 : "%r" (x), "r" (y))
+
+#  define MAD_F_MLA(hi, lo, x, y)  \
+    asm ("smlal	%0, %1, %2, %3"  \
+	 : "+r" (lo), "+r" (hi)  \
+	 : "%r" (x), "r" (y))
+
+#  define MAD_F_MLN(hi, lo)  \
+    asm ("rsbs	%0, %2, #0\n\t"  \
+	 "rsc	%1, %3, #0"  \
+	 : "=r" (lo), "=r" (hi)  \
+	 : "0" (lo), "1" (hi)  \
+	 : "cc")
+
+#  define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("movs	%0, %1, lsr %3\n\t"  \
+	    "adc	%0, %0, %2, lsl %4"  \
+	    : "=&r" (__result)  \
+	    : "r" (lo), "r" (hi),  \
+	      "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+
+/* --- MIPS ---------------------------------------------------------------- */
+
+# elif defined(FPM_MIPS)
+
+/*
+ * This MIPS version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("mult	%2,%3"  \
+	 : "=l" (lo), "=h" (hi)  \
+	 : "%r" (x), "r" (y))
+
+# if defined(HAVE_MADD_ASM)
+#  define MAD_F_MLA(hi, lo, x, y)  \
+    asm ("madd	%2,%3"  \
+	 : "+l" (lo), "+h" (hi)  \
+	 : "%r" (x), "r" (y))
+# elif defined(HAVE_MADD16_ASM)
+/*
+ * This loses significant accuracy due to the 16-bit integer limit in the
+ * multiply/accumulate instruction.
+ */
+#  define MAD_F_ML0(hi, lo, x, y)  \
+    asm ("mult	%2,%3"  \
+	 : "=l" (lo), "=h" (hi)  \
+	 : "%r" ((x) >> 12), "r" ((y) >> 16))
+#  define MAD_F_MLA(hi, lo, x, y)  \
+    asm ("madd16	%2,%3"  \
+	 : "+l" (lo), "+h" (hi)  \
+	 : "%r" ((x) >> 12), "r" ((y) >> 16))
+#  define MAD_F_MLZ(hi, lo)  ((mad_fixed_t) (lo))
+# endif
+
+# if defined(OPT_SPEED)
+#  define mad_f_scale64(hi, lo)  \
+    ((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS)))
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+# endif
+
+/* --- SPARC --------------------------------------------------------------- */
+
+# elif defined(FPM_SPARC)
+
+/*
+ * This SPARC V8 version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("smul %2, %3, %0\n\t"  \
+	 "rd %%y, %1"  \
+	 : "=r" (lo), "=r" (hi)  \
+	 : "%r" (x), "rI" (y))
+
+/* --- PowerPC ------------------------------------------------------------- */
+
+# elif defined(FPM_PPC)
+
+/*
+ * This PowerPC version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    do {  \
+      asm ("mullw %0,%1,%2"  \
+	   : "=r" (lo)  \
+	   : "%r" (x), "r" (y));  \
+      asm ("mulhw %0,%1,%2"  \
+	   : "=r" (hi)  \
+	   : "%r" (x), "r" (y));  \
+    }  \
+    while (0)
+
+#  if defined(OPT_ACCURACY)
+/*
+ * This gives best accuracy but is not very fast.
+ */
+#   define MAD_F_MLA(hi, lo, x, y)  \
+    ({ mad_fixed64hi_t __hi;  \
+       mad_fixed64lo_t __lo;  \
+       MAD_F_MLX(__hi, __lo, (x), (y));  \
+       asm ("addc %0,%2,%3\n\t"  \
+	    "adde %1,%4,%5"  \
+	    : "=r" (lo), "=r" (hi)  \
+	    : "%r" (lo), "r" (__lo),  \
+	      "%r" (hi), "r" (__hi)  \
+	    : "xer");  \
+    })
+#  endif
+
+#  if defined(OPT_ACCURACY)
+/*
+ * This is slower than the truncating version below it.
+ */
+#   define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result, __round;  \
+       asm ("rotrwi %0,%1,%2"  \
+	    : "=r" (__result)  \
+	    : "r" (lo), "i" (MAD_F_SCALEBITS));  \
+       asm ("extrwi %0,%1,1,0"  \
+	    : "=r" (__round)  \
+	    : "r" (__result));  \
+       asm ("insrwi %0,%1,%2,0"  \
+	    : "+r" (__result)  \
+	    : "r" (hi), "i" (MAD_F_SCALEBITS));  \
+       asm ("add %0,%1,%2"  \
+	    : "=r" (__result)  \
+	    : "%r" (__result), "r" (__round));  \
+       __result;  \
+    })
+#  else
+#   define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("rotrwi %0,%1,%2"  \
+	    : "=r" (__result)  \
+	    : "r" (lo), "i" (MAD_F_SCALEBITS));  \
+       asm ("insrwi %0,%1,%2,0"  \
+	    : "+r" (__result)  \
+	    : "r" (hi), "i" (MAD_F_SCALEBITS));  \
+       __result;  \
+    })
+#  endif
+
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+
+/* --- Default ------------------------------------------------------------- */
+
+# elif defined(FPM_DEFAULT)
+
+/*
+ * This version is the most portable but it loses significant accuracy.
+ * Furthermore, accuracy is biased against the second argument, so care
+ * should be taken when ordering operands.
+ *
+ * The scale factors are constant as this is not used with SSO.
+ *
+ * Pre-rounding is required to stay within the limits of compliance.
+ */
+#  if defined(OPT_SPEED)
+#   define mad_f_mul(x, y)	(((x) >> 12) * ((y) >> 16))
+#  else
+#   define mad_f_mul(x, y)	((((x) + (1L << 11)) >> 12) *  \
+				 (((y) + (1L << 15)) >> 16))
+#  endif
+
+/* ------------------------------------------------------------------------- */
+
+# else
+#  error "no FPM selected"
+# endif
+
+/* default implementations */
+
+# if !defined(mad_f_mul)
+#  define mad_f_mul(x, y)  \
+    ({ register mad_fixed64hi_t __hi;  \
+       register mad_fixed64lo_t __lo;  \
+       MAD_F_MLX(__hi, __lo, (x), (y));  \
+       mad_f_scale64(__hi, __lo);  \
+    })
+# endif
+
+# if !defined(MAD_F_MLA)
+#  define MAD_F_ML0(hi, lo, x, y)	((lo)  = mad_f_mul((x), (y)))
+#  define MAD_F_MLA(hi, lo, x, y)	((lo) += mad_f_mul((x), (y)))
+#  define MAD_F_MLN(hi, lo)		((lo)  = -(lo))
+#  define MAD_F_MLZ(hi, lo)		((void) (hi), (mad_fixed_t) (lo))
+# endif
+
+# if !defined(MAD_F_ML0)
+#  define MAD_F_ML0(hi, lo, x, y)	MAD_F_MLX((hi), (lo), (x), (y))
+# endif
+
+# if !defined(MAD_F_MLN)
+#  define MAD_F_MLN(hi, lo)		((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi))
+# endif
+
+# if !defined(MAD_F_MLZ)
+#  define MAD_F_MLZ(hi, lo)		mad_f_scale64((hi), (lo))
+# endif
+
+# if !defined(mad_f_scale64)
+#  if defined(OPT_ACCURACY)
+#   define mad_f_scale64(hi, lo)  \
+    ((((mad_fixed_t)  \
+       (((hi) << (32 - (MAD_F_SCALEBITS - 1))) |  \
+	((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1)
+#  else
+#   define mad_f_scale64(hi, lo)  \
+    ((mad_fixed_t)  \
+     (((hi) << (32 - MAD_F_SCALEBITS)) |  \
+      ((lo) >> MAD_F_SCALEBITS)))
+#  endif
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+# endif
+
+/* C routines */
+
+mad_fixed_t mad_f_abs(mad_fixed_t);
+mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t);
+
+# endif

+ 501 - 0
libmad/frame.c

@@ -0,0 +1,501 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: frame.c,v 1.29 2004/02/04 22:59:19 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# include <stdlib.h>
+
+# include "bit.h"
+# include "stream.h"
+# include "frame.h"
+# include "timer.h"
+# include "layer12.h"
+# include "layer3.h"
+
+static
+unsigned long const bitrate_table[5][15] = {
+  /* MPEG-1 */
+  { 0,  32000,  64000,  96000, 128000, 160000, 192000, 224000,  /* Layer I   */
+       256000, 288000, 320000, 352000, 384000, 416000, 448000 },
+  { 0,  32000,  48000,  56000,  64000,  80000,  96000, 112000,  /* Layer II  */
+       128000, 160000, 192000, 224000, 256000, 320000, 384000 },
+  { 0,  32000,  40000,  48000,  56000,  64000,  80000,  96000,  /* Layer III */
+       112000, 128000, 160000, 192000, 224000, 256000, 320000 },
+
+  /* MPEG-2 LSF */
+  { 0,  32000,  48000,  56000,  64000,  80000,  96000, 112000,  /* Layer I   */
+       128000, 144000, 160000, 176000, 192000, 224000, 256000 },
+  { 0,   8000,  16000,  24000,  32000,  40000,  48000,  56000,  /* Layers    */
+        64000,  80000,  96000, 112000, 128000, 144000, 160000 } /* II & III  */
+};
+
+static
+unsigned int const samplerate_table[3] = { 44100, 48000, 32000 };
+
+static
+int (*const decoder_table[3])(struct mad_stream *, struct mad_frame *) = {
+  mad_layer_I,
+  mad_layer_II,
+  mad_layer_III
+};
+
+/*
+ * NAME:	header->init()
+ * DESCRIPTION:	initialize header struct
+ */
+void mad_header_init(struct mad_header *header)
+{
+  header->layer          = 0;
+  header->mode           = 0;
+  header->mode_extension = 0;
+  header->emphasis       = 0;
+
+  header->bitrate        = 0;
+  header->samplerate     = 0;
+
+  header->crc_check      = 0;
+  header->crc_target     = 0;
+
+  header->flags          = 0;
+  header->private_bits   = 0;
+
+  header->duration       = mad_timer_zero;
+}
+
+/*
+ * NAME:	frame->init()
+ * DESCRIPTION:	initialize frame struct
+ */
+void mad_frame_init(struct mad_frame *frame)
+{
+  mad_header_init(&frame->header);
+
+  frame->options = 0;
+
+  frame->overlap = 0;
+  mad_frame_mute(frame);
+}
+
+/*
+ * NAME:	frame->finish()
+ * DESCRIPTION:	deallocate any dynamic memory associated with frame
+ */
+void mad_frame_finish(struct mad_frame *frame)
+{
+  mad_header_finish(&frame->header);
+
+  if (frame->overlap) {
+    free(frame->overlap);
+    frame->overlap = 0;
+  }
+}
+
+/*
+ * NAME:	decode_header()
+ * DESCRIPTION:	read header data and following CRC word
+ */
+static
+int decode_header(struct mad_header *header, struct mad_stream *stream)
+{
+  unsigned int index;
+
+  header->flags        = 0;
+  header->private_bits = 0;
+
+  /* header() */
+
+  /* syncword */
+  mad_bit_skip(&stream->ptr, 11);
+
+  /* MPEG 2.5 indicator (really part of syncword) */
+  if (mad_bit_read(&stream->ptr, 1) == 0)
+    header->flags |= MAD_FLAG_MPEG_2_5_EXT;
+
+  /* ID */
+  if (mad_bit_read(&stream->ptr, 1) == 0)
+    header->flags |= MAD_FLAG_LSF_EXT;
+  else if (header->flags & MAD_FLAG_MPEG_2_5_EXT) {
+    stream->error = MAD_ERROR_LOSTSYNC;
+    return -1;
+  }
+
+  /* layer */
+  header->layer = 4 - mad_bit_read(&stream->ptr, 2);
+
+  if (header->layer == 4) {
+    stream->error = MAD_ERROR_BADLAYER;
+    return -1;
+  }
+
+  /* protection_bit */
+  if (mad_bit_read(&stream->ptr, 1) == 0) {
+    header->flags    |= MAD_FLAG_PROTECTION;
+    header->crc_check = mad_bit_crc(stream->ptr, 16, 0xffff);
+  }
+
+  /* bitrate_index */
+  index = mad_bit_read(&stream->ptr, 4);
+
+  if (index == 15) {
+    stream->error = MAD_ERROR_BADBITRATE;
+    return -1;
+  }
+
+  if (header->flags & MAD_FLAG_LSF_EXT)
+    header->bitrate = bitrate_table[3 + (header->layer >> 1)][index];
+  else
+    header->bitrate = bitrate_table[header->layer - 1][index];
+
+  /* sampling_frequency */
+  index = mad_bit_read(&stream->ptr, 2);
+
+  if (index == 3) {
+    stream->error = MAD_ERROR_BADSAMPLERATE;
+    return -1;
+  }
+
+  header->samplerate = samplerate_table[index];
+
+  if (header->flags & MAD_FLAG_LSF_EXT) {
+    header->samplerate /= 2;
+
+    if (header->flags & MAD_FLAG_MPEG_2_5_EXT)
+      header->samplerate /= 2;
+  }
+
+  /* padding_bit */
+  if (mad_bit_read(&stream->ptr, 1))
+    header->flags |= MAD_FLAG_PADDING;
+
+  /* private_bit */
+  if (mad_bit_read(&stream->ptr, 1))
+    header->private_bits |= MAD_PRIVATE_HEADER;
+
+  /* mode */
+  header->mode = 3 - mad_bit_read(&stream->ptr, 2);
+
+  /* mode_extension */
+  header->mode_extension = mad_bit_read(&stream->ptr, 2);
+
+  /* copyright */
+  if (mad_bit_read(&stream->ptr, 1))
+    header->flags |= MAD_FLAG_COPYRIGHT;
+
+  /* original/copy */
+  if (mad_bit_read(&stream->ptr, 1))
+    header->flags |= MAD_FLAG_ORIGINAL;
+
+  /* emphasis */
+  header->emphasis = mad_bit_read(&stream->ptr, 2);
+
+# if defined(OPT_STRICT)
+  /*
+   * ISO/IEC 11172-3 says this is a reserved emphasis value, but
+   * streams exist which use it anyway. Since the value is not important
+   * to the decoder proper, we allow it unless OPT_STRICT is defined.
+   */
+  if (header->emphasis == MAD_EMPHASIS_RESERVED) {
+    stream->error = MAD_ERROR_BADEMPHASIS;
+    return -1;
+  }
+# endif
+
+  /* error_check() */
+
+  /* crc_check */
+  if (header->flags & MAD_FLAG_PROTECTION)
+    header->crc_target = mad_bit_read(&stream->ptr, 16);
+
+  return 0;
+}
+
+/*
+ * NAME:	free_bitrate()
+ * DESCRIPTION:	attempt to discover the bitstream's free bitrate
+ */
+static
+int free_bitrate(struct mad_stream *stream, struct mad_header const *header)
+{
+  struct mad_bitptr keep_ptr;
+  unsigned long rate = 0;
+  unsigned int pad_slot, slots_per_frame;
+  unsigned char const *ptr = 0;
+
+  keep_ptr = stream->ptr;
+
+  pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0;
+  slots_per_frame = (header->layer == MAD_LAYER_III &&
+		     (header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144;
+
+  while (mad_stream_sync(stream) == 0) {
+    struct mad_stream peek_stream;
+    struct mad_header peek_header;
+
+    peek_stream = *stream;
+    peek_header = *header;
+
+    if (decode_header(&peek_header, &peek_stream) == 0 &&
+	peek_header.layer == header->layer &&
+	peek_header.samplerate == header->samplerate) {
+      unsigned int N;
+
+      ptr = mad_bit_nextbyte(&stream->ptr);
+
+      N = ptr - stream->this_frame;
+
+      if (header->layer == MAD_LAYER_I) {
+	rate = (unsigned long) header->samplerate *
+	  (N - 4 * pad_slot + 4) / 48 / 1000;
+      }
+      else {
+	rate = (unsigned long) header->samplerate *
+	  (N - pad_slot + 1) / slots_per_frame / 1000;
+      }
+
+      if (rate >= 8)
+	break;
+    }
+
+    mad_bit_skip(&stream->ptr, 8);
+  }
+
+  stream->ptr = keep_ptr;
+
+  if (rate < 8 || (header->layer == MAD_LAYER_III && rate > 640)) {
+    stream->error = MAD_ERROR_LOSTSYNC;
+    return -1;
+  }
+
+  stream->freerate = rate * 1000;
+
+  return 0;
+}
+
+/*
+ * NAME:	header->decode()
+ * DESCRIPTION:	read the next frame header from the stream
+ */
+int mad_header_decode(struct mad_header *header, struct mad_stream *stream)
+{
+  register unsigned char const *ptr, *end;
+  unsigned int pad_slot, N;
+
+  ptr = stream->next_frame;
+  end = stream->bufend;
+
+  if (ptr == 0) {
+    stream->error = MAD_ERROR_BUFPTR;
+    goto fail;
+  }
+
+  /* stream skip */
+  if (stream->skiplen) {
+    if (!stream->sync)
+      ptr = stream->this_frame;
+
+    if (end - ptr < stream->skiplen) {
+      stream->skiplen   -= end - ptr;
+      stream->next_frame = end;
+
+      stream->error = MAD_ERROR_BUFLEN;
+      goto fail;
+    }
+
+    ptr += stream->skiplen;
+    stream->skiplen = 0;
+
+    stream->sync = 1;
+  }
+
+ sync:
+  /* synchronize */
+  if (stream->sync) {
+    if (end - ptr < MAD_BUFFER_GUARD) {
+      stream->next_frame = ptr;
+
+      stream->error = MAD_ERROR_BUFLEN;
+      goto fail;
+    }
+    else if (!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) {
+      /* mark point where frame sync word was expected */
+      stream->this_frame = ptr;
+      stream->next_frame = ptr + 1;
+
+      stream->error = MAD_ERROR_LOSTSYNC;
+      goto fail;
+    }
+  }
+  else {
+    mad_bit_init(&stream->ptr, ptr);
+
+    if (mad_stream_sync(stream) == -1) {
+      if (end - stream->next_frame >= MAD_BUFFER_GUARD)
+	stream->next_frame = end - MAD_BUFFER_GUARD;
+
+      stream->error = MAD_ERROR_BUFLEN;
+      goto fail;
+    }
+
+    ptr = mad_bit_nextbyte(&stream->ptr);
+  }
+
+  /* begin processing */
+  stream->this_frame = ptr;
+  stream->next_frame = ptr + 1;  /* possibly bogus sync word */
+
+  mad_bit_init(&stream->ptr, stream->this_frame);
+
+  if (decode_header(header, stream) == -1)
+    goto fail;
+
+  /* calculate frame duration */
+  mad_timer_set(&header->duration, 0,
+		32 * MAD_NSBSAMPLES(header), header->samplerate);
+
+  /* calculate free bit rate */
+  if (header->bitrate == 0) {
+    if ((stream->freerate == 0 || !stream->sync ||
+	 (header->layer == MAD_LAYER_III && stream->freerate > 640000)) &&
+	free_bitrate(stream, header) == -1)
+      goto fail;
+
+    header->bitrate = stream->freerate;
+    header->flags  |= MAD_FLAG_FREEFORMAT;
+  }
+
+  /* calculate beginning of next frame */
+  pad_slot = (header->flags & MAD_FLAG_PADDING) ? 1 : 0;
+
+  if (header->layer == MAD_LAYER_I)
+    N = ((12 * header->bitrate / header->samplerate) + pad_slot) * 4;
+  else {
+    unsigned int slots_per_frame;
+
+    slots_per_frame = (header->layer == MAD_LAYER_III &&
+		       (header->flags & MAD_FLAG_LSF_EXT)) ? 72 : 144;
+
+    N = (slots_per_frame * header->bitrate / header->samplerate) + pad_slot;
+  }
+
+  /* verify there is enough data left in buffer to decode this frame */
+  if (N + MAD_BUFFER_GUARD > end - stream->this_frame) {
+    stream->next_frame = stream->this_frame;
+
+    stream->error = MAD_ERROR_BUFLEN;
+    goto fail;
+  }
+
+  stream->next_frame = stream->this_frame + N;
+
+  if (!stream->sync) {
+    /* check that a valid frame header follows this frame */
+
+    ptr = stream->next_frame;
+    if (!(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0)) {
+      ptr = stream->next_frame = stream->this_frame + 1;
+      goto sync;
+    }
+
+    stream->sync = 1;
+  }
+
+  header->flags |= MAD_FLAG_INCOMPLETE;
+
+  return 0;
+
+ fail:
+  stream->sync = 0;
+
+  return -1;
+}
+
+/*
+ * NAME:	frame->decode()
+ * DESCRIPTION:	decode a single frame from a bitstream
+ */
+int mad_frame_decode(struct mad_frame *frame, struct mad_stream *stream)
+{
+  frame->options = stream->options;
+
+  /* header() */
+  /* error_check() */
+
+  if (!(frame->header.flags & MAD_FLAG_INCOMPLETE) &&
+      mad_header_decode(&frame->header, stream) == -1)
+    goto fail;
+
+  /* audio_data() */
+
+  frame->header.flags &= ~MAD_FLAG_INCOMPLETE;
+
+  if (decoder_table[frame->header.layer - 1](stream, frame) == -1) {
+    if (!MAD_RECOVERABLE(stream->error))
+      stream->next_frame = stream->this_frame;
+
+    goto fail;
+  }
+
+  /* ancillary_data() */
+
+  if (frame->header.layer != MAD_LAYER_III) {
+    struct mad_bitptr next_frame;
+
+    mad_bit_init(&next_frame, stream->next_frame);
+
+    stream->anc_ptr    = stream->ptr;
+    stream->anc_bitlen = mad_bit_length(&stream->ptr, &next_frame);
+
+    mad_bit_finish(&next_frame);
+  }
+
+  return 0;
+
+ fail:
+  stream->anc_bitlen = 0;
+  return -1;
+}
+
+/*
+ * NAME:	frame->mute()
+ * DESCRIPTION:	zero all subband values so the frame becomes silent
+ */
+void mad_frame_mute(struct mad_frame *frame)
+{
+  unsigned int s, sb;
+
+  for (s = 0; s < 36; ++s) {
+    for (sb = 0; sb < 32; ++sb) {
+      frame->sbsample[0][s][sb] =
+      frame->sbsample[1][s][sb] = 0;
+    }
+  }
+
+  if (frame->overlap) {
+    for (s = 0; s < 18; ++s) {
+      for (sb = 0; sb < 32; ++sb) {
+	(*frame->overlap)[0][sb][s] =
+	(*frame->overlap)[1][sb][s] = 0;
+      }
+    }
+  }
+}

+ 118 - 0
libmad/frame.h

@@ -0,0 +1,118 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_FRAME_H
+# define LIBMAD_FRAME_H
+
+# include "fixed.h"
+# include "timer.h"
+# include "stream.h"
+
+enum mad_layer {
+  MAD_LAYER_I   = 1,			/* Layer I */
+  MAD_LAYER_II  = 2,			/* Layer II */
+  MAD_LAYER_III = 3			/* Layer III */
+};
+
+enum mad_mode {
+  MAD_MODE_SINGLE_CHANNEL = 0,		/* single channel */
+  MAD_MODE_DUAL_CHANNEL	  = 1,		/* dual channel */
+  MAD_MODE_JOINT_STEREO	  = 2,		/* joint (MS/intensity) stereo */
+  MAD_MODE_STEREO	  = 3		/* normal LR stereo */
+};
+
+enum mad_emphasis {
+  MAD_EMPHASIS_NONE	  = 0,		/* no emphasis */
+  MAD_EMPHASIS_50_15_US	  = 1,		/* 50/15 microseconds emphasis */
+  MAD_EMPHASIS_CCITT_J_17 = 3,		/* CCITT J.17 emphasis */
+  MAD_EMPHASIS_RESERVED   = 2		/* unknown emphasis */
+};
+
+struct mad_header {
+  enum mad_layer layer;			/* audio layer (1, 2, or 3) */
+  enum mad_mode mode;			/* channel mode (see above) */
+  int mode_extension;			/* additional mode info */
+  enum mad_emphasis emphasis;		/* de-emphasis to use (see above) */
+
+  unsigned long bitrate;		/* stream bitrate (bps) */
+  unsigned int samplerate;		/* sampling frequency (Hz) */
+
+  unsigned short crc_check;		/* frame CRC accumulator */
+  unsigned short crc_target;		/* final target CRC checksum */
+
+  int flags;				/* flags (see below) */
+  int private_bits;			/* private bits (see below) */
+
+  mad_timer_t duration;			/* audio playing time of frame */
+};
+
+struct mad_frame {
+  struct mad_header header;		/* MPEG audio header */
+
+  int options;				/* decoding options (from stream) */
+
+  mad_fixed_t sbsample[2][36][32];	/* synthesis subband filter samples */
+  mad_fixed_t (*overlap)[2][32][18];	/* Layer III block overlap data */
+};
+
+# define MAD_NCHANNELS(header)		((header)->mode ? 2 : 1)
+# define MAD_NSBSAMPLES(header)  \
+  ((header)->layer == MAD_LAYER_I ? 12 :  \
+   (((header)->layer == MAD_LAYER_III &&  \
+     ((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36))
+
+enum {
+  MAD_FLAG_NPRIVATE_III	= 0x0007,	/* number of Layer III private bits */
+  MAD_FLAG_INCOMPLETE	= 0x0008,	/* header but not data is decoded */
+
+  MAD_FLAG_PROTECTION	= 0x0010,	/* frame has CRC protection */
+  MAD_FLAG_COPYRIGHT	= 0x0020,	/* frame is copyright */
+  MAD_FLAG_ORIGINAL	= 0x0040,	/* frame is original (else copy) */
+  MAD_FLAG_PADDING	= 0x0080,	/* frame has additional slot */
+
+  MAD_FLAG_I_STEREO	= 0x0100,	/* uses intensity joint stereo */
+  MAD_FLAG_MS_STEREO	= 0x0200,	/* uses middle/side joint stereo */
+  MAD_FLAG_FREEFORMAT	= 0x0400,	/* uses free format bitrate */
+
+  MAD_FLAG_LSF_EXT	= 0x1000,	/* lower sampling freq. extension */
+  MAD_FLAG_MC_EXT	= 0x2000,	/* multichannel audio extension */
+  MAD_FLAG_MPEG_2_5_EXT	= 0x4000	/* MPEG 2.5 (unofficial) extension */
+};
+
+enum {
+  MAD_PRIVATE_HEADER	= 0x0100,	/* header private bit */
+  MAD_PRIVATE_III	= 0x001f	/* Layer III private bits (up to 5) */
+};
+
+void mad_header_init(struct mad_header *);
+
+# define mad_header_finish(header)  /* nothing */
+
+int mad_header_decode(struct mad_header *, struct mad_stream *);
+
+void mad_frame_init(struct mad_frame *);
+void mad_frame_finish(struct mad_frame *);
+
+int mad_frame_decode(struct mad_frame *, struct mad_stream *);
+
+void mad_frame_mute(struct mad_frame *);
+
+# endif

File diff suppressed because it is too large
+ 3107 - 0
libmad/huffman.c


+ 66 - 0
libmad/huffman.h

@@ -0,0 +1,66 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: huffman.h,v 1.11 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_HUFFMAN_H
+# define LIBMAD_HUFFMAN_H
+
+union huffquad {
+  struct {
+    unsigned short final  :  1;
+    unsigned short bits   :  3;
+    unsigned short offset : 12;
+  } ptr;
+  struct {
+    unsigned short final  :  1;
+    unsigned short hlen   :  3;
+    unsigned short v      :  1;
+    unsigned short w      :  1;
+    unsigned short x      :  1;
+    unsigned short y      :  1;
+  } value;
+  unsigned short final    :  1;
+};
+
+union huffpair {
+  struct {
+    unsigned short final  :  1;
+    unsigned short bits   :  3;
+    unsigned short offset : 12;
+  } ptr;
+  struct {
+    unsigned short final  :  1;
+    unsigned short hlen   :  3;
+    unsigned short x      :  4;
+    unsigned short y      :  4;
+  } value;
+  unsigned short final    :  1;
+};
+
+struct hufftable {
+  union huffpair const *table;
+  unsigned short linbits;
+  unsigned short startbits;
+};
+
+extern union huffquad const *const mad_huff_quad_table[2];
+extern struct hufftable const mad_huff_pair_table[32];
+
+# endif

+ 62 - 0
libmad/imdct_s.dat

@@ -0,0 +1,62 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: imdct_s.dat,v 1.8 2004/01/23 09:41:32 rob Exp $
+ */
+
+  /*  0 */  {  MAD_F(0x09bd7ca0) /*  0.608761429 */,
+	      -MAD_F(0x0ec835e8) /* -0.923879533 */,
+	      -MAD_F(0x0216a2a2) /* -0.130526192 */,
+	       MAD_F(0x0fdcf549) /*  0.991444861 */,
+	      -MAD_F(0x061f78aa) /* -0.382683432 */,
+	      -MAD_F(0x0cb19346) /* -0.793353340 */ },
+
+  /*  6 */  { -MAD_F(0x0cb19346) /* -0.793353340 */,
+	       MAD_F(0x061f78aa) /*  0.382683432 */,
+	       MAD_F(0x0fdcf549) /*  0.991444861 */,
+	       MAD_F(0x0216a2a2) /*  0.130526192 */,
+	      -MAD_F(0x0ec835e8) /* -0.923879533 */,
+	      -MAD_F(0x09bd7ca0) /* -0.608761429 */ },
+
+  /*  1 */  {  MAD_F(0x061f78aa) /*  0.382683432 */,
+	      -MAD_F(0x0ec835e8) /* -0.923879533 */,
+	       MAD_F(0x0ec835e8) /*  0.923879533 */,
+	      -MAD_F(0x061f78aa) /* -0.382683432 */,
+	      -MAD_F(0x061f78aa) /* -0.382683432 */,
+	       MAD_F(0x0ec835e8) /*  0.923879533 */ },
+
+  /*  7 */  { -MAD_F(0x0ec835e8) /* -0.923879533 */,
+	      -MAD_F(0x061f78aa) /* -0.382683432 */,
+	       MAD_F(0x061f78aa) /*  0.382683432 */,
+	       MAD_F(0x0ec835e8) /*  0.923879533 */,
+	       MAD_F(0x0ec835e8) /*  0.923879533 */,
+	       MAD_F(0x061f78aa) /*  0.382683432 */ },
+
+  /*  2 */  {  MAD_F(0x0216a2a2) /*  0.130526192 */,
+	      -MAD_F(0x061f78aa) /* -0.382683432 */,
+	       MAD_F(0x09bd7ca0) /*  0.608761429 */,
+	      -MAD_F(0x0cb19346) /* -0.793353340 */,
+	       MAD_F(0x0ec835e8) /*  0.923879533 */,
+	      -MAD_F(0x0fdcf549) /* -0.991444861 */ },
+
+  /*  8 */  { -MAD_F(0x0fdcf549) /* -0.991444861 */,
+	      -MAD_F(0x0ec835e8) /* -0.923879533 */,
+	      -MAD_F(0x0cb19346) /* -0.793353340 */,
+	      -MAD_F(0x09bd7ca0) /* -0.608761429 */,
+	      -MAD_F(0x061f78aa) /* -0.382683432 */,
+	      -MAD_F(0x0216a2a2) /* -0.130526192 */ }

+ 532 - 0
libmad/layer12.c

@@ -0,0 +1,532 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: layer12.c,v 1.17 2004/02/05 09:02:39 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# ifdef HAVE_LIMITS_H
+#  include <limits.h>
+# else
+#  define CHAR_BIT  8
+# endif
+
+# include "fixed.h"
+# include "bit.h"
+# include "stream.h"
+# include "frame.h"
+# include "layer12.h"
+
+/*
+ * scalefactor table
+ * used in both Layer I and Layer II decoding
+ */
+static
+mad_fixed_t const sf_table[64] = {
+# include "sf_table.dat"
+};
+
+/* --- Layer I ------------------------------------------------------------- */
+
+/* linear scaling table */
+static
+mad_fixed_t const linear_table[14] = {
+  MAD_F(0x15555555),  /* 2^2  / (2^2  - 1) == 1.33333333333333 */
+  MAD_F(0x12492492),  /* 2^3  / (2^3  - 1) == 1.14285714285714 */
+  MAD_F(0x11111111),  /* 2^4  / (2^4  - 1) == 1.06666666666667 */
+  MAD_F(0x10842108),  /* 2^5  / (2^5  - 1) == 1.03225806451613 */
+  MAD_F(0x10410410),  /* 2^6  / (2^6  - 1) == 1.01587301587302 */
+  MAD_F(0x10204081),  /* 2^7  / (2^7  - 1) == 1.00787401574803 */
+  MAD_F(0x10101010),  /* 2^8  / (2^8  - 1) == 1.00392156862745 */
+  MAD_F(0x10080402),  /* 2^9  / (2^9  - 1) == 1.00195694716243 */
+  MAD_F(0x10040100),  /* 2^10 / (2^10 - 1) == 1.00097751710655 */
+  MAD_F(0x10020040),  /* 2^11 / (2^11 - 1) == 1.00048851978505 */
+  MAD_F(0x10010010),  /* 2^12 / (2^12 - 1) == 1.00024420024420 */
+  MAD_F(0x10008004),  /* 2^13 / (2^13 - 1) == 1.00012208521548 */
+  MAD_F(0x10004001),  /* 2^14 / (2^14 - 1) == 1.00006103888177 */
+  MAD_F(0x10002000)   /* 2^15 / (2^15 - 1) == 1.00003051850948 */
+};
+
+/*
+ * NAME:	I_sample()
+ * DESCRIPTION:	decode one requantized Layer I sample from a bitstream
+ */
+static
+mad_fixed_t I_sample(struct mad_bitptr *ptr, unsigned int nb)
+{
+  mad_fixed_t sample;
+
+  sample = mad_bit_read(ptr, nb);
+
+  /* invert most significant bit, extend sign, then scale to fixed format */
+
+  sample ^= 1 << (nb - 1);
+  sample |= -(sample & (1 << (nb - 1)));
+
+  sample <<= MAD_F_FRACBITS - (nb - 1);
+
+  /* requantize the sample */
+
+  /* s'' = (2^nb / (2^nb - 1)) * (s''' + 2^(-nb + 1)) */
+
+  sample += MAD_F_ONE >> (nb - 1);
+
+  return mad_f_mul(sample, linear_table[nb - 2]);
+
+  /* s' = factor * s'' */
+  /* (to be performed by caller) */
+}
+
+/*
+ * NAME:	layer->I()
+ * DESCRIPTION:	decode a single Layer I frame
+ */
+int mad_layer_I(struct mad_stream *stream, struct mad_frame *frame)
+{
+  struct mad_header *header = &frame->header;
+  unsigned int nch, bound, ch, s, sb, nb;
+  unsigned char allocation[2][32], scalefactor[2][32];
+
+  nch = MAD_NCHANNELS(header);
+
+  bound = 32;
+  if (header->mode == MAD_MODE_JOINT_STEREO) {
+    header->flags |= MAD_FLAG_I_STEREO;
+    bound = 4 + header->mode_extension * 4;
+  }
+
+  /* check CRC word */
+
+  if (header->flags & MAD_FLAG_PROTECTION) {
+    header->crc_check =
+      mad_bit_crc(stream->ptr, 4 * (bound * nch + (32 - bound)),
+		  header->crc_check);
+
+    if (header->crc_check != header->crc_target &&
+	!(frame->options & MAD_OPTION_IGNORECRC)) {
+      stream->error = MAD_ERROR_BADCRC;
+      return -1;
+    }
+  }
+
+  /* decode bit allocations */
+
+  for (sb = 0; sb < bound; ++sb) {
+    for (ch = 0; ch < nch; ++ch) {
+      nb = mad_bit_read(&stream->ptr, 4);
+
+      if (nb == 15) {
+	stream->error = MAD_ERROR_BADBITALLOC;
+	return -1;
+      }
+
+      allocation[ch][sb] = nb ? nb + 1 : 0;
+    }
+  }
+
+  for (sb = bound; sb < 32; ++sb) {
+    nb = mad_bit_read(&stream->ptr, 4);
+
+    if (nb == 15) {
+      stream->error = MAD_ERROR_BADBITALLOC;
+      return -1;
+    }
+
+    allocation[0][sb] =
+    allocation[1][sb] = nb ? nb + 1 : 0;
+  }
+
+  /* decode scalefactors */
+
+  for (sb = 0; sb < 32; ++sb) {
+    for (ch = 0; ch < nch; ++ch) {
+      if (allocation[ch][sb]) {
+	scalefactor[ch][sb] = mad_bit_read(&stream->ptr, 6);
+
+# if defined(OPT_STRICT)
+	/*
+	 * Scalefactor index 63 does not appear in Table B.1 of
+	 * ISO/IEC 11172-3. Nonetheless, other implementations accept it,
+	 * so we only reject it if OPT_STRICT is defined.
+	 */
+	if (scalefactor[ch][sb] == 63) {
+	  stream->error = MAD_ERROR_BADSCALEFACTOR;
+	  return -1;
+	}
+# endif
+      }
+    }
+  }
+
+  /* decode samples */
+
+  for (s = 0; s < 12; ++s) {
+    for (sb = 0; sb < bound; ++sb) {
+      for (ch = 0; ch < nch; ++ch) {
+	nb = allocation[ch][sb];
+	frame->sbsample[ch][s][sb] = nb ?
+	  mad_f_mul(I_sample(&stream->ptr, nb),
+		    sf_table[scalefactor[ch][sb]]) : 0;
+      }
+    }
+
+    for (sb = bound; sb < 32; ++sb) {
+      if ((nb = allocation[0][sb])) {
+	mad_fixed_t sample;
+
+	sample = I_sample(&stream->ptr, nb);
+
+	for (ch = 0; ch < nch; ++ch) {
+	  frame->sbsample[ch][s][sb] =
+	    mad_f_mul(sample, sf_table[scalefactor[ch][sb]]);
+	}
+      }
+      else {
+	for (ch = 0; ch < nch; ++ch)
+	  frame->sbsample[ch][s][sb] = 0;
+      }
+    }
+  }
+
+  return 0;
+}
+
+/* --- Layer II ------------------------------------------------------------ */
+
+/* possible quantization per subband table */
+static
+struct {
+  unsigned int sblimit;
+  unsigned char const offsets[30];
+} const sbquant_table[5] = {
+  /* ISO/IEC 11172-3 Table B.2a */
+  { 27, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3,	/* 0 */
+	  3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0 } },
+  /* ISO/IEC 11172-3 Table B.2b */
+  { 30, { 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3,	/* 1 */
+	  3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0 } },
+  /* ISO/IEC 11172-3 Table B.2c */
+  {  8, { 5, 5, 2, 2, 2, 2, 2, 2 } },				/* 2 */
+  /* ISO/IEC 11172-3 Table B.2d */
+  { 12, { 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 } },		/* 3 */
+  /* ISO/IEC 13818-3 Table B.1 */
+  { 30, { 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,	/* 4 */
+	  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }
+};
+
+/* bit allocation table */
+static
+struct {
+  unsigned short nbal;
+  unsigned short offset;
+} const bitalloc_table[8] = {
+  { 2, 0 },  /* 0 */
+  { 2, 3 },  /* 1 */
+  { 3, 3 },  /* 2 */
+  { 3, 1 },  /* 3 */
+  { 4, 2 },  /* 4 */
+  { 4, 3 },  /* 5 */
+  { 4, 4 },  /* 6 */
+  { 4, 5 }   /* 7 */
+};
+
+/* offsets into quantization class table */
+static
+unsigned char const offset_table[6][15] = {
+  { 0, 1, 16                                             },  /* 0 */
+  { 0, 1,  2, 3, 4, 5, 16                                },  /* 1 */
+  { 0, 1,  2, 3, 4, 5,  6, 7,  8,  9, 10, 11, 12, 13, 14 },  /* 2 */
+  { 0, 1,  3, 4, 5, 6,  7, 8,  9, 10, 11, 12, 13, 14, 15 },  /* 3 */
+  { 0, 1,  2, 3, 4, 5,  6, 7,  8,  9, 10, 11, 12, 13, 16 },  /* 4 */
+  { 0, 2,  4, 5, 6, 7,  8, 9, 10, 11, 12, 13, 14, 15, 16 }   /* 5 */
+};
+
+/* quantization class table */
+static
+struct quantclass {
+  unsigned short nlevels;
+  unsigned char group;
+  unsigned char bits;
+  mad_fixed_t C;
+  mad_fixed_t D;
+} const qc_table[17] = {
+# include "qc_table.dat"
+};
+
+/*
+ * NAME:	II_samples()
+ * DESCRIPTION:	decode three requantized Layer II samples from a bitstream
+ */
+static
+void II_samples(struct mad_bitptr *ptr,
+		struct quantclass const *quantclass,
+		mad_fixed_t output[3])
+{
+  unsigned int nb, s, sample[3];
+
+  if ((nb = quantclass->group)) {
+    unsigned int c, nlevels;
+
+    /* degrouping */
+    c = mad_bit_read(ptr, quantclass->bits);
+    nlevels = quantclass->nlevels;
+
+    for (s = 0; s < 3; ++s) {
+      sample[s] = c % nlevels;
+      c /= nlevels;
+    }
+  }
+  else {
+    nb = quantclass->bits;
+
+    for (s = 0; s < 3; ++s)
+      sample[s] = mad_bit_read(ptr, nb);
+  }
+
+  for (s = 0; s < 3; ++s) {
+    mad_fixed_t requantized;
+
+    /* invert most significant bit, extend sign, then scale to fixed format */
+
+    requantized  = sample[s] ^ (1 << (nb - 1));
+    requantized |= -(requantized & (1 << (nb - 1)));
+
+    requantized <<= MAD_F_FRACBITS - (nb - 1);
+
+    /* requantize the sample */
+
+    /* s'' = C * (s''' + D) */
+
+    output[s] = mad_f_mul(requantized + quantclass->D, quantclass->C);
+
+    /* s' = factor * s'' */
+    /* (to be performed by caller) */
+  }
+}
+
+/*
+ * NAME:	layer->II()
+ * DESCRIPTION:	decode a single Layer II frame
+ */
+int mad_layer_II(struct mad_stream *stream, struct mad_frame *frame)
+{
+  struct mad_header *header = &frame->header;
+  struct mad_bitptr start;
+  unsigned int index, sblimit, nbal, nch, bound, gr, ch, s, sb;
+  unsigned char const *offsets;
+  unsigned char allocation[2][32], scfsi[2][32], scalefactor[2][32][3];
+  mad_fixed_t samples[3];
+
+  nch = MAD_NCHANNELS(header);
+
+  if (header->flags & MAD_FLAG_LSF_EXT)
+    index = 4;
+  else if (header->flags & MAD_FLAG_FREEFORMAT)
+    goto freeformat;
+  else {
+    unsigned long bitrate_per_channel;
+
+    bitrate_per_channel = header->bitrate;
+    if (nch == 2) {
+      bitrate_per_channel /= 2;
+
+# if defined(OPT_STRICT)
+      /*
+       * ISO/IEC 11172-3 allows only single channel mode for 32, 48, 56, and
+       * 80 kbps bitrates in Layer II, but some encoders ignore this
+       * restriction. We enforce it if OPT_STRICT is defined.
+       */
+      if (bitrate_per_channel <= 28000 || bitrate_per_channel == 40000) {
+	stream->error = MAD_ERROR_BADMODE;
+	return -1;
+      }
+# endif
+    }
+    else {  /* nch == 1 */
+      if (bitrate_per_channel > 192000) {
+	/*
+	 * ISO/IEC 11172-3 does not allow single channel mode for 224, 256,
+	 * 320, or 384 kbps bitrates in Layer II.
+	 */
+	stream->error = MAD_ERROR_BADMODE;
+	return -1;
+      }
+    }
+
+    if (bitrate_per_channel <= 48000)
+      index = (header->samplerate == 32000) ? 3 : 2;
+    else if (bitrate_per_channel <= 80000)
+      index = 0;
+    else {
+    freeformat:
+      index = (header->samplerate == 48000) ? 0 : 1;
+    }
+  }
+
+  sblimit = sbquant_table[index].sblimit;
+  offsets = sbquant_table[index].offsets;
+
+  bound = 32;
+  if (header->mode == MAD_MODE_JOINT_STEREO) {
+    header->flags |= MAD_FLAG_I_STEREO;
+    bound = 4 + header->mode_extension * 4;
+  }
+
+  if (bound > sblimit)
+    bound = sblimit;
+
+  start = stream->ptr;
+
+  /* decode bit allocations */
+
+  for (sb = 0; sb < bound; ++sb) {
+    nbal = bitalloc_table[offsets[sb]].nbal;
+
+    for (ch = 0; ch < nch; ++ch)
+      allocation[ch][sb] = mad_bit_read(&stream->ptr, nbal);
+  }
+
+  for (sb = bound; sb < sblimit; ++sb) {
+    nbal = bitalloc_table[offsets[sb]].nbal;
+
+    allocation[0][sb] =
+    allocation[1][sb] = mad_bit_read(&stream->ptr, nbal);
+  }
+
+  /* decode scalefactor selection info */
+
+  for (sb = 0; sb < sblimit; ++sb) {
+    for (ch = 0; ch < nch; ++ch) {
+      if (allocation[ch][sb])
+	scfsi[ch][sb] = mad_bit_read(&stream->ptr, 2);
+    }
+  }
+
+  /* check CRC word */
+
+  if (header->flags & MAD_FLAG_PROTECTION) {
+    header->crc_check =
+      mad_bit_crc(start, mad_bit_length(&start, &stream->ptr),
+		  header->crc_check);
+
+    if (header->crc_check != header->crc_target &&
+	!(frame->options & MAD_OPTION_IGNORECRC)) {
+      stream->error = MAD_ERROR_BADCRC;
+      return -1;
+    }
+  }
+
+  /* decode scalefactors */
+
+  for (sb = 0; sb < sblimit; ++sb) {
+    for (ch = 0; ch < nch; ++ch) {
+      if (allocation[ch][sb]) {
+	scalefactor[ch][sb][0] = mad_bit_read(&stream->ptr, 6);
+
+	switch (scfsi[ch][sb]) {
+	case 2:
+	  scalefactor[ch][sb][2] =
+	  scalefactor[ch][sb][1] =
+	  scalefactor[ch][sb][0];
+	  break;
+
+	case 0:
+	  scalefactor[ch][sb][1] = mad_bit_read(&stream->ptr, 6);
+	  /* fall through */
+
+	case 1:
+	case 3:
+	  scalefactor[ch][sb][2] = mad_bit_read(&stream->ptr, 6);
+	}
+
+	if (scfsi[ch][sb] & 1)
+	  scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1];
+
+# if defined(OPT_STRICT)
+	/*
+	 * Scalefactor index 63 does not appear in Table B.1 of
+	 * ISO/IEC 11172-3. Nonetheless, other implementations accept it,
+	 * so we only reject it if OPT_STRICT is defined.
+	 */
+	if (scalefactor[ch][sb][0] == 63 ||
+	    scalefactor[ch][sb][1] == 63 ||
+	    scalefactor[ch][sb][2] == 63) {
+	  stream->error = MAD_ERROR_BADSCALEFACTOR;
+	  return -1;
+	}
+# endif
+      }
+    }
+  }
+
+  /* decode samples */
+
+  for (gr = 0; gr < 12; ++gr) {
+    for (sb = 0; sb < bound; ++sb) {
+      for (ch = 0; ch < nch; ++ch) {
+	if ((index = allocation[ch][sb])) {
+	  index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1];
+
+	  II_samples(&stream->ptr, &qc_table[index], samples);
+
+	  for (s = 0; s < 3; ++s) {
+	    frame->sbsample[ch][3 * gr + s][sb] =
+	      mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]);
+	  }
+	}
+	else {
+	  for (s = 0; s < 3; ++s)
+	    frame->sbsample[ch][3 * gr + s][sb] = 0;
+	}
+      }
+    }
+
+    for (sb = bound; sb < sblimit; ++sb) {
+      if ((index = allocation[0][sb])) {
+	index = offset_table[bitalloc_table[offsets[sb]].offset][index - 1];
+
+	II_samples(&stream->ptr, &qc_table[index], samples);
+
+	for (ch = 0; ch < nch; ++ch) {
+	  for (s = 0; s < 3; ++s) {
+	    frame->sbsample[ch][3 * gr + s][sb] =
+	      mad_f_mul(samples[s], sf_table[scalefactor[ch][sb][gr / 4]]);
+	  }
+	}
+      }
+      else {
+	for (ch = 0; ch < nch; ++ch) {
+	  for (s = 0; s < 3; ++s)
+	    frame->sbsample[ch][3 * gr + s][sb] = 0;
+	}
+      }
+    }
+
+    for (ch = 0; ch < nch; ++ch) {
+      for (s = 0; s < 3; ++s) {
+	for (sb = sblimit; sb < 32; ++sb)
+	  frame->sbsample[ch][3 * gr + s][sb] = 0;
+      }
+    }
+  }
+
+  return 0;
+}

+ 31 - 0
libmad/layer12.h

@@ -0,0 +1,31 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: layer12.h,v 1.10 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_LAYER12_H
+# define LIBMAD_LAYER12_H
+
+# include "stream.h"
+# include "frame.h"
+
+int mad_layer_I(struct mad_stream *, struct mad_frame *);
+int mad_layer_II(struct mad_stream *, struct mad_frame *);
+
+# endif

File diff suppressed because it is too large
+ 2696 - 0
libmad/layer3.c


+ 30 - 0
libmad/layer3.h

@@ -0,0 +1,30 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: layer3.h,v 1.10 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_LAYER3_H
+# define LIBMAD_LAYER3_H
+
+# include "stream.h"
+# include "frame.h"
+
+int mad_layer_III(struct mad_stream *, struct mad_frame *);
+
+# endif

+ 139 - 0
libmad/libmad_config.h

@@ -0,0 +1,139 @@
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to enable diagnostic debugging support. */
+/* #undef DEBUG */
+
+/* Define to enable experimental code. */
+/* #undef EXPERIMENTAL */
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the `fcntl' function. */
+/* #undef HAVE_FCNTL */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fork' function. */
+/* #undef HAVE_FORK */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if your MIPS CPU supports a 2-operand MADD16 instruction. */
+/* #undef HAVE_MADD16_ASM */
+
+/* Define if your MIPS CPU supports a 2-operand MADD instruction. */
+/* #undef HAVE_MADD_ASM */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `pipe' function. */
+/* #undef HAVE_PIPE */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* #undef HAVE_SYS_WAIT_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #undef HAVE_UNISTD_H */
+
+/* Define to 1 if you have the `waitpid' function. */
+/* #undef HAVE_WAITPID */
+
+/* Define to disable debugging assertions. */
+/* #undef NDEBUG */
+
+/* Define to optimize for accuracy over speed. */
+/* #undef OPT_ACCURACY */
+
+/* Define to optimize for speed over accuracy. */
+/* #undef OPT_SPEED */
+
+/* Define to enable a fast subband synthesis approximation optimization. */
+/* #undef OPT_SSO */
+
+/* Define to influence a strict interpretation of the ISO/IEC standards, even
+   if this is in opposition with best accepted practices. */
+/* #undef OPT_STRICT */
+
+/* Name of package */
+#define PACKAGE "libmad"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "support@underbit.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "MPEG Audio Decoder"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "MPEG Audio Decoder 0.15.1b"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libmad"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.15.1b"
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.15.1b"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define as `__inline' if that's what the C compiler calls it, or to nothing
+   if it is not supported. */
+#define inline __inline
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+#define FPM_DEFAULT 1
+
+#ifdef _MSC_VER
+#pragma warning (disable:4018)
+#pragma warning (disable:4146)
+#pragma warning (disable:4244)
+#pragma warning (disable:4996)
+#endif

+ 58 - 0
libmad/libmad_global.h

@@ -0,0 +1,58 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: global.h,v 1.11 2004/01/23 09:41:32 rob Exp $
+ */
+
+# ifndef LIBMAD_GLOBAL_H
+# define LIBMAD_GLOBAL_H
+
+/* conditional debugging */
+
+# if defined(DEBUG) && defined(NDEBUG)
+#  error "cannot define both DEBUG and NDEBUG"
+# endif
+
+# if defined(DEBUG)
+#  include <stdio.h>
+# endif
+
+/* conditional features */
+
+# if defined(OPT_SPEED) && defined(OPT_ACCURACY)
+#  error "cannot optimize for both speed and accuracy"
+# endif
+
+# if defined(OPT_SPEED) && !defined(OPT_SSO)
+#  define OPT_SSO
+# endif
+
+# if defined(HAVE_UNISTD_H) && defined(HAVE_WAITPID) &&  \
+    defined(HAVE_FCNTL) && defined(HAVE_PIPE) && defined(HAVE_FORK)
+#  define USE_ASYNC
+# endif
+
+# if !defined(HAVE_ASSERT_H)
+#  if defined(NDEBUG)
+#   define assert(x)	/* nothing */
+#  else
+#   define assert(x)	do { if (!(x)) abort(); } while (0)
+#  endif
+# endif
+
+# endif

+ 964 - 0
libmad/mad.h

@@ -0,0 +1,964 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * If you would like to negotiate alternate licensing terms, you may do
+ * so by contacting: Underbit Technologies, Inc. <info@underbit.com>
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# define FPM_INTEL
+
+
+
+# define SIZEOF_INT 4
+# define SIZEOF_LONG 4
+# define SIZEOF_LONG_LONG 8
+
+
+/* Id: version.h,v 1.26 2004/01/23 09:41:33 rob Exp */
+
+# ifndef LIBMAD_VERSION_H
+# define LIBMAD_VERSION_H
+
+# define MAD_VERSION_MAJOR	0
+# define MAD_VERSION_MINOR	15
+# define MAD_VERSION_PATCH	1
+# define MAD_VERSION_EXTRA	" (beta)"
+
+# define MAD_VERSION_STRINGIZE(str)	#str
+# define MAD_VERSION_STRING(num)	MAD_VERSION_STRINGIZE(num)
+
+# define MAD_VERSION		MAD_VERSION_STRING(MAD_VERSION_MAJOR) "."  \
+				MAD_VERSION_STRING(MAD_VERSION_MINOR) "."  \
+				MAD_VERSION_STRING(MAD_VERSION_PATCH)  \
+				MAD_VERSION_EXTRA
+
+# define MAD_PUBLISHYEAR	"2000-2004"
+# define MAD_AUTHOR		"Underbit Technologies, Inc."
+# define MAD_EMAIL		"info@underbit.com"
+
+extern char const mad_version[];
+extern char const mad_copyright[];
+extern char const mad_author[];
+extern char const mad_build[];
+
+# endif
+
+/* Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp */
+
+# ifndef LIBMAD_FIXED_H
+# define LIBMAD_FIXED_H
+
+# if SIZEOF_INT >= 4
+typedef   signed int mad_fixed_t;
+
+typedef   signed int mad_fixed64hi_t;
+typedef unsigned int mad_fixed64lo_t;
+# else
+typedef   signed long mad_fixed_t;
+
+typedef   signed long mad_fixed64hi_t;
+typedef unsigned long mad_fixed64lo_t;
+# endif
+
+# if defined(_MSC_VER)
+#  define mad_fixed64_t  signed __int64
+# elif 1 || defined(__GNUC__)
+#  define mad_fixed64_t  signed long long
+# endif
+
+# if defined(FPM_FLOAT)
+typedef double mad_sample_t;
+# else
+typedef mad_fixed_t mad_sample_t;
+# endif
+
+/*
+ * Fixed-point format: 0xABBBBBBB
+ * A == whole part      (sign + 3 bits)
+ * B == fractional part (28 bits)
+ *
+ * Values are signed two's complement, so the effective range is:
+ * 0x80000000 to 0x7fffffff
+ *       -8.0 to +7.9999999962747097015380859375
+ *
+ * The smallest representable value is:
+ * 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9)
+ *
+ * 28 bits of fractional accuracy represent about
+ * 8.6 digits of decimal accuracy.
+ *
+ * Fixed-point numbers can be added or subtracted as normal
+ * integers, but multiplication requires shifting the 64-bit result
+ * from 56 fractional bits back to 28 (and rounding.)
+ *
+ * Changing the definition of MAD_F_FRACBITS is only partially
+ * supported, and must be done with care.
+ */
+
+# define MAD_F_FRACBITS		28
+
+# if MAD_F_FRACBITS == 28
+#  define MAD_F(x)		((mad_fixed_t) (x##L))
+# else
+#  if MAD_F_FRACBITS < 28
+#   warning "MAD_F_FRACBITS < 28"
+#   define MAD_F(x)		((mad_fixed_t)  \
+				 (((x##L) +  \
+				   (1L << (28 - MAD_F_FRACBITS - 1))) >>  \
+				  (28 - MAD_F_FRACBITS)))
+#  elif MAD_F_FRACBITS > 28
+#   error "MAD_F_FRACBITS > 28 not currently supported"
+#   define MAD_F(x)		((mad_fixed_t)  \
+				 ((x##L) << (MAD_F_FRACBITS - 28)))
+#  endif
+# endif
+
+# define MAD_F_MIN		((mad_fixed_t) -0x80000000L)
+# define MAD_F_MAX		((mad_fixed_t) +0x7fffffffL)
+
+# define MAD_F_ONE		MAD_F(0x10000000)
+
+# define mad_f_tofixed(x)	((mad_fixed_t)  \
+				 ((x) * (double) (1L << MAD_F_FRACBITS) + 0.5))
+# define mad_f_todouble(x)	((double)  \
+				 ((x) / (double) (1L << MAD_F_FRACBITS)))
+
+# define mad_f_intpart(x)	((x) >> MAD_F_FRACBITS)
+# define mad_f_fracpart(x)	((x) & ((1L << MAD_F_FRACBITS) - 1))
+				/* (x should be positive) */
+
+# define mad_f_fromint(x)	((x) << MAD_F_FRACBITS)
+
+# define mad_f_add(x, y)	((x) + (y))
+# define mad_f_sub(x, y)	((x) - (y))
+
+# if defined(FPM_FLOAT)
+#  error "FPM_FLOAT not yet supported"
+
+#  undef MAD_F
+#  define MAD_F(x)		mad_f_todouble(x)
+
+#  define mad_f_mul(x, y)	((x) * (y))
+#  define mad_f_scale64
+
+#  undef ASO_ZEROCHECK
+
+# elif defined(FPM_64BIT)
+
+/*
+ * This version should be the most accurate if 64-bit types are supported by
+ * the compiler, although it may not be the most efficient.
+ */
+#  if defined(OPT_ACCURACY)
+#   define mad_f_mul(x, y)  \
+    ((mad_fixed_t)  \
+     ((((mad_fixed64_t) (x) * (y)) +  \
+       (1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS))
+#  else
+#   define mad_f_mul(x, y)  \
+    ((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS))
+#  endif
+
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+
+/* --- Intel --------------------------------------------------------------- */
+
+# elif defined(FPM_INTEL)
+
+#  if defined(_MSC_VER)
+#   pragma warning(push)
+#   pragma warning(disable: 4035)  /* no return value */
+static __forceinline
+mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y)
+{
+  enum {
+    fracbits = MAD_F_FRACBITS
+  };
+
+  __asm {
+    mov eax, x
+    imul y
+    shrd eax, edx, fracbits
+  }
+
+  /* implicit return of eax */
+}
+#   pragma warning(pop)
+
+#   define mad_f_mul		mad_f_mul_inline
+#   define mad_f_scale64
+#  else
+/*
+ * This Intel version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#   define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("imull %3"  \
+	 : "=a" (lo), "=d" (hi)  \
+	 : "%a" (x), "rm" (y)  \
+	 : "cc")
+
+#   if defined(OPT_ACCURACY)
+/*
+ * This gives best accuracy but is not very fast.
+ */
+#    define MAD_F_MLA(hi, lo, x, y)  \
+    ({ mad_fixed64hi_t __hi;  \
+       mad_fixed64lo_t __lo;  \
+       MAD_F_MLX(__hi, __lo, (x), (y));  \
+       asm ("addl %2,%0\n\t"  \
+	    "adcl %3,%1"  \
+	    : "=rm" (lo), "=rm" (hi)  \
+	    : "r" (__lo), "r" (__hi), "0" (lo), "1" (hi)  \
+	    : "cc");  \
+    })
+#   endif  /* OPT_ACCURACY */
+
+#   if defined(OPT_ACCURACY)
+/*
+ * Surprisingly, this is faster than SHRD followed by ADC.
+ */
+#    define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed64hi_t __hi_;  \
+       mad_fixed64lo_t __lo_;  \
+       mad_fixed_t __result;  \
+       asm ("addl %4,%2\n\t"  \
+	    "adcl %5,%3"  \
+	    : "=rm" (__lo_), "=rm" (__hi_)  \
+	    : "0" (lo), "1" (hi),  \
+	      "ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0)  \
+	    : "cc");  \
+       asm ("shrdl %3,%2,%1"  \
+	    : "=rm" (__result)  \
+	    : "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+#   elif defined(OPT_INTEL)
+/*
+ * Alternate Intel scaling that may or may not perform better.
+ */
+#    define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("shrl %3,%1\n\t"  \
+	    "shll %4,%2\n\t"  \
+	    "orl %2,%1"  \
+	    : "=rm" (__result)  \
+	    : "0" (lo), "r" (hi),  \
+	      "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+#   else
+#    define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("shrdl %3,%2,%1"  \
+	    : "=rm" (__result)  \
+	    : "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+#   endif  /* OPT_ACCURACY */
+
+#   define MAD_F_SCALEBITS  MAD_F_FRACBITS
+#  endif
+
+/* --- ARM ----------------------------------------------------------------- */
+
+# elif defined(FPM_ARM)
+
+/* 
+ * This ARM V4 version is as accurate as FPM_64BIT but much faster. The
+ * least significant bit is properly rounded at no CPU cycle cost!
+ */
+# if 1
+/*
+ * This is faster than the default implementation via MAD_F_MLX() and
+ * mad_f_scale64().
+ */
+#  define mad_f_mul(x, y)  \
+    ({ mad_fixed64hi_t __hi;  \
+       mad_fixed64lo_t __lo;  \
+       mad_fixed_t __result;  \
+       asm ("smull	%0, %1, %3, %4\n\t"  \
+	    "movs	%0, %0, lsr %5\n\t"  \
+	    "adc	%2, %0, %1, lsl %6"  \
+	    : "=&r" (__lo), "=&r" (__hi), "=r" (__result)  \
+	    : "%r" (x), "r" (y),  \
+	      "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+# endif
+
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("smull	%0, %1, %2, %3"  \
+	 : "=&r" (lo), "=&r" (hi)  \
+	 : "%r" (x), "r" (y))
+
+#  define MAD_F_MLA(hi, lo, x, y)  \
+    asm ("smlal	%0, %1, %2, %3"  \
+	 : "+r" (lo), "+r" (hi)  \
+	 : "%r" (x), "r" (y))
+
+#  define MAD_F_MLN(hi, lo)  \
+    asm ("rsbs	%0, %2, #0\n\t"  \
+	 "rsc	%1, %3, #0"  \
+	 : "=r" (lo), "=r" (hi)  \
+	 : "0" (lo), "1" (hi)  \
+	 : "cc")
+
+#  define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("movs	%0, %1, lsr %3\n\t"  \
+	    "adc	%0, %0, %2, lsl %4"  \
+	    : "=&r" (__result)  \
+	    : "r" (lo), "r" (hi),  \
+	      "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS)  \
+	    : "cc");  \
+       __result;  \
+    })
+
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+
+/* --- MIPS ---------------------------------------------------------------- */
+
+# elif defined(FPM_MIPS)
+
+/*
+ * This MIPS version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("mult	%2,%3"  \
+	 : "=l" (lo), "=h" (hi)  \
+	 : "%r" (x), "r" (y))
+
+# if defined(HAVE_MADD_ASM)
+#  define MAD_F_MLA(hi, lo, x, y)  \
+    asm ("madd	%2,%3"  \
+	 : "+l" (lo), "+h" (hi)  \
+	 : "%r" (x), "r" (y))
+# elif defined(HAVE_MADD16_ASM)
+/*
+ * This loses significant accuracy due to the 16-bit integer limit in the
+ * multiply/accumulate instruction.
+ */
+#  define MAD_F_ML0(hi, lo, x, y)  \
+    asm ("mult	%2,%3"  \
+	 : "=l" (lo), "=h" (hi)  \
+	 : "%r" ((x) >> 12), "r" ((y) >> 16))
+#  define MAD_F_MLA(hi, lo, x, y)  \
+    asm ("madd16	%2,%3"  \
+	 : "+l" (lo), "+h" (hi)  \
+	 : "%r" ((x) >> 12), "r" ((y) >> 16))
+#  define MAD_F_MLZ(hi, lo)  ((mad_fixed_t) (lo))
+# endif
+
+# if defined(OPT_SPEED)
+#  define mad_f_scale64(hi, lo)  \
+    ((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS)))
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+# endif
+
+/* --- SPARC --------------------------------------------------------------- */
+
+# elif defined(FPM_SPARC)
+
+/*
+ * This SPARC V8 version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    asm ("smul %2, %3, %0\n\t"  \
+	 "rd %%y, %1"  \
+	 : "=r" (lo), "=r" (hi)  \
+	 : "%r" (x), "rI" (y))
+
+/* --- PowerPC ------------------------------------------------------------- */
+
+# elif defined(FPM_PPC)
+
+/*
+ * This PowerPC version is fast and accurate; the disposition of the least
+ * significant bit depends on OPT_ACCURACY via mad_f_scale64().
+ */
+#  define MAD_F_MLX(hi, lo, x, y)  \
+    do {  \
+      asm ("mullw %0,%1,%2"  \
+	   : "=r" (lo)  \
+	   : "%r" (x), "r" (y));  \
+      asm ("mulhw %0,%1,%2"  \
+	   : "=r" (hi)  \
+	   : "%r" (x), "r" (y));  \
+    }  \
+    while (0)
+
+#  if defined(OPT_ACCURACY)
+/*
+ * This gives best accuracy but is not very fast.
+ */
+#   define MAD_F_MLA(hi, lo, x, y)  \
+    ({ mad_fixed64hi_t __hi;  \
+       mad_fixed64lo_t __lo;  \
+       MAD_F_MLX(__hi, __lo, (x), (y));  \
+       asm ("addc %0,%2,%3\n\t"  \
+	    "adde %1,%4,%5"  \
+	    : "=r" (lo), "=r" (hi)  \
+	    : "%r" (lo), "r" (__lo),  \
+	      "%r" (hi), "r" (__hi)  \
+	    : "xer");  \
+    })
+#  endif
+
+#  if defined(OPT_ACCURACY)
+/*
+ * This is slower than the truncating version below it.
+ */
+#   define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result, __round;  \
+       asm ("rotrwi %0,%1,%2"  \
+	    : "=r" (__result)  \
+	    : "r" (lo), "i" (MAD_F_SCALEBITS));  \
+       asm ("extrwi %0,%1,1,0"  \
+	    : "=r" (__round)  \
+	    : "r" (__result));  \
+       asm ("insrwi %0,%1,%2,0"  \
+	    : "+r" (__result)  \
+	    : "r" (hi), "i" (MAD_F_SCALEBITS));  \
+       asm ("add %0,%1,%2"  \
+	    : "=r" (__result)  \
+	    : "%r" (__result), "r" (__round));  \
+       __result;  \
+    })
+#  else
+#   define mad_f_scale64(hi, lo)  \
+    ({ mad_fixed_t __result;  \
+       asm ("rotrwi %0,%1,%2"  \
+	    : "=r" (__result)  \
+	    : "r" (lo), "i" (MAD_F_SCALEBITS));  \
+       asm ("insrwi %0,%1,%2,0"  \
+	    : "+r" (__result)  \
+	    : "r" (hi), "i" (MAD_F_SCALEBITS));  \
+       __result;  \
+    })
+#  endif
+
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+
+/* --- Default ------------------------------------------------------------- */
+
+# elif defined(FPM_DEFAULT)
+
+/*
+ * This version is the most portable but it loses significant accuracy.
+ * Furthermore, accuracy is biased against the second argument, so care
+ * should be taken when ordering operands.
+ *
+ * The scale factors are constant as this is not used with SSO.
+ *
+ * Pre-rounding is required to stay within the limits of compliance.
+ */
+#  if defined(OPT_SPEED)
+#   define mad_f_mul(x, y)	(((x) >> 12) * ((y) >> 16))
+#  else
+#   define mad_f_mul(x, y)	((((x) + (1L << 11)) >> 12) *  \
+				 (((y) + (1L << 15)) >> 16))
+#  endif
+
+/* ------------------------------------------------------------------------- */
+
+# else
+#  error "no FPM selected"
+# endif
+
+/* default implementations */
+
+# if !defined(mad_f_mul)
+#  define mad_f_mul(x, y)  \
+    ({ register mad_fixed64hi_t __hi;  \
+       register mad_fixed64lo_t __lo;  \
+       MAD_F_MLX(__hi, __lo, (x), (y));  \
+       mad_f_scale64(__hi, __lo);  \
+    })
+# endif
+
+# if !defined(MAD_F_MLA)
+#  define MAD_F_ML0(hi, lo, x, y)	((lo)  = mad_f_mul((x), (y)))
+#  define MAD_F_MLA(hi, lo, x, y)	((lo) += mad_f_mul((x), (y)))
+#  define MAD_F_MLN(hi, lo)		((lo)  = -(lo))
+#  define MAD_F_MLZ(hi, lo)		((void) (hi), (mad_fixed_t) (lo))
+# endif
+
+# if !defined(MAD_F_ML0)
+#  define MAD_F_ML0(hi, lo, x, y)	MAD_F_MLX((hi), (lo), (x), (y))
+# endif
+
+# if !defined(MAD_F_MLN)
+#  define MAD_F_MLN(hi, lo)		((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi))
+# endif
+
+# if !defined(MAD_F_MLZ)
+#  define MAD_F_MLZ(hi, lo)		mad_f_scale64((hi), (lo))
+# endif
+
+# if !defined(mad_f_scale64)
+#  if defined(OPT_ACCURACY)
+#   define mad_f_scale64(hi, lo)  \
+    ((((mad_fixed_t)  \
+       (((hi) << (32 - (MAD_F_SCALEBITS - 1))) |  \
+	((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1)
+#  else
+#   define mad_f_scale64(hi, lo)  \
+    ((mad_fixed_t)  \
+     (((hi) << (32 - MAD_F_SCALEBITS)) |  \
+      ((lo) >> MAD_F_SCALEBITS)))
+#  endif
+#  define MAD_F_SCALEBITS  MAD_F_FRACBITS
+# endif
+
+/* C routines */
+
+mad_fixed_t mad_f_abs(mad_fixed_t);
+mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t);
+
+# endif
+
+/* Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp */
+
+# ifndef LIBMAD_BIT_H
+# define LIBMAD_BIT_H
+
+struct mad_bitptr {
+  unsigned char const *byte;
+  unsigned short cache;
+  unsigned short left;
+};
+
+void mad_bit_init(struct mad_bitptr *, unsigned char const *);
+
+# define mad_bit_finish(bitptr)		/* nothing */
+
+unsigned int mad_bit_length(struct mad_bitptr const *,
+			    struct mad_bitptr const *);
+
+# define mad_bit_bitsleft(bitptr)  ((bitptr)->left)
+unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *);
+
+void mad_bit_skip(struct mad_bitptr *, unsigned int);
+unsigned long mad_bit_read(struct mad_bitptr *, unsigned int);
+void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long);
+
+unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short);
+
+# endif
+
+/* Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp */
+
+# ifndef LIBMAD_TIMER_H
+# define LIBMAD_TIMER_H
+
+typedef struct {
+  signed long seconds;		/* whole seconds */
+  unsigned long fraction;	/* 1/MAD_TIMER_RESOLUTION seconds */
+} mad_timer_t;
+
+extern mad_timer_t const mad_timer_zero;
+
+# define MAD_TIMER_RESOLUTION	352800000UL
+
+enum mad_units {
+  MAD_UNITS_HOURS	 =    -2,
+  MAD_UNITS_MINUTES	 =    -1,
+  MAD_UNITS_SECONDS	 =     0,
+
+  /* metric units */
+
+  MAD_UNITS_DECISECONDS	 =    10,
+  MAD_UNITS_CENTISECONDS =   100,
+  MAD_UNITS_MILLISECONDS =  1000,
+
+  /* audio sample units */
+
+  MAD_UNITS_8000_HZ	 =  8000,
+  MAD_UNITS_11025_HZ	 = 11025,
+  MAD_UNITS_12000_HZ	 = 12000,
+
+  MAD_UNITS_16000_HZ	 = 16000,
+  MAD_UNITS_22050_HZ	 = 22050,
+  MAD_UNITS_24000_HZ	 = 24000,
+
+  MAD_UNITS_32000_HZ	 = 32000,
+  MAD_UNITS_44100_HZ	 = 44100,
+  MAD_UNITS_48000_HZ	 = 48000,
+
+  /* video frame/field units */
+
+  MAD_UNITS_24_FPS	 =    24,
+  MAD_UNITS_25_FPS	 =    25,
+  MAD_UNITS_30_FPS	 =    30,
+  MAD_UNITS_48_FPS	 =    48,
+  MAD_UNITS_50_FPS	 =    50,
+  MAD_UNITS_60_FPS	 =    60,
+
+  /* CD audio frames */
+
+  MAD_UNITS_75_FPS	 =    75,
+
+  /* video drop-frame units */
+
+  MAD_UNITS_23_976_FPS	 =   -24,
+  MAD_UNITS_24_975_FPS	 =   -25,
+  MAD_UNITS_29_97_FPS	 =   -30,
+  MAD_UNITS_47_952_FPS	 =   -48,
+  MAD_UNITS_49_95_FPS	 =   -50,
+  MAD_UNITS_59_94_FPS	 =   -60
+};
+
+# define mad_timer_reset(timer)	((void) (*(timer) = mad_timer_zero))
+
+int mad_timer_compare(mad_timer_t, mad_timer_t);
+
+# define mad_timer_sign(timer)	mad_timer_compare((timer), mad_timer_zero)
+
+void mad_timer_negate(mad_timer_t *);
+mad_timer_t mad_timer_abs(mad_timer_t);
+
+void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long);
+void mad_timer_add(mad_timer_t *, mad_timer_t);
+void mad_timer_multiply(mad_timer_t *, signed long);
+
+signed long mad_timer_count(mad_timer_t, enum mad_units);
+unsigned long mad_timer_fraction(mad_timer_t, unsigned long);
+void mad_timer_string(mad_timer_t, char *, char const *,
+		      enum mad_units, enum mad_units, unsigned long);
+
+# endif
+
+/* Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp */
+
+# ifndef LIBMAD_STREAM_H
+# define LIBMAD_STREAM_H
+
+
+# define MAD_BUFFER_GUARD	8
+# define MAD_BUFFER_MDLEN	(511 + 2048 + MAD_BUFFER_GUARD)
+
+enum mad_error {
+  MAD_ERROR_NONE	   = 0x0000,	/* no error */
+
+  MAD_ERROR_BUFLEN	   = 0x0001,	/* input buffer too small (or EOF) */
+  MAD_ERROR_BUFPTR	   = 0x0002,	/* invalid (null) buffer pointer */
+
+  MAD_ERROR_NOMEM	   = 0x0031,	/* not enough memory */
+
+  MAD_ERROR_LOSTSYNC	   = 0x0101,	/* lost synchronization */
+  MAD_ERROR_BADLAYER	   = 0x0102,	/* reserved header layer value */
+  MAD_ERROR_BADBITRATE	   = 0x0103,	/* forbidden bitrate value */
+  MAD_ERROR_BADSAMPLERATE  = 0x0104,	/* reserved sample frequency value */
+  MAD_ERROR_BADEMPHASIS	   = 0x0105,	/* reserved emphasis value */
+
+  MAD_ERROR_BADCRC	   = 0x0201,	/* CRC check failed */
+  MAD_ERROR_BADBITALLOC	   = 0x0211,	/* forbidden bit allocation value */
+  MAD_ERROR_BADSCALEFACTOR = 0x0221,	/* bad scalefactor index */
+  MAD_ERROR_BADMODE        = 0x0222,	/* bad bitrate/mode combination */
+  MAD_ERROR_BADFRAMELEN	   = 0x0231,	/* bad frame length */
+  MAD_ERROR_BADBIGVALUES   = 0x0232,	/* bad big_values count */
+  MAD_ERROR_BADBLOCKTYPE   = 0x0233,	/* reserved block_type */
+  MAD_ERROR_BADSCFSI	   = 0x0234,	/* bad scalefactor selection info */
+  MAD_ERROR_BADDATAPTR	   = 0x0235,	/* bad main_data_begin pointer */
+  MAD_ERROR_BADPART3LEN	   = 0x0236,	/* bad audio data length */
+  MAD_ERROR_BADHUFFTABLE   = 0x0237,	/* bad Huffman table select */
+  MAD_ERROR_BADHUFFDATA	   = 0x0238,	/* Huffman data overrun */
+  MAD_ERROR_BADSTEREO	   = 0x0239	/* incompatible block_type for JS */
+};
+
+# define MAD_RECOVERABLE(error)	((error) & 0xff00)
+
+struct mad_stream {
+  unsigned char const *buffer;		/* input bitstream buffer */
+  unsigned char const *bufend;		/* end of buffer */
+  unsigned long skiplen;		/* bytes to skip before next frame */
+
+  int sync;				/* stream sync found */
+  unsigned long freerate;		/* free bitrate (fixed) */
+
+  unsigned char const *this_frame;	/* start of current frame */
+  unsigned char const *next_frame;	/* start of next frame */
+  struct mad_bitptr ptr;		/* current processing bit pointer */
+
+  struct mad_bitptr anc_ptr;		/* ancillary bits pointer */
+  unsigned int anc_bitlen;		/* number of ancillary bits */
+
+  unsigned char (*main_data)[MAD_BUFFER_MDLEN];
+					/* Layer III main_data() */
+  unsigned int md_len;			/* bytes in main_data */
+
+  int options;				/* decoding options (see below) */
+  enum mad_error error;			/* error code (see above) */
+};
+
+enum {
+  MAD_OPTION_IGNORECRC      = 0x0001,	/* ignore CRC errors */
+  MAD_OPTION_HALFSAMPLERATE = 0x0002	/* generate PCM at 1/2 sample rate */
+# if 0  /* not yet implemented */
+  MAD_OPTION_LEFTCHANNEL    = 0x0010,	/* decode left channel only */
+  MAD_OPTION_RIGHTCHANNEL   = 0x0020,	/* decode right channel only */
+  MAD_OPTION_SINGLECHANNEL  = 0x0030	/* combine channels */
+# endif
+};
+
+void mad_stream_init(struct mad_stream *);
+void mad_stream_finish(struct mad_stream *);
+
+# define mad_stream_options(stream, opts)  \
+    ((void) ((stream)->options = (opts)))
+
+void mad_stream_buffer(struct mad_stream *,
+		       unsigned char const *, unsigned long);
+void mad_stream_skip(struct mad_stream *, unsigned long);
+
+int mad_stream_sync(struct mad_stream *);
+
+char const *mad_stream_errorstr(struct mad_stream const *);
+
+# endif
+
+/* Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp */
+
+# ifndef LIBMAD_FRAME_H
+# define LIBMAD_FRAME_H
+
+
+enum mad_layer {
+  MAD_LAYER_I   = 1,			/* Layer I */
+  MAD_LAYER_II  = 2,			/* Layer II */
+  MAD_LAYER_III = 3			/* Layer III */
+};
+
+enum mad_mode {
+  MAD_MODE_SINGLE_CHANNEL = 0,		/* single channel */
+  MAD_MODE_DUAL_CHANNEL	  = 1,		/* dual channel */
+  MAD_MODE_JOINT_STEREO	  = 2,		/* joint (MS/intensity) stereo */
+  MAD_MODE_STEREO	  = 3		/* normal LR stereo */
+};
+
+enum mad_emphasis {
+  MAD_EMPHASIS_NONE	  = 0,		/* no emphasis */
+  MAD_EMPHASIS_50_15_US	  = 1,		/* 50/15 microseconds emphasis */
+  MAD_EMPHASIS_CCITT_J_17 = 3,		/* CCITT J.17 emphasis */
+  MAD_EMPHASIS_RESERVED   = 2		/* unknown emphasis */
+};
+
+struct mad_header {
+  enum mad_layer layer;			/* audio layer (1, 2, or 3) */
+  enum mad_mode mode;			/* channel mode (see above) */
+  int mode_extension;			/* additional mode info */
+  enum mad_emphasis emphasis;		/* de-emphasis to use (see above) */
+
+  unsigned long bitrate;		/* stream bitrate (bps) */
+  unsigned int samplerate;		/* sampling frequency (Hz) */
+
+  unsigned short crc_check;		/* frame CRC accumulator */
+  unsigned short crc_target;		/* final target CRC checksum */
+
+  int flags;				/* flags (see below) */
+  int private_bits;			/* private bits (see below) */
+
+  mad_timer_t duration;			/* audio playing time of frame */
+};
+
+struct mad_frame {
+  struct mad_header header;		/* MPEG audio header */
+
+  int options;				/* decoding options (from stream) */
+
+  mad_fixed_t sbsample[2][36][32];	/* synthesis subband filter samples */
+  mad_fixed_t (*overlap)[2][32][18];	/* Layer III block overlap data */
+};
+
+# define MAD_NCHANNELS(header)		((header)->mode ? 2 : 1)
+# define MAD_NSBSAMPLES(header)  \
+  ((header)->layer == MAD_LAYER_I ? 12 :  \
+   (((header)->layer == MAD_LAYER_III &&  \
+     ((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36))
+
+enum {
+  MAD_FLAG_NPRIVATE_III	= 0x0007,	/* number of Layer III private bits */
+  MAD_FLAG_INCOMPLETE	= 0x0008,	/* header but not data is decoded */
+
+  MAD_FLAG_PROTECTION	= 0x0010,	/* frame has CRC protection */
+  MAD_FLAG_COPYRIGHT	= 0x0020,	/* frame is copyright */
+  MAD_FLAG_ORIGINAL	= 0x0040,	/* frame is original (else copy) */
+  MAD_FLAG_PADDING	= 0x0080,	/* frame has additional slot */
+
+  MAD_FLAG_I_STEREO	= 0x0100,	/* uses intensity joint stereo */
+  MAD_FLAG_MS_STEREO	= 0x0200,	/* uses middle/side joint stereo */
+  MAD_FLAG_FREEFORMAT	= 0x0400,	/* uses free format bitrate */
+
+  MAD_FLAG_LSF_EXT	= 0x1000,	/* lower sampling freq. extension */
+  MAD_FLAG_MC_EXT	= 0x2000,	/* multichannel audio extension */
+  MAD_FLAG_MPEG_2_5_EXT	= 0x4000	/* MPEG 2.5 (unofficial) extension */
+};
+
+enum {
+  MAD_PRIVATE_HEADER	= 0x0100,	/* header private bit */
+  MAD_PRIVATE_III	= 0x001f	/* Layer III private bits (up to 5) */
+};
+
+void mad_header_init(struct mad_header *);
+
+# define mad_header_finish(header)  /* nothing */
+
+int mad_header_decode(struct mad_header *, struct mad_stream *);
+
+void mad_frame_init(struct mad_frame *);
+void mad_frame_finish(struct mad_frame *);
+
+int mad_frame_decode(struct mad_frame *, struct mad_stream *);
+
+void mad_frame_mute(struct mad_frame *);
+
+# endif
+
+/* Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp */
+
+# ifndef LIBMAD_SYNTH_H
+# define LIBMAD_SYNTH_H
+
+
+struct mad_pcm {
+  unsigned int samplerate;		/* sampling frequency (Hz) */
+  unsigned short channels;		/* number of channels */
+  unsigned short length;		/* number of samples per channel */
+  mad_fixed_t samples[2][1152];		/* PCM output samples [ch][sample] */
+};
+
+struct mad_synth {
+  mad_fixed_t filter[2][2][2][16][8];	/* polyphase filterbank outputs */
+  					/* [ch][eo][peo][s][v] */
+
+  unsigned int phase;			/* current processing phase */
+
+  struct mad_pcm pcm;			/* PCM output */
+};
+
+/* single channel PCM selector */
+enum {
+  MAD_PCM_CHANNEL_SINGLE = 0
+};
+
+/* dual channel PCM selector */
+enum {
+  MAD_PCM_CHANNEL_DUAL_1 = 0,
+  MAD_PCM_CHANNEL_DUAL_2 = 1
+};
+
+/* stereo PCM selector */
+enum {
+  MAD_PCM_CHANNEL_STEREO_LEFT  = 0,
+  MAD_PCM_CHANNEL_STEREO_RIGHT = 1
+};
+
+void mad_synth_init(struct mad_synth *);
+
+# define mad_synth_finish(synth)  /* nothing */
+
+void mad_synth_mute(struct mad_synth *);
+
+void mad_synth_frame(struct mad_synth *, struct mad_frame const *);
+
+# endif
+
+/* Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp */
+
+# ifndef LIBMAD_DECODER_H
+# define LIBMAD_DECODER_H
+
+
+enum mad_decoder_mode {
+  MAD_DECODER_MODE_SYNC  = 0,
+  MAD_DECODER_MODE_ASYNC
+};
+
+enum mad_flow {
+  MAD_FLOW_CONTINUE = 0x0000,	/* continue normally */
+  MAD_FLOW_STOP     = 0x0010,	/* stop decoding normally */
+  MAD_FLOW_BREAK    = 0x0011,	/* stop decoding and signal an error */
+  MAD_FLOW_IGNORE   = 0x0020	/* ignore the current frame */
+};
+
+struct mad_decoder {
+  enum mad_decoder_mode mode;
+
+  int options;
+
+  struct {
+    long pid;
+    int in;
+    int out;
+  } async;
+
+  struct {
+    struct mad_stream stream;
+    struct mad_frame frame;
+    struct mad_synth synth;
+  } *sync;
+
+  void *cb_data;
+
+  enum mad_flow (*input_func)(void *, struct mad_stream *);
+  enum mad_flow (*header_func)(void *, struct mad_header const *);
+  enum mad_flow (*filter_func)(void *,
+			       struct mad_stream const *, struct mad_frame *);
+  enum mad_flow (*output_func)(void *,
+			       struct mad_header const *, struct mad_pcm *);
+  enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *);
+  enum mad_flow (*message_func)(void *, void *, unsigned int *);
+};
+
+void mad_decoder_init(struct mad_decoder *, void *,
+		      enum mad_flow (*)(void *, struct mad_stream *),
+		      enum mad_flow (*)(void *, struct mad_header const *),
+		      enum mad_flow (*)(void *,
+					struct mad_stream const *,
+					struct mad_frame *),
+		      enum mad_flow (*)(void *,
+					struct mad_header const *,
+					struct mad_pcm *),
+		      enum mad_flow (*)(void *,
+					struct mad_stream *,
+					struct mad_frame *),
+		      enum mad_flow (*)(void *, void *, unsigned int *));
+int mad_decoder_finish(struct mad_decoder *);
+
+# define mad_decoder_options(decoder, opts)  \
+    ((void) ((decoder)->options = (opts)))
+
+int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode);
+int mad_decoder_message(struct mad_decoder *, void *, unsigned int *);
+
+# endif
+
+# ifdef __cplusplus
+}
+# endif

+ 327 - 0
libmad/music_mad.c

@@ -0,0 +1,327 @@
+/*
+    SDL_mixer:  An audio mixer library based on the SDL library
+    Copyright (C) 1997-2004 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include "music_mad.h"
+
+mad_data *
+mad_openFile(const char *filename, SDL_AudioSpec *mixer) {
+  SDL_RWops *rw;
+
+  rw = SDL_RWFromFile(filename, "rb");
+  if (rw == NULL) {
+	return NULL;
+  }
+
+  return mad_openFileRW(rw, mixer);
+}
+
+mad_data *
+mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer) {
+  mad_data *mp3_mad;
+
+  mp3_mad = (mad_data *)malloc(sizeof(mad_data));
+  mp3_mad->rw = rw;
+  mad_stream_init(&mp3_mad->stream);
+  mad_frame_init(&mp3_mad->frame);
+  mad_synth_init(&mp3_mad->synth);
+  mp3_mad->frames_read = 0;
+  mad_timer_reset(&mp3_mad->next_frame_start);
+  mp3_mad->volume = 128;
+  mp3_mad->status = 0;
+  mp3_mad->output_begin = 0;
+  mp3_mad->output_end = 0;
+  mp3_mad->mixer = *mixer;
+
+  return mp3_mad;
+}
+
+void
+mad_closeFile(mad_data *mp3_mad) {
+  SDL_FreeRW(mp3_mad->rw);
+  mad_stream_finish(&mp3_mad->stream);
+  mad_frame_finish(&mp3_mad->frame);
+  mad_synth_finish(&mp3_mad->synth);
+
+  free(mp3_mad);
+}
+
+/* Starts the playback. */
+void
+mad_start(mad_data *mp3_mad) {
+  mp3_mad->status |= MS_playing;
+}
+
+/* Stops the playback. */
+void 
+mad_stop(mad_data *mp3_mad) {
+  mp3_mad->status &= ~MS_playing;
+}
+
+/* Returns true if the playing is engaged, false otherwise. */
+int
+mad_isPlaying(mad_data *mp3_mad) {
+  return ((mp3_mad->status & MS_playing) != 0);
+}
+
+/* Reads the next frame from the file.  Returns true on success or
+   false on failure. */
+static int
+read_next_frame(mad_data *mp3_mad) {
+  if (mp3_mad->stream.buffer == NULL || 
+	  mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
+	size_t read_size;
+	size_t remaining;
+	unsigned char *read_start;
+	
+	/* There might be some bytes in the buffer left over from last
+	   time.  If so, move them down and read more bytes following
+	   them. */
+	if (mp3_mad->stream.next_frame != NULL) {
+	  remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
+	  memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
+	  read_start = mp3_mad->input_buffer + remaining;
+	  read_size = MAD_INPUT_BUFFER_SIZE - remaining;
+	  
+	} else {
+	  read_size = MAD_INPUT_BUFFER_SIZE;
+	  read_start = mp3_mad->input_buffer;
+	  remaining = 0;
+	}
+
+	/* Now read additional bytes from the input file. */
+	read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
+	
+	if (read_size <= 0) {
+	  if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
+		if (read_size == 0) {
+		  mp3_mad->status |= MS_input_eof;
+		} else {
+		  mp3_mad->status |= MS_input_error;
+		}
+		
+		/* At the end of the file, we must stuff MAD_BUFFER_GUARD
+		   number of 0 bytes. */
+		memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
+		read_size += MAD_BUFFER_GUARD;
+	  }
+	}
+	
+	/* Now feed those bytes into the libmad stream. */
+	mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
+					  read_size + remaining);
+	mp3_mad->stream.error = MAD_ERROR_NONE;
+  }
+  
+  /* Now ask libmad to extract a frame from the data we just put in
+	 its buffer. */
+  if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
+	if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
+	  return 0;
+	  
+	} else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
+	  return 0;
+	  
+	} else {
+	  mp3_mad->status |= MS_decode_error;
+	  return 0;
+	}
+  }
+  
+  mp3_mad->frames_read++;
+  mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
+
+  return 1;
+}
+
+/* Scale a MAD sample to 16 bits for output. */
+static signed int
+scale(mad_fixed_t sample) {
+  /* round */
+  sample += (1L << (MAD_F_FRACBITS - 16));
+
+  /* clip */
+  if (sample >= MAD_F_ONE)
+    sample = MAD_F_ONE - 1;
+  else if (sample < -MAD_F_ONE)
+    sample = -MAD_F_ONE;
+
+  /* quantize */
+  return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
+
+/* Once the frame has been read, copies its samples into the output
+   buffer. */
+static void
+decode_frame(mad_data *mp3_mad) {
+  struct mad_pcm *pcm;
+  unsigned int nchannels, nsamples;
+  mad_fixed_t const *left_ch, *right_ch;
+  unsigned char *out;
+
+  mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
+  pcm = &mp3_mad->synth.pcm;
+  out = mp3_mad->output_buffer + mp3_mad->output_end;
+
+  if ((mp3_mad->status & MS_cvt_decoded) == 0) {
+	mp3_mad->status |= MS_cvt_decoded;
+
+	/* The first frame determines some key properties of the stream.
+	   In particular, it tells us enough to set up the convert
+	   structure now. */
+	SDL_BuildAudioCVT(&mp3_mad->cvt, AUDIO_S16, (Uint8)pcm->channels, mp3_mad->frame.header.samplerate, mp3_mad->mixer.format, mp3_mad->mixer.channels, mp3_mad->mixer.freq);
+  }
+
+  /* pcm->samplerate contains the sampling frequency */
+
+  nchannels = pcm->channels;
+  nsamples  = pcm->length;
+  left_ch   = pcm->samples[0];
+  right_ch  = pcm->samples[1];
+
+  while (nsamples--) {
+    signed int sample;
+
+    /* output sample(s) in 16-bit signed little-endian PCM */
+
+    sample = scale(*left_ch++);
+    *out++ = ((sample >> 0) & 0xff);
+    *out++ = ((sample >> 8) & 0xff);
+
+    if (nchannels == 2) {
+      sample = scale(*right_ch++);
+      *out++ = ((sample >> 0) & 0xff);
+      *out++ = ((sample >> 8) & 0xff);
+    }
+  }
+
+  mp3_mad->output_end = out - mp3_mad->output_buffer;
+  /*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
+}
+
+void
+mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
+  int bytes_remaining;
+  int num_bytes;
+  Uint8 *out;
+
+  if ((mp3_mad->status & MS_playing) == 0) {
+	/* We're not supposed to be playing, so send silence instead. */
+	memset(stream, 0, len);
+	return;
+  }
+
+  out = stream;
+  bytes_remaining = len;
+  while (bytes_remaining > 0) {
+	if (mp3_mad->output_end == mp3_mad->output_begin) {
+	  /* We need to get a new frame. */
+	  mp3_mad->output_begin = 0;
+	  mp3_mad->output_end = 0;
+	  if (!read_next_frame(mp3_mad)) {
+		if ((mp3_mad->status & MS_error_flags) != 0) {
+		  /* Couldn't read a frame; either an error condition or
+			 end-of-file.  Stop. */
+		  memset(out, 0, bytes_remaining);
+		  mp3_mad->status &= ~MS_playing;
+		  return;
+		}
+	  } else {
+		decode_frame(mp3_mad);
+
+		/* Now convert the frame data to the appropriate format for
+		   output. */
+		mp3_mad->cvt.buf = mp3_mad->output_buffer;
+		mp3_mad->cvt.len = mp3_mad->output_end;
+		
+		mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
+		/*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
+		SDL_ConvertAudio(&mp3_mad->cvt);
+	  }
+	}
+
+	num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
+	if (bytes_remaining < num_bytes) {
+	  num_bytes = bytes_remaining;
+	}
+
+	if (mp3_mad->volume == 128) {
+	  memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
+	} else {
+	  SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
+				   num_bytes, mp3_mad->volume);
+	}
+	out += num_bytes;
+	mp3_mad->output_begin += num_bytes;
+	bytes_remaining -= num_bytes;
+  }
+}
+
+void
+mad_seek(mad_data *mp3_mad, double position) {
+  mad_timer_t target;
+  int int_part;
+
+  int_part = (int)position;
+  mad_timer_set(&target, int_part, 
+				(int)((position - int_part) * 1000000), 1000000);
+
+  if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
+	/* In order to seek backwards in a VBR file, we have to rewind and
+	   start again from the beginning.  This isn't necessary if the
+	   file happens to be CBR, of course; in that case we could seek
+	   directly to the frame we want.  But I leave that little
+	   optimization for the future developer who discovers she really
+	   needs it. */
+	mp3_mad->frames_read = 0;
+	mad_timer_reset(&mp3_mad->next_frame_start);
+	mp3_mad->status &= ~MS_error_flags;
+	mp3_mad->output_begin = 0;
+	mp3_mad->output_end = 0;
+
+	SDL_RWseek(mp3_mad->rw, 0, SEEK_SET);
+  }
+
+  /* Now we have to skip frames until we come to the right one.
+	 Again, only truly necessary if the file is VBR. */
+  while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
+	if (!read_next_frame(mp3_mad)) {
+	  if ((mp3_mad->status & MS_error_flags) != 0) {
+		/* Couldn't read a frame; either an error condition or
+		   end-of-file.  Stop. */
+		mp3_mad->status &= ~MS_playing;
+		return;
+	  }
+	}
+  }
+
+  /* Here we are, at the beginning of the frame that contains the
+	 target time.  Ehh, I say that's close enough.  If we wanted to,
+	 we could get more precise by decoding the frame now and counting
+	 the appropriate number of samples out of it. */
+}
+
+void
+mad_setVolume(mad_data *mp3_mad, int volume) {
+  mp3_mad->volume = volume;
+}

+ 68 - 0
libmad/music_mad.h

@@ -0,0 +1,68 @@
+/*
+    SDL_mixer:  An audio mixer library based on the SDL library
+    Copyright (C) 1997-2004 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#include "mad.h"
+#include "SDL_rwops.h"
+#include "SDL_audio.h"
+
+#define MAD_INPUT_BUFFER_SIZE	(5*8192)
+#define MAD_OUTPUT_BUFFER_SIZE	8192
+
+enum {
+  MS_input_eof    = 0x0001,
+  MS_input_error  = 0x0001,
+  MS_decode_eof   = 0x0002,
+  MS_decode_error = 0x0004,
+  MS_error_flags  = 0x000f,
+
+  MS_playing      = 0x0100,
+  MS_cvt_decoded  = 0x0200,
+};
+
+typedef struct {
+  SDL_RWops *rw;
+  struct mad_stream stream;
+  struct mad_frame frame;
+  struct mad_synth synth;
+  int frames_read;
+  mad_timer_t next_frame_start;
+  int volume;
+  int status;
+  int output_begin, output_end;
+  SDL_AudioSpec mixer;
+  SDL_AudioCVT cvt;
+
+  unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
+  unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
+} mad_data;
+
+mad_data *mad_openFile(const char *filename, SDL_AudioSpec *mixer);
+mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer);
+void mad_closeFile(mad_data *mp3_mad);
+
+void mad_start(mad_data *mp3_mad);
+void mad_stop(mad_data *mp3_mad);
+int mad_isPlaying(mad_data *mp3_mad);
+
+void mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
+void mad_seek(mad_data *mp3_mad, double position);
+void mad_setVolume(mad_data *mp3_mad, int volume);

+ 77 - 0
libmad/qc_table.dat

@@ -0,0 +1,77 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: qc_table.dat,v 1.7 2004/01/23 09:41:32 rob Exp $
+ */
+
+/*
+ * These are the Layer II classes of quantization.
+ * The table is derived from Table B.4 of ISO/IEC 11172-3.
+ */
+
+  {     3, 2,  5,
+    MAD_F(0x15555555) /* 1.33333333333 => 1.33333333209, e  0.00000000124 */,
+    MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e  0.00000000000 */ },
+  {     5, 3,  7,
+    MAD_F(0x1999999a) /* 1.60000000000 => 1.60000000149, e -0.00000000149 */,
+    MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e  0.00000000000 */ },
+  {     7, 0,  3,
+    MAD_F(0x12492492) /* 1.14285714286 => 1.14285714179, e  0.00000000107 */,
+    MAD_F(0x04000000) /* 0.25000000000 => 0.25000000000, e  0.00000000000 */ },
+  {     9, 4, 10,
+    MAD_F(0x1c71c71c) /* 1.77777777777 => 1.77777777612, e  0.00000000165 */,
+    MAD_F(0x08000000) /* 0.50000000000 => 0.50000000000, e  0.00000000000 */ },
+  {    15, 0,  4,
+    MAD_F(0x11111111) /* 1.06666666666 => 1.06666666642, e  0.00000000024 */,
+    MAD_F(0x02000000) /* 0.12500000000 => 0.12500000000, e  0.00000000000 */ },
+  {    31, 0,  5,
+    MAD_F(0x10842108) /* 1.03225806452 => 1.03225806355, e  0.00000000097 */,
+    MAD_F(0x01000000) /* 0.06250000000 => 0.06250000000, e  0.00000000000 */ },
+  {    63, 0,  6,
+    MAD_F(0x10410410) /* 1.01587301587 => 1.01587301493, e  0.00000000094 */,
+    MAD_F(0x00800000) /* 0.03125000000 => 0.03125000000, e  0.00000000000 */ },
+  {   127, 0,  7,
+    MAD_F(0x10204081) /* 1.00787401575 => 1.00787401572, e  0.00000000003 */,
+    MAD_F(0x00400000) /* 0.01562500000 => 0.01562500000, e  0.00000000000 */ },
+  {   255, 0,  8,
+    MAD_F(0x10101010) /* 1.00392156863 => 1.00392156839, e  0.00000000024 */,
+    MAD_F(0x00200000) /* 0.00781250000 => 0.00781250000, e  0.00000000000 */ },
+  {   511, 0,  9,
+    MAD_F(0x10080402) /* 1.00195694716 => 1.00195694715, e  0.00000000001 */,
+    MAD_F(0x00100000) /* 0.00390625000 => 0.00390625000, e  0.00000000000 */ },
+  {  1023, 0, 10,
+    MAD_F(0x10040100) /* 1.00097751711 => 1.00097751617, e  0.00000000094 */,
+    MAD_F(0x00080000) /* 0.00195312500 => 0.00195312500, e  0.00000000000 */ },
+  {  2047, 0, 11,
+    MAD_F(0x10020040) /* 1.00048851979 => 1.00048851967, e  0.00000000012 */,
+    MAD_F(0x00040000) /* 0.00097656250 => 0.00097656250, e  0.00000000000 */ },
+  {  4095, 0, 12,
+    MAD_F(0x10010010) /* 1.00024420024 => 1.00024420023, e  0.00000000001 */,
+    MAD_F(0x00020000) /* 0.00048828125 => 0.00048828125, e  0.00000000000 */ },
+  {  8191, 0, 13,
+    MAD_F(0x10008004) /* 1.00012208522 => 1.00012208521, e  0.00000000001 */,
+    MAD_F(0x00010000) /* 0.00024414063 => 0.00024414062, e  0.00000000000 */ },
+  { 16383, 0, 14,
+    MAD_F(0x10004001) /* 1.00006103888 => 1.00006103888, e -0.00000000000 */,
+    MAD_F(0x00008000) /* 0.00012207031 => 0.00012207031, e -0.00000000000 */ },
+  { 32767, 0, 15,
+    MAD_F(0x10002000) /* 1.00003051851 => 1.00003051758, e  0.00000000093 */,
+    MAD_F(0x00004000) /* 0.00006103516 => 0.00006103516, e  0.00000000000 */ },
+  { 65535, 0, 16,
+    MAD_F(0x10001000) /* 1.00001525902 => 1.00001525879, e  0.00000000023 */,
+    MAD_F(0x00002000) /* 0.00003051758 => 0.00003051758, e  0.00000000000 */ }

File diff suppressed because it is too large
+ 8747 - 0
libmad/rq_table.dat


+ 106 - 0
libmad/sf_table.dat

@@ -0,0 +1,106 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: sf_table.dat,v 1.7 2004/01/23 09:41:33 rob Exp $
+ */
+
+/*
+ * These are the scalefactor values for Layer I and Layer II.
+ * The values are from Table B.1 of ISO/IEC 11172-3.
+ *
+ * There is some error introduced by the 32-bit fixed-point representation;
+ * the amount of error is shown. For 16-bit PCM output, this shouldn't be
+ * too much of a problem.
+ *
+ * Strictly speaking, Table B.1 has only 63 entries (0-62), thus a strict
+ * interpretation of ISO/IEC 11172-3 would suggest that a scalefactor index of
+ * 63 is invalid. However, for better compatibility with current practices, we
+ * add a 64th entry.
+ */
+
+  MAD_F(0x20000000),  /* 2.000000000000 => 2.000000000000, e  0.000000000000 */
+  MAD_F(0x1965fea5),  /* 1.587401051968 => 1.587401051074, e  0.000000000894 */
+  MAD_F(0x1428a2fa),  /* 1.259921049895 => 1.259921051562, e -0.000000001667 */
+  MAD_F(0x10000000),  /* 1.000000000000 => 1.000000000000, e  0.000000000000 */
+  MAD_F(0x0cb2ff53),  /* 0.793700525984 => 0.793700527400, e -0.000000001416 */
+  MAD_F(0x0a14517d),  /* 0.629960524947 => 0.629960525781, e -0.000000000833 */
+  MAD_F(0x08000000),  /* 0.500000000000 => 0.500000000000, e  0.000000000000 */
+  MAD_F(0x06597fa9),  /* 0.396850262992 => 0.396850261837, e  0.000000001155 */
+
+  MAD_F(0x050a28be),  /* 0.314980262474 => 0.314980261028, e  0.000000001446 */
+  MAD_F(0x04000000),  /* 0.250000000000 => 0.250000000000, e  0.000000000000 */
+  MAD_F(0x032cbfd5),  /* 0.198425131496 => 0.198425132781, e -0.000000001285 */
+  MAD_F(0x0285145f),  /* 0.157490131237 => 0.157490130514, e  0.000000000723 */
+  MAD_F(0x02000000),  /* 0.125000000000 => 0.125000000000, e  0.000000000000 */
+  MAD_F(0x01965fea),  /* 0.099212565748 => 0.099212564528, e  0.000000001220 */
+  MAD_F(0x01428a30),  /* 0.078745065618 => 0.078745067120, e -0.000000001501 */
+  MAD_F(0x01000000),  /* 0.062500000000 => 0.062500000000, e  0.000000000000 */
+
+  MAD_F(0x00cb2ff5),  /* 0.049606282874 => 0.049606282264, e  0.000000000610 */
+  MAD_F(0x00a14518),  /* 0.039372532809 => 0.039372533560, e -0.000000000751 */
+  MAD_F(0x00800000),  /* 0.031250000000 => 0.031250000000, e  0.000000000000 */
+  MAD_F(0x006597fb),  /* 0.024803141437 => 0.024803142995, e -0.000000001558 */
+  MAD_F(0x0050a28c),  /* 0.019686266405 => 0.019686266780, e -0.000000000375 */
+  MAD_F(0x00400000),  /* 0.015625000000 => 0.015625000000, e  0.000000000000 */
+  MAD_F(0x0032cbfd),  /* 0.012401570719 => 0.012401569635, e  0.000000001084 */
+  MAD_F(0x00285146),  /* 0.009843133202 => 0.009843133390, e -0.000000000188 */
+
+  MAD_F(0x00200000),  /* 0.007812500000 => 0.007812500000, e  0.000000000000 */
+  MAD_F(0x001965ff),  /* 0.006200785359 => 0.006200786680, e -0.000000001321 */
+  MAD_F(0x001428a3),  /* 0.004921566601 => 0.004921566695, e -0.000000000094 */
+  MAD_F(0x00100000),  /* 0.003906250000 => 0.003906250000, e  0.000000000000 */
+  MAD_F(0x000cb2ff),  /* 0.003100392680 => 0.003100391477, e  0.000000001202 */
+  MAD_F(0x000a1451),  /* 0.002460783301 => 0.002460781485, e  0.000000001816 */
+  MAD_F(0x00080000),  /* 0.001953125000 => 0.001953125000, e  0.000000000000 */
+  MAD_F(0x00065980),  /* 0.001550196340 => 0.001550197601, e -0.000000001262 */
+
+  MAD_F(0x00050a29),  /* 0.001230391650 => 0.001230392605, e -0.000000000955 */
+  MAD_F(0x00040000),  /* 0.000976562500 => 0.000976562500, e  0.000000000000 */
+  MAD_F(0x00032cc0),  /* 0.000775098170 => 0.000775098801, e -0.000000000631 */
+  MAD_F(0x00028514),  /* 0.000615195825 => 0.000615194440, e  0.000000001385 */
+  MAD_F(0x00020000),  /* 0.000488281250 => 0.000488281250, e  0.000000000000 */
+  MAD_F(0x00019660),  /* 0.000387549085 => 0.000387549400, e -0.000000000315 */
+  MAD_F(0x0001428a),  /* 0.000307597913 => 0.000307597220, e  0.000000000693 */
+  MAD_F(0x00010000),  /* 0.000244140625 => 0.000244140625, e  0.000000000000 */
+
+  MAD_F(0x0000cb30),  /* 0.000193774542 => 0.000193774700, e -0.000000000158 */
+  MAD_F(0x0000a145),  /* 0.000153798956 => 0.000153798610, e  0.000000000346 */
+  MAD_F(0x00008000),  /* 0.000122070313 => 0.000122070313, e  0.000000000000 */
+  MAD_F(0x00006598),  /* 0.000096887271 => 0.000096887350, e -0.000000000079 */
+  MAD_F(0x000050a3),  /* 0.000076899478 => 0.000076901168, e -0.000000001689 */
+  MAD_F(0x00004000),  /* 0.000061035156 => 0.000061035156, e  0.000000000000 */
+  MAD_F(0x000032cc),  /* 0.000048443636 => 0.000048443675, e -0.000000000039 */
+  MAD_F(0x00002851),  /* 0.000038449739 => 0.000038448721, e  0.000000001018 */
+
+  MAD_F(0x00002000),  /* 0.000030517578 => 0.000030517578, e  0.000000000000 */
+  MAD_F(0x00001966),  /* 0.000024221818 => 0.000024221838, e -0.000000000020 */
+  MAD_F(0x00001429),  /* 0.000019224870 => 0.000019226223, e -0.000000001354 */
+  MAD_F(0x00001000),  /* 0.000015258789 => 0.000015258789, e -0.000000000000 */
+  MAD_F(0x00000cb3),  /* 0.000012110909 => 0.000012110919, e -0.000000000010 */
+  MAD_F(0x00000a14),  /* 0.000009612435 => 0.000009611249, e  0.000000001186 */
+  MAD_F(0x00000800),  /* 0.000007629395 => 0.000007629395, e -0.000000000000 */
+  MAD_F(0x00000659),  /* 0.000006055454 => 0.000006053597, e  0.000000001858 */
+
+  MAD_F(0x0000050a),  /* 0.000004806217 => 0.000004805624, e  0.000000000593 */
+  MAD_F(0x00000400),  /* 0.000003814697 => 0.000003814697, e  0.000000000000 */
+  MAD_F(0x0000032d),  /* 0.000003027727 => 0.000003028661, e -0.000000000934 */
+  MAD_F(0x00000285),  /* 0.000002403109 => 0.000002402812, e  0.000000000296 */
+  MAD_F(0x00000200),  /* 0.000001907349 => 0.000001907349, e -0.000000000000 */
+  MAD_F(0x00000196),  /* 0.000001513864 => 0.000001512468, e  0.000000001396 */
+  MAD_F(0x00000143),  /* 0.000001201554 => 0.000001203269, e -0.000000001714 */
+  MAD_F(0x00000000)   /* this compatibility entry is not part of Table B.1 */

+ 159 - 0
libmad/stream.c

@@ -0,0 +1,159 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: stream.c,v 1.12 2004/02/05 09:02:39 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# include <stdlib.h>
+
+# include "bit.h"
+# include "stream.h"
+
+/*
+ * NAME:	stream->init()
+ * DESCRIPTION:	initialize stream struct
+ */
+void mad_stream_init(struct mad_stream *stream)
+{
+  stream->buffer     = 0;
+  stream->bufend     = 0;
+  stream->skiplen    = 0;
+
+  stream->sync       = 0;
+  stream->freerate   = 0;
+
+  stream->this_frame = 0;
+  stream->next_frame = 0;
+  mad_bit_init(&stream->ptr, 0);
+
+  mad_bit_init(&stream->anc_ptr, 0);
+  stream->anc_bitlen = 0;
+
+  stream->main_data  = 0;
+  stream->md_len     = 0;
+
+  stream->options    = 0;
+  stream->error      = MAD_ERROR_NONE;
+}
+
+/*
+ * NAME:	stream->finish()
+ * DESCRIPTION:	deallocate any dynamic memory associated with stream
+ */
+void mad_stream_finish(struct mad_stream *stream)
+{
+  if (stream->main_data) {
+    free(stream->main_data);
+    stream->main_data = 0;
+  }
+
+  mad_bit_finish(&stream->anc_ptr);
+  mad_bit_finish(&stream->ptr);
+}
+
+/*
+ * NAME:	stream->buffer()
+ * DESCRIPTION:	set stream buffer pointers
+ */
+void mad_stream_buffer(struct mad_stream *stream,
+		       unsigned char const *buffer, unsigned long length)
+{
+  stream->buffer = buffer;
+  stream->bufend = buffer + length;
+
+  stream->this_frame = buffer;
+  stream->next_frame = buffer;
+
+  stream->sync = 1;
+
+  mad_bit_init(&stream->ptr, buffer);
+}
+
+/*
+ * NAME:	stream->skip()
+ * DESCRIPTION:	arrange to skip bytes before the next frame
+ */
+void mad_stream_skip(struct mad_stream *stream, unsigned long length)
+{
+  stream->skiplen += length;
+}
+
+/*
+ * NAME:	stream->sync()
+ * DESCRIPTION:	locate the next stream sync word
+ */
+int mad_stream_sync(struct mad_stream *stream)
+{
+  register unsigned char const *ptr, *end;
+
+  ptr = mad_bit_nextbyte(&stream->ptr);
+  end = stream->bufend;
+
+  while (ptr < end - 1 &&
+	 !(ptr[0] == 0xff && (ptr[1] & 0xe0) == 0xe0))
+    ++ptr;
+
+  if (end - ptr < MAD_BUFFER_GUARD)
+    return -1;
+
+  mad_bit_init(&stream->ptr, ptr);
+
+  return 0;
+}
+
+/*
+ * NAME:	stream->errorstr()
+ * DESCRIPTION:	return a string description of the current error condition
+ */
+char const *mad_stream_errorstr(struct mad_stream const *stream)
+{
+  switch (stream->error) {
+  case MAD_ERROR_NONE:		 return "no error";
+
+  case MAD_ERROR_BUFLEN:	 return "input buffer too small (or EOF)";
+  case MAD_ERROR_BUFPTR:	 return "invalid (null) buffer pointer";
+
+  case MAD_ERROR_NOMEM:		 return "not enough memory";
+
+  case MAD_ERROR_LOSTSYNC:	 return "lost synchronization";
+  case MAD_ERROR_BADLAYER:	 return "reserved header layer value";
+  case MAD_ERROR_BADBITRATE:	 return "forbidden bitrate value";
+  case MAD_ERROR_BADSAMPLERATE:	 return "reserved sample frequency value";
+  case MAD_ERROR_BADEMPHASIS:	 return "reserved emphasis value";
+
+  case MAD_ERROR_BADCRC:	 return "CRC check failed";
+  case MAD_ERROR_BADBITALLOC:	 return "forbidden bit allocation value";
+  case MAD_ERROR_BADSCALEFACTOR: return "bad scalefactor index";
+  case MAD_ERROR_BADMODE:	 return "bad bitrate/mode combination";
+  case MAD_ERROR_BADFRAMELEN:	 return "bad frame length";
+  case MAD_ERROR_BADBIGVALUES:	 return "bad big_values count";
+  case MAD_ERROR_BADBLOCKTYPE:	 return "reserved block_type";
+  case MAD_ERROR_BADSCFSI:	 return "bad scalefactor selection info";
+  case MAD_ERROR_BADDATAPTR:	 return "bad main_data_begin pointer";
+  case MAD_ERROR_BADPART3LEN:	 return "bad audio data length";
+  case MAD_ERROR_BADHUFFTABLE:	 return "bad Huffman table select";
+  case MAD_ERROR_BADHUFFDATA:	 return "Huffman data overrun";
+  case MAD_ERROR_BADSTEREO:	 return "incompatible block_type for JS";
+  }
+
+  return 0;
+}

+ 108 - 0
libmad/stream.h

@@ -0,0 +1,108 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp $
+ */
+
+# ifndef LIBMAD_STREAM_H
+# define LIBMAD_STREAM_H
+
+# include "bit.h"
+
+# define MAD_BUFFER_GUARD	8
+# define MAD_BUFFER_MDLEN	(511 + 2048 + MAD_BUFFER_GUARD)
+
+enum mad_error {
+  MAD_ERROR_NONE	   = 0x0000,	/* no error */
+
+  MAD_ERROR_BUFLEN	   = 0x0001,	/* input buffer too small (or EOF) */
+  MAD_ERROR_BUFPTR	   = 0x0002,	/* invalid (null) buffer pointer */
+
+  MAD_ERROR_NOMEM	   = 0x0031,	/* not enough memory */
+
+  MAD_ERROR_LOSTSYNC	   = 0x0101,	/* lost synchronization */
+  MAD_ERROR_BADLAYER	   = 0x0102,	/* reserved header layer value */
+  MAD_ERROR_BADBITRATE	   = 0x0103,	/* forbidden bitrate value */
+  MAD_ERROR_BADSAMPLERATE  = 0x0104,	/* reserved sample frequency value */
+  MAD_ERROR_BADEMPHASIS	   = 0x0105,	/* reserved emphasis value */
+
+  MAD_ERROR_BADCRC	   = 0x0201,	/* CRC check failed */
+  MAD_ERROR_BADBITALLOC	   = 0x0211,	/* forbidden bit allocation value */
+  MAD_ERROR_BADSCALEFACTOR = 0x0221,	/* bad scalefactor index */
+  MAD_ERROR_BADMODE        = 0x0222,	/* bad bitrate/mode combination */
+  MAD_ERROR_BADFRAMELEN	   = 0x0231,	/* bad frame length */
+  MAD_ERROR_BADBIGVALUES   = 0x0232,	/* bad big_values count */
+  MAD_ERROR_BADBLOCKTYPE   = 0x0233,	/* reserved block_type */
+  MAD_ERROR_BADSCFSI	   = 0x0234,	/* bad scalefactor selection info */
+  MAD_ERROR_BADDATAPTR	   = 0x0235,	/* bad main_data_begin pointer */
+  MAD_ERROR_BADPART3LEN	   = 0x0236,	/* bad audio data length */
+  MAD_ERROR_BADHUFFTABLE   = 0x0237,	/* bad Huffman table select */
+  MAD_ERROR_BADHUFFDATA	   = 0x0238,	/* Huffman data overrun */
+  MAD_ERROR_BADSTEREO	   = 0x0239	/* incompatible block_type for JS */
+};
+
+# define MAD_RECOVERABLE(error)	((error) & 0xff00)
+
+struct mad_stream {
+  unsigned char const *buffer;		/* input bitstream buffer */
+  unsigned char const *bufend;		/* end of buffer */
+  unsigned long skiplen;		/* bytes to skip before next frame */
+
+  int sync;				/* stream sync found */
+  unsigned long freerate;		/* free bitrate (fixed) */
+
+  unsigned char const *this_frame;	/* start of current frame */
+  unsigned char const *next_frame;	/* start of next frame */
+  struct mad_bitptr ptr;		/* current processing bit pointer */
+
+  struct mad_bitptr anc_ptr;		/* ancillary bits pointer */
+  unsigned int anc_bitlen;		/* number of ancillary bits */
+
+  unsigned char (*main_data)[MAD_BUFFER_MDLEN];
+					/* Layer III main_data() */
+  unsigned int md_len;			/* bytes in main_data */
+
+  int options;				/* decoding options (see below) */
+  enum mad_error error;			/* error code (see above) */
+};
+
+enum {
+  MAD_OPTION_IGNORECRC      = 0x0001,	/* ignore CRC errors */
+  MAD_OPTION_HALFSAMPLERATE = 0x0002	/* generate PCM at 1/2 sample rate */
+# if 0  /* not yet implemented */
+  MAD_OPTION_LEFTCHANNEL    = 0x0010,	/* decode left channel only */
+  MAD_OPTION_RIGHTCHANNEL   = 0x0020,	/* decode right channel only */
+  MAD_OPTION_SINGLECHANNEL  = 0x0030	/* combine channels */
+# endif
+};
+
+void mad_stream_init(struct mad_stream *);
+void mad_stream_finish(struct mad_stream *);
+
+# define mad_stream_options(stream, opts)  \
+    ((void) ((stream)->options = (opts)))
+
+void mad_stream_buffer(struct mad_stream *,
+		       unsigned char const *, unsigned long);
+void mad_stream_skip(struct mad_stream *, unsigned long);
+
+int mad_stream_sync(struct mad_stream *);
+
+char const *mad_stream_errorstr(struct mad_stream const *);
+
+# endif

+ 855 - 0
libmad/synth.c

@@ -0,0 +1,855 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: synth.c,v 1.25 2004/01/23 09:41:33 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# include "fixed.h"
+# include "frame.h"
+# include "synth.h"
+
+/*
+ * NAME:	synth->init()
+ * DESCRIPTION:	initialize synth struct
+ */
+void mad_synth_init(struct mad_synth *synth)
+{
+  mad_synth_mute(synth);
+
+  synth->phase = 0;
+
+  synth->pcm.samplerate = 0;
+  synth->pcm.channels   = 0;
+  synth->pcm.length     = 0;
+}
+
+/*
+ * NAME:	synth->mute()
+ * DESCRIPTION:	zero all polyphase filterbank values, resetting synthesis
+ */
+void mad_synth_mute(struct mad_synth *synth)
+{
+  unsigned int ch, s, v;
+
+  for (ch = 0; ch < 2; ++ch) {
+    for (s = 0; s < 16; ++s) {
+      for (v = 0; v < 8; ++v) {
+	synth->filter[ch][0][0][s][v] = synth->filter[ch][0][1][s][v] =
+	synth->filter[ch][1][0][s][v] = synth->filter[ch][1][1][s][v] = 0;
+      }
+    }
+  }
+}
+
+/*
+ * An optional optimization called here the Subband Synthesis Optimization
+ * (SSO) improves the performance of subband synthesis at the expense of
+ * accuracy.
+ *
+ * The idea is to simplify 32x32->64-bit multiplication to 32x32->32 such
+ * that extra scaling and rounding are not necessary. This often allows the
+ * compiler to use faster 32-bit multiply-accumulate instructions instead of
+ * explicit 64-bit multiply, shift, and add instructions.
+ *
+ * SSO works like this: a full 32x32->64-bit multiply of two mad_fixed_t
+ * values requires the result to be right-shifted 28 bits to be properly
+ * scaled to the same fixed-point format. Right shifts can be applied at any
+ * time to either operand or to the result, so the optimization involves
+ * careful placement of these shifts to minimize the loss of accuracy.
+ *
+ * First, a 14-bit shift is applied with rounding at compile-time to the D[]
+ * table of coefficients for the subband synthesis window. This only loses 2
+ * bits of accuracy because the lower 12 bits are always zero. A second
+ * 12-bit shift occurs after the DCT calculation. This loses 12 bits of
+ * accuracy. Finally, a third 2-bit shift occurs just before the sample is
+ * saved in the PCM buffer. 14 + 12 + 2 == 28 bits.
+ */
+
+/* FPM_DEFAULT without OPT_SSO will actually lose accuracy and performance */
+
+# if defined(FPM_DEFAULT) && !defined(OPT_SSO)
+#  define OPT_SSO
+# endif
+
+/* second SSO shift, with rounding */
+
+# if defined(OPT_SSO)
+#  define SHIFT(x)  (((x) + (1L << 11)) >> 12)
+# else
+#  define SHIFT(x)  (x)
+# endif
+
+/* possible DCT speed optimization */
+
+# if defined(OPT_SPEED) && defined(MAD_F_MLX)
+#  define OPT_DCTO
+#  define MUL(x, y)  \
+    ({ mad_fixed64hi_t hi;  \
+       mad_fixed64lo_t lo;  \
+       MAD_F_MLX(hi, lo, (x), (y));  \
+       hi << (32 - MAD_F_SCALEBITS - 3);  \
+    })
+# else
+#  undef OPT_DCTO
+#  define MUL(x, y)  mad_f_mul((x), (y))
+# endif
+
+/*
+ * NAME:	dct32()
+ * DESCRIPTION:	perform fast in[32]->out[32] DCT
+ */
+static
+void dct32(mad_fixed_t const in[32], unsigned int slot,
+	   mad_fixed_t lo[16][8], mad_fixed_t hi[16][8])
+{
+  mad_fixed_t t0,   t1,   t2,   t3,   t4,   t5,   t6,   t7;
+  mad_fixed_t t8,   t9,   t10,  t11,  t12,  t13,  t14,  t15;
+  mad_fixed_t t16,  t17,  t18,  t19,  t20,  t21,  t22,  t23;
+  mad_fixed_t t24,  t25,  t26,  t27,  t28,  t29,  t30,  t31;
+  mad_fixed_t t32,  t33,  t34,  t35,  t36,  t37,  t38,  t39;
+  mad_fixed_t t40,  t41,  t42,  t43,  t44,  t45,  t46,  t47;
+  mad_fixed_t t48,  t49,  t50,  t51,  t52,  t53,  t54,  t55;
+  mad_fixed_t t56,  t57,  t58,  t59,  t60,  t61,  t62,  t63;
+  mad_fixed_t t64,  t65,  t66,  t67,  t68,  t69,  t70,  t71;
+  mad_fixed_t t72,  t73,  t74,  t75,  t76,  t77,  t78,  t79;
+  mad_fixed_t t80,  t81,  t82,  t83,  t84,  t85,  t86,  t87;
+  mad_fixed_t t88,  t89,  t90,  t91,  t92,  t93,  t94,  t95;
+  mad_fixed_t t96,  t97,  t98,  t99,  t100, t101, t102, t103;
+  mad_fixed_t t104, t105, t106, t107, t108, t109, t110, t111;
+  mad_fixed_t t112, t113, t114, t115, t116, t117, t118, t119;
+  mad_fixed_t t120, t121, t122, t123, t124, t125, t126, t127;
+  mad_fixed_t t128, t129, t130, t131, t132, t133, t134, t135;
+  mad_fixed_t t136, t137, t138, t139, t140, t141, t142, t143;
+  mad_fixed_t t144, t145, t146, t147, t148, t149, t150, t151;
+  mad_fixed_t t152, t153, t154, t155, t156, t157, t158, t159;
+  mad_fixed_t t160, t161, t162, t163, t164, t165, t166, t167;
+  mad_fixed_t t168, t169, t170, t171, t172, t173, t174, t175;
+  mad_fixed_t t176;
+
+  /* costab[i] = cos(PI / (2 * 32) * i) */
+
+# if defined(OPT_DCTO)
+#  define costab1	MAD_F(0x7fd8878e)
+#  define costab2	MAD_F(0x7f62368f)
+#  define costab3	MAD_F(0x7e9d55fc)
+#  define costab4	MAD_F(0x7d8a5f40)
+#  define costab5	MAD_F(0x7c29fbee)
+#  define costab6	MAD_F(0x7a7d055b)
+#  define costab7	MAD_F(0x78848414)
+#  define costab8	MAD_F(0x7641af3d)
+#  define costab9	MAD_F(0x73b5ebd1)
+#  define costab10	MAD_F(0x70e2cbc6)
+#  define costab11	MAD_F(0x6dca0d14)
+#  define costab12	MAD_F(0x6a6d98a4)
+#  define costab13	MAD_F(0x66cf8120)
+#  define costab14	MAD_F(0x62f201ac)
+#  define costab15	MAD_F(0x5ed77c8a)
+#  define costab16	MAD_F(0x5a82799a)
+#  define costab17	MAD_F(0x55f5a4d2)
+#  define costab18	MAD_F(0x5133cc94)
+#  define costab19	MAD_F(0x4c3fdff4)
+#  define costab20	MAD_F(0x471cece7)
+#  define costab21	MAD_F(0x41ce1e65)
+#  define costab22	MAD_F(0x3c56ba70)
+#  define costab23	MAD_F(0x36ba2014)
+#  define costab24	MAD_F(0x30fbc54d)
+#  define costab25	MAD_F(0x2b1f34eb)
+#  define costab26	MAD_F(0x25280c5e)
+#  define costab27	MAD_F(0x1f19f97b)
+#  define costab28	MAD_F(0x18f8b83c)
+#  define costab29	MAD_F(0x12c8106f)
+#  define costab30	MAD_F(0x0c8bd35e)
+#  define costab31	MAD_F(0x0647d97c)
+# else
+#  define costab1	MAD_F(0x0ffb10f2)  /* 0.998795456 */
+#  define costab2	MAD_F(0x0fec46d2)  /* 0.995184727 */
+#  define costab3	MAD_F(0x0fd3aac0)  /* 0.989176510 */
+#  define costab4	MAD_F(0x0fb14be8)  /* 0.980785280 */
+#  define costab5	MAD_F(0x0f853f7e)  /* 0.970031253 */
+#  define costab6	MAD_F(0x0f4fa0ab)  /* 0.956940336 */
+#  define costab7	MAD_F(0x0f109082)  /* 0.941544065 */
+#  define costab8	MAD_F(0x0ec835e8)  /* 0.923879533 */
+#  define costab9	MAD_F(0x0e76bd7a)  /* 0.903989293 */
+#  define costab10	MAD_F(0x0e1c5979)  /* 0.881921264 */
+#  define costab11	MAD_F(0x0db941a3)  /* 0.857728610 */
+#  define costab12	MAD_F(0x0d4db315)  /* 0.831469612 */
+#  define costab13	MAD_F(0x0cd9f024)  /* 0.803207531 */
+#  define costab14	MAD_F(0x0c5e4036)  /* 0.773010453 */
+#  define costab15	MAD_F(0x0bdaef91)  /* 0.740951125 */
+#  define costab16	MAD_F(0x0b504f33)  /* 0.707106781 */
+#  define costab17	MAD_F(0x0abeb49a)  /* 0.671558955 */
+#  define costab18	MAD_F(0x0a267993)  /* 0.634393284 */
+#  define costab19	MAD_F(0x0987fbfe)  /* 0.595699304 */
+#  define costab20	MAD_F(0x08e39d9d)  /* 0.555570233 */
+#  define costab21	MAD_F(0x0839c3cd)  /* 0.514102744 */
+#  define costab22	MAD_F(0x078ad74e)  /* 0.471396737 */
+#  define costab23	MAD_F(0x06d74402)  /* 0.427555093 */
+#  define costab24	MAD_F(0x061f78aa)  /* 0.382683432 */
+#  define costab25	MAD_F(0x0563e69d)  /* 0.336889853 */
+#  define costab26	MAD_F(0x04a5018c)  /* 0.290284677 */
+#  define costab27	MAD_F(0x03e33f2f)  /* 0.242980180 */
+#  define costab28	MAD_F(0x031f1708)  /* 0.195090322 */
+#  define costab29	MAD_F(0x0259020e)  /* 0.146730474 */
+#  define costab30	MAD_F(0x01917a6c)  /* 0.098017140 */
+#  define costab31	MAD_F(0x00c8fb30)  /* 0.049067674 */
+# endif
+
+  t0   = in[0]  + in[31];  t16  = MUL(in[0]  - in[31], costab1);
+  t1   = in[15] + in[16];  t17  = MUL(in[15] - in[16], costab31);
+
+  t41  = t16 + t17;
+  t59  = MUL(t16 - t17, costab2);
+  t33  = t0  + t1;
+  t50  = MUL(t0  - t1,  costab2);
+
+  t2   = in[7]  + in[24];  t18  = MUL(in[7]  - in[24], costab15);
+  t3   = in[8]  + in[23];  t19  = MUL(in[8]  - in[23], costab17);
+
+  t42  = t18 + t19;
+  t60  = MUL(t18 - t19, costab30);
+  t34  = t2  + t3;
+  t51  = MUL(t2  - t3,  costab30);
+
+  t4   = in[3]  + in[28];  t20  = MUL(in[3]  - in[28], costab7);
+  t5   = in[12] + in[19];  t21  = MUL(in[12] - in[19], costab25);
+
+  t43  = t20 + t21;
+  t61  = MUL(t20 - t21, costab14);
+  t35  = t4  + t5;
+  t52  = MUL(t4  - t5,  costab14);
+
+  t6   = in[4]  + in[27];  t22  = MUL(in[4]  - in[27], costab9);
+  t7   = in[11] + in[20];  t23  = MUL(in[11] - in[20], costab23);
+
+  t44  = t22 + t23;
+  t62  = MUL(t22 - t23, costab18);
+  t36  = t6  + t7;
+  t53  = MUL(t6  - t7,  costab18);
+
+  t8   = in[1]  + in[30];  t24  = MUL(in[1]  - in[30], costab3);
+  t9   = in[14] + in[17];  t25  = MUL(in[14] - in[17], costab29);
+
+  t45  = t24 + t25;
+  t63  = MUL(t24 - t25, costab6);
+  t37  = t8  + t9;
+  t54  = MUL(t8  - t9,  costab6);
+
+  t10  = in[6]  + in[25];  t26  = MUL(in[6]  - in[25], costab13);
+  t11  = in[9]  + in[22];  t27  = MUL(in[9]  - in[22], costab19);
+
+  t46  = t26 + t27;
+  t64  = MUL(t26 - t27, costab26);
+  t38  = t10 + t11;
+  t55  = MUL(t10 - t11, costab26);
+
+  t12  = in[2]  + in[29];  t28  = MUL(in[2]  - in[29], costab5);
+  t13  = in[13] + in[18];  t29  = MUL(in[13] - in[18], costab27);
+
+  t47  = t28 + t29;
+  t65  = MUL(t28 - t29, costab10);
+  t39  = t12 + t13;
+  t56  = MUL(t12 - t13, costab10);
+
+  t14  = in[5]  + in[26];  t30  = MUL(in[5]  - in[26], costab11);
+  t15  = in[10] + in[21];  t31  = MUL(in[10] - in[21], costab21);
+
+  t48  = t30 + t31;
+  t66  = MUL(t30 - t31, costab22);
+  t40  = t14 + t15;
+  t57  = MUL(t14 - t15, costab22);
+
+  t69  = t33 + t34;  t89  = MUL(t33 - t34, costab4);
+  t70  = t35 + t36;  t90  = MUL(t35 - t36, costab28);
+  t71  = t37 + t38;  t91  = MUL(t37 - t38, costab12);
+  t72  = t39 + t40;  t92  = MUL(t39 - t40, costab20);
+  t73  = t41 + t42;  t94  = MUL(t41 - t42, costab4);
+  t74  = t43 + t44;  t95  = MUL(t43 - t44, costab28);
+  t75  = t45 + t46;  t96  = MUL(t45 - t46, costab12);
+  t76  = t47 + t48;  t97  = MUL(t47 - t48, costab20);
+
+  t78  = t50 + t51;  t100 = MUL(t50 - t51, costab4);
+  t79  = t52 + t53;  t101 = MUL(t52 - t53, costab28);
+  t80  = t54 + t55;  t102 = MUL(t54 - t55, costab12);
+  t81  = t56 + t57;  t103 = MUL(t56 - t57, costab20);
+
+  t83  = t59 + t60;  t106 = MUL(t59 - t60, costab4);
+  t84  = t61 + t62;  t107 = MUL(t61 - t62, costab28);
+  t85  = t63 + t64;  t108 = MUL(t63 - t64, costab12);
+  t86  = t65 + t66;  t109 = MUL(t65 - t66, costab20);
+
+  t113 = t69  + t70;
+  t114 = t71  + t72;
+
+  /*  0 */ hi[15][slot] = SHIFT(t113 + t114);
+  /* 16 */ lo[ 0][slot] = SHIFT(MUL(t113 - t114, costab16));
+
+  t115 = t73  + t74;
+  t116 = t75  + t76;
+
+  t32  = t115 + t116;
+
+  /*  1 */ hi[14][slot] = SHIFT(t32);
+
+  t118 = t78  + t79;
+  t119 = t80  + t81;
+
+  t58  = t118 + t119;
+
+  /*  2 */ hi[13][slot] = SHIFT(t58);
+
+  t121 = t83  + t84;
+  t122 = t85  + t86;
+
+  t67  = t121 + t122;
+
+  t49  = (t67 * 2) - t32;
+
+  /*  3 */ hi[12][slot] = SHIFT(t49);
+
+  t125 = t89  + t90;
+  t126 = t91  + t92;
+
+  t93  = t125 + t126;
+
+  /*  4 */ hi[11][slot] = SHIFT(t93);
+
+  t128 = t94  + t95;
+  t129 = t96  + t97;
+
+  t98  = t128 + t129;
+
+  t68  = (t98 * 2) - t49;
+
+  /*  5 */ hi[10][slot] = SHIFT(t68);
+
+  t132 = t100 + t101;
+  t133 = t102 + t103;
+
+  t104 = t132 + t133;
+
+  t82  = (t104 * 2) - t58;
+
+  /*  6 */ hi[ 9][slot] = SHIFT(t82);
+
+  t136 = t106 + t107;
+  t137 = t108 + t109;
+
+  t110 = t136 + t137;
+
+  t87  = (t110 * 2) - t67;
+
+  t77  = (t87 * 2) - t68;
+
+  /*  7 */ hi[ 8][slot] = SHIFT(t77);
+
+  t141 = MUL(t69 - t70, costab8);
+  t142 = MUL(t71 - t72, costab24);
+  t143 = t141 + t142;
+
+  /*  8 */ hi[ 7][slot] = SHIFT(t143);
+  /* 24 */ lo[ 8][slot] =
+	     SHIFT((MUL(t141 - t142, costab16) * 2) - t143);
+
+  t144 = MUL(t73 - t74, costab8);
+  t145 = MUL(t75 - t76, costab24);
+  t146 = t144 + t145;
+
+  t88  = (t146 * 2) - t77;
+
+  /*  9 */ hi[ 6][slot] = SHIFT(t88);
+
+  t148 = MUL(t78 - t79, costab8);
+  t149 = MUL(t80 - t81, costab24);
+  t150 = t148 + t149;
+
+  t105 = (t150 * 2) - t82;
+
+  /* 10 */ hi[ 5][slot] = SHIFT(t105);
+
+  t152 = MUL(t83 - t84, costab8);
+  t153 = MUL(t85 - t86, costab24);
+  t154 = t152 + t153;
+
+  t111 = (t154 * 2) - t87;
+
+  t99  = (t111 * 2) - t88;
+
+  /* 11 */ hi[ 4][slot] = SHIFT(t99);
+
+  t157 = MUL(t89 - t90, costab8);
+  t158 = MUL(t91 - t92, costab24);
+  t159 = t157 + t158;
+
+  t127 = (t159 * 2) - t93;
+
+  /* 12 */ hi[ 3][slot] = SHIFT(t127);
+
+  t160 = (MUL(t125 - t126, costab16) * 2) - t127;
+
+  /* 20 */ lo[ 4][slot] = SHIFT(t160);
+  /* 28 */ lo[12][slot] =
+	     SHIFT((((MUL(t157 - t158, costab16) * 2) - t159) * 2) - t160);
+
+  t161 = MUL(t94 - t95, costab8);
+  t162 = MUL(t96 - t97, costab24);
+  t163 = t161 + t162;
+
+  t130 = (t163 * 2) - t98;
+
+  t112 = (t130 * 2) - t99;
+
+  /* 13 */ hi[ 2][slot] = SHIFT(t112);
+
+  t164 = (MUL(t128 - t129, costab16) * 2) - t130;
+
+  t166 = MUL(t100 - t101, costab8);
+  t167 = MUL(t102 - t103, costab24);
+  t168 = t166 + t167;
+
+  t134 = (t168 * 2) - t104;
+
+  t120 = (t134 * 2) - t105;
+
+  /* 14 */ hi[ 1][slot] = SHIFT(t120);
+
+  t135 = (MUL(t118 - t119, costab16) * 2) - t120;
+
+  /* 18 */ lo[ 2][slot] = SHIFT(t135);
+
+  t169 = (MUL(t132 - t133, costab16) * 2) - t134;
+
+  t151 = (t169 * 2) - t135;
+
+  /* 22 */ lo[ 6][slot] = SHIFT(t151);
+
+  t170 = (((MUL(t148 - t149, costab16) * 2) - t150) * 2) - t151;
+
+  /* 26 */ lo[10][slot] = SHIFT(t170);
+  /* 30 */ lo[14][slot] =
+	     SHIFT((((((MUL(t166 - t167, costab16) * 2) -
+		       t168) * 2) - t169) * 2) - t170);
+
+  t171 = MUL(t106 - t107, costab8);
+  t172 = MUL(t108 - t109, costab24);
+  t173 = t171 + t172;
+
+  t138 = (t173 * 2) - t110;
+
+  t123 = (t138 * 2) - t111;
+
+  t139 = (MUL(t121 - t122, costab16) * 2) - t123;
+
+  t117 = (t123 * 2) - t112;
+
+  /* 15 */ hi[ 0][slot] = SHIFT(t117);
+
+  t124 = (MUL(t115 - t116, costab16) * 2) - t117;
+
+  /* 17 */ lo[ 1][slot] = SHIFT(t124);
+
+  t131 = (t139 * 2) - t124;
+
+  /* 19 */ lo[ 3][slot] = SHIFT(t131);
+
+  t140 = (t164 * 2) - t131;
+
+  /* 21 */ lo[ 5][slot] = SHIFT(t140);
+
+  t174 = (MUL(t136 - t137, costab16) * 2) - t138;
+
+  t155 = (t174 * 2) - t139;
+
+  t147 = (t155 * 2) - t140;
+
+  /* 23 */ lo[ 7][slot] = SHIFT(t147);
+
+  t156 = (((MUL(t144 - t145, costab16) * 2) - t146) * 2) - t147;
+
+  /* 25 */ lo[ 9][slot] = SHIFT(t156);
+
+  t175 = (((MUL(t152 - t153, costab16) * 2) - t154) * 2) - t155;
+
+  t165 = (t175 * 2) - t156;
+
+  /* 27 */ lo[11][slot] = SHIFT(t165);
+
+  t176 = (((((MUL(t161 - t162, costab16) * 2) -
+	     t163) * 2) - t164) * 2) - t165;
+
+  /* 29 */ lo[13][slot] = SHIFT(t176);
+  /* 31 */ lo[15][slot] =
+	     SHIFT((((((((MUL(t171 - t172, costab16) * 2) -
+			 t173) * 2) - t174) * 2) - t175) * 2) - t176);
+
+  /*
+   * Totals:
+   *  80 multiplies
+   *  80 additions
+   * 119 subtractions
+   *  49 shifts (not counting SSO)
+   */
+}
+
+# undef MUL
+# undef SHIFT
+
+/* third SSO shift and/or D[] optimization preshift */
+
+# if defined(OPT_SSO)
+#  if MAD_F_FRACBITS != 28
+#   error "MAD_F_FRACBITS must be 28 to use OPT_SSO"
+#  endif
+#  define ML0(hi, lo, x, y)	((lo)  = (x) * (y))
+#  define MLA(hi, lo, x, y)	((lo) += (x) * (y))
+#  define MLN(hi, lo)		((lo)  = -(lo))
+#  define MLZ(hi, lo)		((void) (hi), (mad_fixed_t) (lo))
+#  define SHIFT(x)		((x) >> 2)
+#  define PRESHIFT(x)		((MAD_F(x) + (1L << 13)) >> 14)
+# else
+#  define ML0(hi, lo, x, y)	MAD_F_ML0((hi), (lo), (x), (y))
+#  define MLA(hi, lo, x, y)	MAD_F_MLA((hi), (lo), (x), (y))
+#  define MLN(hi, lo)		MAD_F_MLN((hi), (lo))
+#  define MLZ(hi, lo)		MAD_F_MLZ((hi), (lo))
+#  define SHIFT(x)		(x)
+#  if defined(MAD_F_SCALEBITS)
+#   undef  MAD_F_SCALEBITS
+#   define MAD_F_SCALEBITS	(MAD_F_FRACBITS - 12)
+#   define PRESHIFT(x)		(MAD_F(x) >> 12)
+#  else
+#   define PRESHIFT(x)		MAD_F(x)
+#  endif
+# endif
+
+static
+mad_fixed_t const D[17][32] = {
+# include "D.dat"
+};
+
+# if defined(ASO_SYNTH)
+void synth_full(struct mad_synth *, struct mad_frame const *,
+		unsigned int, unsigned int);
+# else
+/*
+ * NAME:	synth->full()
+ * DESCRIPTION:	perform full frequency PCM synthesis
+ */
+static
+void synth_full(struct mad_synth *synth, struct mad_frame const *frame,
+		unsigned int nch, unsigned int ns)
+{
+  unsigned int phase, ch, s, sb, pe, po;
+  mad_fixed_t *pcm1, *pcm2, (*filter)[2][2][16][8];
+  mad_fixed_t const (*sbsample)[36][32];
+  register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8];
+  register mad_fixed_t const (*Dptr)[32], *ptr;
+  register mad_fixed64hi_t hi;
+  register mad_fixed64lo_t lo;
+
+  for (ch = 0; ch < nch; ++ch) {
+    sbsample = &frame->sbsample[ch];
+    filter   = &synth->filter[ch];
+    phase    = synth->phase;
+    pcm1     = synth->pcm.samples[ch];
+
+    for (s = 0; s < ns; ++s) {
+      dct32((*sbsample)[s], phase >> 1,
+	    (*filter)[0][phase & 1], (*filter)[1][phase & 1]);
+
+      pe = phase & ~1;
+      po = ((phase - 1) & 0xf) | 1;
+
+      /* calculate 32 samples */
+
+      fe = &(*filter)[0][ phase & 1][0];
+      fx = &(*filter)[0][~phase & 1][0];
+      fo = &(*filter)[1][~phase & 1][0];
+
+      Dptr = &D[0];
+
+      ptr = *Dptr + po;
+      ML0(hi, lo, (*fx)[0], ptr[ 0]);
+      MLA(hi, lo, (*fx)[1], ptr[14]);
+      MLA(hi, lo, (*fx)[2], ptr[12]);
+      MLA(hi, lo, (*fx)[3], ptr[10]);
+      MLA(hi, lo, (*fx)[4], ptr[ 8]);
+      MLA(hi, lo, (*fx)[5], ptr[ 6]);
+      MLA(hi, lo, (*fx)[6], ptr[ 4]);
+      MLA(hi, lo, (*fx)[7], ptr[ 2]);
+      MLN(hi, lo);
+
+      ptr = *Dptr + pe;
+      MLA(hi, lo, (*fe)[0], ptr[ 0]);
+      MLA(hi, lo, (*fe)[1], ptr[14]);
+      MLA(hi, lo, (*fe)[2], ptr[12]);
+      MLA(hi, lo, (*fe)[3], ptr[10]);
+      MLA(hi, lo, (*fe)[4], ptr[ 8]);
+      MLA(hi, lo, (*fe)[5], ptr[ 6]);
+      MLA(hi, lo, (*fe)[6], ptr[ 4]);
+      MLA(hi, lo, (*fe)[7], ptr[ 2]);
+
+      *pcm1++ = SHIFT(MLZ(hi, lo));
+
+      pcm2 = pcm1 + 30;
+
+      for (sb = 1; sb < 16; ++sb) {
+	++fe;
+	++Dptr;
+
+	/* D[32 - sb][i] == -D[sb][31 - i] */
+
+	ptr = *Dptr + po;
+	ML0(hi, lo, (*fo)[0], ptr[ 0]);
+	MLA(hi, lo, (*fo)[1], ptr[14]);
+	MLA(hi, lo, (*fo)[2], ptr[12]);
+	MLA(hi, lo, (*fo)[3], ptr[10]);
+	MLA(hi, lo, (*fo)[4], ptr[ 8]);
+	MLA(hi, lo, (*fo)[5], ptr[ 6]);
+	MLA(hi, lo, (*fo)[6], ptr[ 4]);
+	MLA(hi, lo, (*fo)[7], ptr[ 2]);
+	MLN(hi, lo);
+
+	ptr = *Dptr + pe;
+	MLA(hi, lo, (*fe)[7], ptr[ 2]);
+	MLA(hi, lo, (*fe)[6], ptr[ 4]);
+	MLA(hi, lo, (*fe)[5], ptr[ 6]);
+	MLA(hi, lo, (*fe)[4], ptr[ 8]);
+	MLA(hi, lo, (*fe)[3], ptr[10]);
+	MLA(hi, lo, (*fe)[2], ptr[12]);
+	MLA(hi, lo, (*fe)[1], ptr[14]);
+	MLA(hi, lo, (*fe)[0], ptr[ 0]);
+
+	*pcm1++ = SHIFT(MLZ(hi, lo));
+
+	ptr = *Dptr - pe;
+	ML0(hi, lo, (*fe)[0], ptr[31 - 16]);
+	MLA(hi, lo, (*fe)[1], ptr[31 - 14]);
+	MLA(hi, lo, (*fe)[2], ptr[31 - 12]);
+	MLA(hi, lo, (*fe)[3], ptr[31 - 10]);
+	MLA(hi, lo, (*fe)[4], ptr[31 -  8]);
+	MLA(hi, lo, (*fe)[5], ptr[31 -  6]);
+	MLA(hi, lo, (*fe)[6], ptr[31 -  4]);
+	MLA(hi, lo, (*fe)[7], ptr[31 -  2]);
+
+	ptr = *Dptr - po;
+	MLA(hi, lo, (*fo)[7], ptr[31 -  2]);
+	MLA(hi, lo, (*fo)[6], ptr[31 -  4]);
+	MLA(hi, lo, (*fo)[5], ptr[31 -  6]);
+	MLA(hi, lo, (*fo)[4], ptr[31 -  8]);
+	MLA(hi, lo, (*fo)[3], ptr[31 - 10]);
+	MLA(hi, lo, (*fo)[2], ptr[31 - 12]);
+	MLA(hi, lo, (*fo)[1], ptr[31 - 14]);
+	MLA(hi, lo, (*fo)[0], ptr[31 - 16]);
+
+	*pcm2-- = SHIFT(MLZ(hi, lo));
+
+	++fo;
+      }
+
+      ++Dptr;
+
+      ptr = *Dptr + po;
+      ML0(hi, lo, (*fo)[0], ptr[ 0]);
+      MLA(hi, lo, (*fo)[1], ptr[14]);
+      MLA(hi, lo, (*fo)[2], ptr[12]);
+      MLA(hi, lo, (*fo)[3], ptr[10]);
+      MLA(hi, lo, (*fo)[4], ptr[ 8]);
+      MLA(hi, lo, (*fo)[5], ptr[ 6]);
+      MLA(hi, lo, (*fo)[6], ptr[ 4]);
+      MLA(hi, lo, (*fo)[7], ptr[ 2]);
+
+      *pcm1 = SHIFT(-MLZ(hi, lo));
+      pcm1 += 16;
+
+      phase = (phase + 1) % 16;
+    }
+  }
+}
+# endif
+
+/*
+ * NAME:	synth->half()
+ * DESCRIPTION:	perform half frequency PCM synthesis
+ */
+static
+void synth_half(struct mad_synth *synth, struct mad_frame const *frame,
+		unsigned int nch, unsigned int ns)
+{
+  unsigned int phase, ch, s, sb, pe, po;
+  mad_fixed_t *pcm1, *pcm2, (*filter)[2][2][16][8];
+  mad_fixed_t const (*sbsample)[36][32];
+  register mad_fixed_t (*fe)[8], (*fx)[8], (*fo)[8];
+  register mad_fixed_t const (*Dptr)[32], *ptr;
+  register mad_fixed64hi_t hi;
+  register mad_fixed64lo_t lo;
+
+  for (ch = 0; ch < nch; ++ch) {
+    sbsample = &frame->sbsample[ch];
+    filter   = &synth->filter[ch];
+    phase    = synth->phase;
+    pcm1     = synth->pcm.samples[ch];
+
+    for (s = 0; s < ns; ++s) {
+      dct32((*sbsample)[s], phase >> 1,
+	    (*filter)[0][phase & 1], (*filter)[1][phase & 1]);
+
+      pe = phase & ~1;
+      po = ((phase - 1) & 0xf) | 1;
+
+      /* calculate 16 samples */
+
+      fe = &(*filter)[0][ phase & 1][0];
+      fx = &(*filter)[0][~phase & 1][0];
+      fo = &(*filter)[1][~phase & 1][0];
+
+      Dptr = &D[0];
+
+      ptr = *Dptr + po;
+      ML0(hi, lo, (*fx)[0], ptr[ 0]);
+      MLA(hi, lo, (*fx)[1], ptr[14]);
+      MLA(hi, lo, (*fx)[2], ptr[12]);
+      MLA(hi, lo, (*fx)[3], ptr[10]);
+      MLA(hi, lo, (*fx)[4], ptr[ 8]);
+      MLA(hi, lo, (*fx)[5], ptr[ 6]);
+      MLA(hi, lo, (*fx)[6], ptr[ 4]);
+      MLA(hi, lo, (*fx)[7], ptr[ 2]);
+      MLN(hi, lo);
+
+      ptr = *Dptr + pe;
+      MLA(hi, lo, (*fe)[0], ptr[ 0]);
+      MLA(hi, lo, (*fe)[1], ptr[14]);
+      MLA(hi, lo, (*fe)[2], ptr[12]);
+      MLA(hi, lo, (*fe)[3], ptr[10]);
+      MLA(hi, lo, (*fe)[4], ptr[ 8]);
+      MLA(hi, lo, (*fe)[5], ptr[ 6]);
+      MLA(hi, lo, (*fe)[6], ptr[ 4]);
+      MLA(hi, lo, (*fe)[7], ptr[ 2]);
+
+      *pcm1++ = SHIFT(MLZ(hi, lo));
+
+      pcm2 = pcm1 + 14;
+
+      for (sb = 1; sb < 16; ++sb) {
+	++fe;
+	++Dptr;
+
+	/* D[32 - sb][i] == -D[sb][31 - i] */
+
+	if (!(sb & 1)) {
+	  ptr = *Dptr + po;
+	  ML0(hi, lo, (*fo)[0], ptr[ 0]);
+	  MLA(hi, lo, (*fo)[1], ptr[14]);
+	  MLA(hi, lo, (*fo)[2], ptr[12]);
+	  MLA(hi, lo, (*fo)[3], ptr[10]);
+	  MLA(hi, lo, (*fo)[4], ptr[ 8]);
+	  MLA(hi, lo, (*fo)[5], ptr[ 6]);
+	  MLA(hi, lo, (*fo)[6], ptr[ 4]);
+	  MLA(hi, lo, (*fo)[7], ptr[ 2]);
+	  MLN(hi, lo);
+
+	  ptr = *Dptr + pe;
+	  MLA(hi, lo, (*fe)[7], ptr[ 2]);
+	  MLA(hi, lo, (*fe)[6], ptr[ 4]);
+	  MLA(hi, lo, (*fe)[5], ptr[ 6]);
+	  MLA(hi, lo, (*fe)[4], ptr[ 8]);
+	  MLA(hi, lo, (*fe)[3], ptr[10]);
+	  MLA(hi, lo, (*fe)[2], ptr[12]);
+	  MLA(hi, lo, (*fe)[1], ptr[14]);
+	  MLA(hi, lo, (*fe)[0], ptr[ 0]);
+
+	  *pcm1++ = SHIFT(MLZ(hi, lo));
+
+	  ptr = *Dptr - po;
+	  ML0(hi, lo, (*fo)[7], ptr[31 -  2]);
+	  MLA(hi, lo, (*fo)[6], ptr[31 -  4]);
+	  MLA(hi, lo, (*fo)[5], ptr[31 -  6]);
+	  MLA(hi, lo, (*fo)[4], ptr[31 -  8]);
+	  MLA(hi, lo, (*fo)[3], ptr[31 - 10]);
+	  MLA(hi, lo, (*fo)[2], ptr[31 - 12]);
+	  MLA(hi, lo, (*fo)[1], ptr[31 - 14]);
+	  MLA(hi, lo, (*fo)[0], ptr[31 - 16]);
+
+	  ptr = *Dptr - pe;
+	  MLA(hi, lo, (*fe)[0], ptr[31 - 16]);
+	  MLA(hi, lo, (*fe)[1], ptr[31 - 14]);
+	  MLA(hi, lo, (*fe)[2], ptr[31 - 12]);
+	  MLA(hi, lo, (*fe)[3], ptr[31 - 10]);
+	  MLA(hi, lo, (*fe)[4], ptr[31 -  8]);
+	  MLA(hi, lo, (*fe)[5], ptr[31 -  6]);
+	  MLA(hi, lo, (*fe)[6], ptr[31 -  4]);
+	  MLA(hi, lo, (*fe)[7], ptr[31 -  2]);
+
+	  *pcm2-- = SHIFT(MLZ(hi, lo));
+	}
+
+	++fo;
+      }
+
+      ++Dptr;
+
+      ptr = *Dptr + po;
+      ML0(hi, lo, (*fo)[0], ptr[ 0]);
+      MLA(hi, lo, (*fo)[1], ptr[14]);
+      MLA(hi, lo, (*fo)[2], ptr[12]);
+      MLA(hi, lo, (*fo)[3], ptr[10]);
+      MLA(hi, lo, (*fo)[4], ptr[ 8]);
+      MLA(hi, lo, (*fo)[5], ptr[ 6]);
+      MLA(hi, lo, (*fo)[6], ptr[ 4]);
+      MLA(hi, lo, (*fo)[7], ptr[ 2]);
+
+      *pcm1 = SHIFT(-MLZ(hi, lo));
+      pcm1 += 8;
+
+      phase = (phase + 1) % 16;
+    }
+  }
+}
+
+/*
+ * NAME:	synth->frame()
+ * DESCRIPTION:	perform PCM synthesis of frame subband samples
+ */
+void mad_synth_frame(struct mad_synth *synth, struct mad_frame const *frame)
+{
+  unsigned int nch, ns;
+  void (*synth_frame)(struct mad_synth *, struct mad_frame const *,
+		      unsigned int, unsigned int);
+
+  nch = MAD_NCHANNELS(&frame->header);
+  ns  = MAD_NSBSAMPLES(&frame->header);
+
+  synth->pcm.samplerate = frame->header.samplerate;
+  synth->pcm.channels   = nch;
+  synth->pcm.length     = 32 * ns;
+
+  synth_frame = synth_full;
+
+  if (frame->options & MAD_OPTION_HALFSAMPLERATE) {
+    synth->pcm.samplerate /= 2;
+    synth->pcm.length     /= 2;
+
+    synth_frame = synth_half;
+  }
+
+  synth_frame(synth, frame, nch, ns);
+
+  synth->phase = (synth->phase + ns) % 16;
+}

+ 69 - 0
libmad/synth.h

@@ -0,0 +1,69 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp $
+ */
+
+# ifndef LIBMAD_SYNTH_H
+# define LIBMAD_SYNTH_H
+
+# include "fixed.h"
+# include "frame.h"
+
+struct mad_pcm {
+  unsigned int samplerate;		/* sampling frequency (Hz) */
+  unsigned short channels;		/* number of channels */
+  unsigned short length;		/* number of samples per channel */
+  mad_fixed_t samples[2][1152];		/* PCM output samples [ch][sample] */
+};
+
+struct mad_synth {
+  mad_fixed_t filter[2][2][2][16][8];	/* polyphase filterbank outputs */
+  					/* [ch][eo][peo][s][v] */
+
+  unsigned int phase;			/* current processing phase */
+
+  struct mad_pcm pcm;			/* PCM output */
+};
+
+/* single channel PCM selector */
+enum {
+  MAD_PCM_CHANNEL_SINGLE = 0
+};
+
+/* dual channel PCM selector */
+enum {
+  MAD_PCM_CHANNEL_DUAL_1 = 0,
+  MAD_PCM_CHANNEL_DUAL_2 = 1
+};
+
+/* stereo PCM selector */
+enum {
+  MAD_PCM_CHANNEL_STEREO_LEFT  = 0,
+  MAD_PCM_CHANNEL_STEREO_RIGHT = 1
+};
+
+void mad_synth_init(struct mad_synth *);
+
+# define mad_synth_finish(synth)  /* nothing */
+
+void mad_synth_mute(struct mad_synth *);
+
+void mad_synth_frame(struct mad_synth *, struct mad_frame const *);
+
+# endif

+ 483 - 0
libmad/timer.c

@@ -0,0 +1,483 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: timer.c,v 1.18 2004/01/23 09:41:33 rob Exp $
+ */
+
+# include "libmad_config.h"
+
+# include "libmad_global.h"
+
+# include <stdio.h>
+
+# ifdef HAVE_ASSERT_H
+#  include <assert.h>
+# endif
+
+# include "timer.h"
+
+mad_timer_t const mad_timer_zero = { 0, 0 };
+
+/*
+ * NAME:	timer->compare()
+ * DESCRIPTION:	indicate relative order of two timers
+ */
+int mad_timer_compare(mad_timer_t timer1, mad_timer_t timer2)
+{
+  signed long diff;
+
+  diff = timer1.seconds - timer2.seconds;
+  if (diff < 0)
+    return -1;
+  else if (diff > 0)
+    return +1;
+
+  diff = timer1.fraction - timer2.fraction;
+  if (diff < 0)
+    return -1;
+  else if (diff > 0)
+    return +1;
+
+  return 0;
+}
+
+/*
+ * NAME:	timer->negate()
+ * DESCRIPTION:	invert the sign of a timer
+ */
+void mad_timer_negate(mad_timer_t *timer)
+{
+  timer->seconds = -timer->seconds;
+
+  if (timer->fraction) {
+    timer->seconds -= 1;
+    timer->fraction = MAD_TIMER_RESOLUTION - timer->fraction;
+  }
+}
+
+/*
+ * NAME:	timer->abs()
+ * DESCRIPTION:	return the absolute value of a timer
+ */
+mad_timer_t mad_timer_abs(mad_timer_t timer)
+{
+  if (timer.seconds < 0)
+    mad_timer_negate(&timer);
+
+  return timer;
+}
+
+/*
+ * NAME:	reduce_timer()
+ * DESCRIPTION:	carry timer fraction into seconds
+ */
+static
+void reduce_timer(mad_timer_t *timer)
+{
+  timer->seconds  += timer->fraction / MAD_TIMER_RESOLUTION;
+  timer->fraction %= MAD_TIMER_RESOLUTION;
+}
+
+/*
+ * NAME:	gcd()
+ * DESCRIPTION:	compute greatest common denominator
+ */
+static
+unsigned long gcd(unsigned long num1, unsigned long num2)
+{
+  unsigned long tmp;
+
+  while (num2) {
+    tmp  = num2;
+    num2 = num1 % num2;
+    num1 = tmp;
+  }
+
+  return num1;
+}
+
+/*
+ * NAME:	reduce_rational()
+ * DESCRIPTION:	convert rational expression to lowest terms
+ */
+static
+void reduce_rational(unsigned long *numer, unsigned long *denom)
+{
+  unsigned long factor;
+
+  factor = gcd(*numer, *denom);
+
+  assert(factor != 0);
+
+  *numer /= factor;
+  *denom /= factor;
+}
+
+/*
+ * NAME:	scale_rational()
+ * DESCRIPTION:	solve numer/denom == ?/scale avoiding overflowing
+ */
+static
+unsigned long scale_rational(unsigned long numer, unsigned long denom,
+			     unsigned long scale)
+{
+  reduce_rational(&numer, &denom);
+  reduce_rational(&scale, &denom);
+
+  assert(denom != 0);
+
+  if (denom < scale)
+    return numer * (scale / denom) + numer * (scale % denom) / denom;
+  if (denom < numer)
+    return scale * (numer / denom) + scale * (numer % denom) / denom;
+
+  return numer * scale / denom;
+}
+
+/*
+ * NAME:	timer->set()
+ * DESCRIPTION:	set timer to specific (positive) value
+ */
+void mad_timer_set(mad_timer_t *timer, unsigned long seconds,
+		   unsigned long numer, unsigned long denom)
+{
+  timer->seconds = seconds;
+  if (numer >= denom && denom > 0) {
+    timer->seconds += numer / denom;
+    numer %= denom;
+  }
+
+  switch (denom) {
+  case 0:
+  case 1:
+    timer->fraction = 0;
+    break;
+
+  case MAD_TIMER_RESOLUTION:
+    timer->fraction = numer;
+    break;
+
+  case 1000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION /  1000);
+    break;
+
+  case 8000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION /  8000);
+    break;
+
+  case 11025:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 11025);
+    break;
+
+  case 12000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 12000);
+    break;
+
+  case 16000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 16000);
+    break;
+
+  case 22050:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 22050);
+    break;
+
+  case 24000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 24000);
+    break;
+
+  case 32000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 32000);
+    break;
+
+  case 44100:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 44100);
+    break;
+
+  case 48000:
+    timer->fraction = numer * (MAD_TIMER_RESOLUTION / 48000);
+    break;
+
+  default:
+    timer->fraction = scale_rational(numer, denom, MAD_TIMER_RESOLUTION);
+    break;
+  }
+
+  if (timer->fraction >= MAD_TIMER_RESOLUTION)
+    reduce_timer(timer);
+}
+
+/*
+ * NAME:	timer->add()
+ * DESCRIPTION:	add one timer to another
+ */
+void mad_timer_add(mad_timer_t *timer, mad_timer_t incr)
+{
+  timer->seconds  += incr.seconds;
+  timer->fraction += incr.fraction;
+
+  if (timer->fraction >= MAD_TIMER_RESOLUTION)
+    reduce_timer(timer);
+}
+
+/*
+ * NAME:	timer->multiply()
+ * DESCRIPTION:	multiply a timer by a scalar value
+ */
+void mad_timer_multiply(mad_timer_t *timer, signed long scalar)
+{
+  mad_timer_t addend;
+  unsigned long factor;
+
+  factor = scalar;
+  if (scalar < 0) {
+    factor = -scalar;
+    mad_timer_negate(timer);
+  }
+
+  addend = *timer;
+  *timer = mad_timer_zero;
+
+  while (factor) {
+    if (factor & 1)
+      mad_timer_add(timer, addend);
+
+    mad_timer_add(&addend, addend);
+    factor >>= 1;
+  }
+}
+
+/*
+ * NAME:	timer->count()
+ * DESCRIPTION:	return timer value in selected units
+ */
+signed long mad_timer_count(mad_timer_t timer, enum mad_units units)
+{
+  switch (units) {
+  case MAD_UNITS_HOURS:
+    return timer.seconds / 60 / 60;
+
+  case MAD_UNITS_MINUTES:
+    return timer.seconds / 60;
+
+  case MAD_UNITS_SECONDS:
+    return timer.seconds;
+
+  case MAD_UNITS_DECISECONDS:
+  case MAD_UNITS_CENTISECONDS:
+  case MAD_UNITS_MILLISECONDS:
+
+  case MAD_UNITS_8000_HZ:
+  case MAD_UNITS_11025_HZ:
+  case MAD_UNITS_12000_HZ:
+  case MAD_UNITS_16000_HZ:
+  case MAD_UNITS_22050_HZ:
+  case MAD_UNITS_24000_HZ:
+  case MAD_UNITS_32000_HZ:
+  case MAD_UNITS_44100_HZ:
+  case MAD_UNITS_48000_HZ:
+
+  case MAD_UNITS_24_FPS:
+  case MAD_UNITS_25_FPS:
+  case MAD_UNITS_30_FPS:
+  case MAD_UNITS_48_FPS:
+  case MAD_UNITS_50_FPS:
+  case MAD_UNITS_60_FPS:
+  case MAD_UNITS_75_FPS:
+    return timer.seconds * (signed long) units +
+      (signed long) scale_rational(timer.fraction, MAD_TIMER_RESOLUTION,
+				   units);
+
+  case MAD_UNITS_23_976_FPS:
+  case MAD_UNITS_24_975_FPS:
+  case MAD_UNITS_29_97_FPS:
+  case MAD_UNITS_47_952_FPS:
+  case MAD_UNITS_49_95_FPS:
+  case MAD_UNITS_59_94_FPS:
+    return (mad_timer_count(timer, -units) + 1) * 1000 / 1001;
+  }
+
+  /* unsupported units */
+  return 0;
+}
+
+/*
+ * NAME:	timer->fraction()
+ * DESCRIPTION:	return fractional part of timer in arbitrary terms
+ */
+unsigned long mad_timer_fraction(mad_timer_t timer, unsigned long denom)
+{
+  timer = mad_timer_abs(timer);
+
+  switch (denom) {
+  case 0:
+    return timer.fraction ?
+      MAD_TIMER_RESOLUTION / timer.fraction : MAD_TIMER_RESOLUTION + 1;
+
+  case MAD_TIMER_RESOLUTION:
+    return timer.fraction;
+
+  default:
+    return scale_rational(timer.fraction, MAD_TIMER_RESOLUTION, denom);
+  }
+}
+
+/*
+ * NAME:	timer->string()
+ * DESCRIPTION:	write a string representation of a timer using a template
+ */
+void mad_timer_string(mad_timer_t timer,
+		      char *dest, char const *format, enum mad_units units,
+		      enum mad_units fracunits, unsigned long subparts)
+{
+  unsigned long hours, minutes, seconds, sub;
+  unsigned int frac;
+
+  timer = mad_timer_abs(timer);
+
+  seconds = timer.seconds;
+  frac = sub = 0;
+
+  switch (fracunits) {
+  case MAD_UNITS_HOURS:
+  case MAD_UNITS_MINUTES:
+  case MAD_UNITS_SECONDS:
+    break;
+
+  case MAD_UNITS_DECISECONDS:
+  case MAD_UNITS_CENTISECONDS:
+  case MAD_UNITS_MILLISECONDS:
+
+  case MAD_UNITS_8000_HZ:
+  case MAD_UNITS_11025_HZ:
+  case MAD_UNITS_12000_HZ:
+  case MAD_UNITS_16000_HZ:
+  case MAD_UNITS_22050_HZ:
+  case MAD_UNITS_24000_HZ:
+  case MAD_UNITS_32000_HZ:
+  case MAD_UNITS_44100_HZ:
+  case MAD_UNITS_48000_HZ:
+
+  case MAD_UNITS_24_FPS:
+  case MAD_UNITS_25_FPS:
+  case MAD_UNITS_30_FPS:
+  case MAD_UNITS_48_FPS:
+  case MAD_UNITS_50_FPS:
+  case MAD_UNITS_60_FPS:
+  case MAD_UNITS_75_FPS:
+    {
+      unsigned long denom;
+
+      denom = MAD_TIMER_RESOLUTION / fracunits;
+
+      frac = timer.fraction / denom;
+      sub  = scale_rational(timer.fraction % denom, denom, subparts);
+    }
+    break;
+
+  case MAD_UNITS_23_976_FPS:
+  case MAD_UNITS_24_975_FPS:
+  case MAD_UNITS_29_97_FPS:
+  case MAD_UNITS_47_952_FPS:
+  case MAD_UNITS_49_95_FPS:
+  case MAD_UNITS_59_94_FPS:
+    /* drop-frame encoding */
+    /* N.B. this is only well-defined for MAD_UNITS_29_97_FPS */
+    {
+      unsigned long frame, cycle, d, m;
+
+      frame = mad_timer_count(timer, fracunits);
+
+      cycle = -fracunits * 60 * 10 - (10 - 1) * 2;
+
+      d = frame / cycle;
+      m = frame % cycle;
+      frame += (10 - 1) * 2 * d;
+      if (m > 2)
+	frame += 2 * ((m - 2) / (cycle / 10));
+
+      frac    = frame % -fracunits;
+      seconds = frame / -fracunits;
+    }
+    break;
+  }
+
+  switch (units) {
+  case MAD_UNITS_HOURS:
+    minutes = seconds / 60;
+    hours   = minutes / 60;
+
+    sprintf(dest, format,
+	    hours,
+	    (unsigned int) (minutes % 60),
+	    (unsigned int) (seconds % 60),
+	    frac, sub);
+    break;
+
+  case MAD_UNITS_MINUTES:
+    minutes = seconds / 60;
+
+    sprintf(dest, format,
+	    minutes,
+	    (unsigned int) (seconds % 60),
+	    frac, sub);
+    break;
+
+  case MAD_UNITS_SECONDS:
+    sprintf(dest, format,
+	    seconds,
+	    frac, sub);
+    break;
+
+  case MAD_UNITS_23_976_FPS:
+  case MAD_UNITS_24_975_FPS:
+  case MAD_UNITS_29_97_FPS:
+  case MAD_UNITS_47_952_FPS:
+  case MAD_UNITS_49_95_FPS:
+  case MAD_UNITS_59_94_FPS:
+    if (fracunits < 0) {
+      /* not yet implemented */
+      sub = 0;
+    }
+
+    /* fall through */
+
+  case MAD_UNITS_DECISECONDS:
+  case MAD_UNITS_CENTISECONDS:
+  case MAD_UNITS_MILLISECONDS:
+
+  case MAD_UNITS_8000_HZ:
+  case MAD_UNITS_11025_HZ:
+  case MAD_UNITS_12000_HZ:
+  case MAD_UNITS_16000_HZ:
+  case MAD_UNITS_22050_HZ:
+  case MAD_UNITS_24000_HZ:
+  case MAD_UNITS_32000_HZ:
+  case MAD_UNITS_44100_HZ:
+  case MAD_UNITS_48000_HZ:
+
+  case MAD_UNITS_24_FPS:
+  case MAD_UNITS_25_FPS:
+  case MAD_UNITS_30_FPS:
+  case MAD_UNITS_48_FPS:
+  case MAD_UNITS_50_FPS:
+  case MAD_UNITS_60_FPS:
+  case MAD_UNITS_75_FPS:
+    sprintf(dest, format, mad_timer_count(timer, units), sub);
+    break;
+  }
+}

+ 100 - 0
libmad/timer.h

@@ -0,0 +1,100 @@
+/*
+ * libmad - MPEG audio decoder library
+ * Copyright (C) 2000-2004 Underbit Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp $
+ */
+
+# ifndef LIBMAD_TIMER_H
+# define LIBMAD_TIMER_H
+
+typedef struct {
+  signed long seconds;		/* whole seconds */
+  unsigned long fraction;	/* 1/MAD_TIMER_RESOLUTION seconds */
+} mad_timer_t;
+
+extern mad_timer_t const mad_timer_zero;
+
+# define MAD_TIMER_RESOLUTION	352800000UL
+
+enum mad_units {
+  MAD_UNITS_HOURS	 =    -2,
+  MAD_UNITS_MINUTES	 =    -1,
+  MAD_UNITS_SECONDS	 =     0,
+
+  /* metric units */
+
+  MAD_UNITS_DECISECONDS	 =    10,
+  MAD_UNITS_CENTISECONDS =   100,
+  MAD_UNITS_MILLISECONDS =  1000,
+
+  /* audio sample units */
+
+  MAD_UNITS_8000_HZ	 =  8000,
+  MAD_UNITS_11025_HZ	 = 11025,
+  MAD_UNITS_12000_HZ	 = 12000,
+
+  MAD_UNITS_16000_HZ	 = 16000,
+  MAD_UNITS_22050_HZ	 = 22050,
+  MAD_UNITS_24000_HZ	 = 24000,
+
+  MAD_UNITS_32000_HZ	 = 32000,
+  MAD_UNITS_44100_HZ	 = 44100,
+  MAD_UNITS_48000_HZ	 = 48000,
+
+  /* video frame/field units */
+
+  MAD_UNITS_24_FPS	 =    24,
+  MAD_UNITS_25_FPS	 =    25,
+  MAD_UNITS_30_FPS	 =    30,
+  MAD_UNITS_48_FPS	 =    48,
+  MAD_UNITS_50_FPS	 =    50,
+  MAD_UNITS_60_FPS	 =    60,
+
+  /* CD audio frames */
+
+  MAD_UNITS_75_FPS	 =    75,
+
+  /* video drop-frame units */
+
+  MAD_UNITS_23_976_FPS	 =   -24,
+  MAD_UNITS_24_975_FPS	 =   -25,
+  MAD_UNITS_29_97_FPS	 =   -30,
+  MAD_UNITS_47_952_FPS	 =   -48,
+  MAD_UNITS_49_95_FPS	 =   -50,
+  MAD_UNITS_59_94_FPS	 =   -60
+};
+
+# define mad_timer_reset(timer)	((void) (*(timer) = mad_timer_zero))
+
+int mad_timer_compare(mad_timer_t, mad_timer_t);
+
+# define mad_timer_sign(timer)	mad_timer_compare((timer), mad_timer_zero)
+
+void mad_timer_negate(mad_timer_t *);
+mad_timer_t mad_timer_abs(mad_timer_t);
+
+void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long);
+void mad_timer_add(mad_timer_t *, mad_timer_t);
+void mad_timer_multiply(mad_timer_t *, signed long);
+
+signed long mad_timer_count(mad_timer_t, enum mad_units);
+unsigned long mad_timer_fraction(mad_timer_t, unsigned long);
+void mad_timer_string(mad_timer_t, char *, char const *,
+		      enum mad_units, enum mad_units, unsigned long);
+
+# endif

+ 40 - 0
native_midi/native_midi.h

@@ -0,0 +1,40 @@
+/*
+    native_midi:  Hardware Midi support for the SDL_mixer library
+    Copyright (C) 2000  Florian 'Proff' Schulze
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Florian 'Proff' Schulze
+    florian.proff.schulze@gmx.net
+*/
+
+#ifndef _NATIVE_MIDI_H_
+#define _NATIVE_MIDI_H_
+
+#include <SDL_rwops.h>
+
+typedef struct _NativeMidiSong NativeMidiSong;
+
+int native_midi_detect();
+NativeMidiSong *native_midi_loadsong(const char *midifile);
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw);
+void native_midi_freesong(NativeMidiSong *song);
+void native_midi_start(NativeMidiSong *song);
+void native_midi_stop();
+int native_midi_active();
+void native_midi_setvolume(int volume);
+const char *native_midi_error(void);
+
+#endif /* _NATIVE_MIDI_H_ */

+ 409 - 0
native_midi/native_midi_common.c

@@ -0,0 +1,409 @@
+/*
+    native_midi:  Hardware Midi support for the SDL_mixer library
+    Copyright (C) 2000,2001  Florian 'Proff' Schulze
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Florian 'Proff' Schulze
+    florian.proff.schulze@gmx.net
+*/
+
+
+#include "native_midi_common.h"
+
+#include "SDL.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+
+/* The maximum number of midi tracks that we can handle 
+#define MIDI_TRACKS 32 */
+
+
+/* A single midi track as read from the midi file */
+typedef struct
+{
+	Uint8 *data;					/* MIDI message stream */
+	int len;						/* length of the track data */
+} MIDITrack;
+
+/* A midi file, stripped down to the absolute minimum - divison & track data */
+typedef struct
+{
+	int division;					/* number of pulses per quarter note (ppqn) */
+    int nTracks;                    /* number of tracks */
+	MIDITrack *track;               /* tracks */
+} MIDIFile;
+
+
+/* Some macros that help us stay endianess-independant */
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define BE_SHORT(x) (x)
+#define BE_LONG(x) (x)
+#else
+#define BE_SHORT(x)	((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define BE_LONG(x)	((((x)&0x0000FF)<<24) | \
+			 (((x)&0x00FF00)<<8) | \
+			 (((x)&0xFF0000)>>8) | \
+			 (((x)>>24)&0xFF))
+#endif
+
+
+
+/* Get Variable Length Quantity */
+static int GetVLQ(MIDITrack *track, int *currentPos)
+{
+	int l = 0;
+	Uint8 c;
+	while(1)
+	{
+		c = track->data[*currentPos];
+		(*currentPos)++;
+		l += (c & 0x7f);
+		if (!(c & 0x80)) 
+			return l;
+		l <<= 7;
+	}
+}
+
+/* Create a single MIDIEvent */
+static MIDIEvent *CreateEvent(Uint32 time, Uint8 event, Uint8 a, Uint8 b)
+{
+	MIDIEvent *newEvent;
+
+	newEvent = calloc(1, sizeof(MIDIEvent));
+	if (newEvent)
+	{
+		newEvent->time = time;
+		newEvent->status = event;
+		newEvent->data[0] = a;
+		newEvent->data[1] = b;
+	}
+	else
+		printf("Out of memory");
+
+	return newEvent;
+}
+
+/* Convert a single midi track to a list of MIDIEvents */
+static MIDIEvent *MIDITracktoStream(MIDITrack *track)
+{
+	Uint32 atime = 0;
+	Uint32 len = 0;
+	Uint8 event,type,a,b;
+	Uint8 laststatus = 0;
+	Uint8 lastchan = 0;
+	int currentPos = 0;
+	int end = 0;
+	MIDIEvent *head = CreateEvent(0,0,0,0);	/* dummy event to make handling the list easier */
+	MIDIEvent *currentEvent = head;
+
+	while (!end)
+	{
+		if (currentPos >= track->len)
+			break; /* End of data stream reached */
+
+		atime += GetVLQ(track, &currentPos);
+		event = track->data[currentPos++];
+		
+		/* Handle SysEx seperatly */
+		if (((event>>4) & 0x0F) == MIDI_STATUS_SYSEX)
+		{
+			if (event == 0xFF)
+			{
+				type = track->data[currentPos];
+				currentPos++;
+				switch(type)
+				{
+					case 0x2f: /* End of data marker */
+						end = 1;
+					case 0x51: /* Tempo change */
+						/*
+						a=track->data[currentPos];
+						b=track->data[currentPos+1];
+						c=track->data[currentPos+2];
+						AddEvent(song, atime, MEVT_TEMPO, c, b, a);
+						*/
+						break;
+				}
+			}
+			else
+				type = 0;
+
+			len = GetVLQ(track, &currentPos);
+			
+			/* Create an event and attach the extra data, if any */
+			currentEvent->next = CreateEvent(atime, event, type, 0);
+			currentEvent = currentEvent->next;
+			if (NULL == currentEvent)
+			{
+				FreeMIDIEventList(head);
+				return NULL;
+			}
+			if (len)
+			{
+				currentEvent->extraLen = len;
+				currentEvent->extraData = malloc(len);
+				memcpy(currentEvent->extraData, &(track->data[currentPos]), len);
+				currentPos += len;
+			}
+		}
+		else
+		{
+			a = event;
+			if (a & 0x80) /* It's a status byte */
+			{
+				/* Extract channel and status information */
+				lastchan = a & 0x0F;
+				laststatus = (a>>4) & 0x0F;
+				
+				/* Read the next byte which should always be a data byte */
+				a = track->data[currentPos++] & 0x7F;
+			}
+			switch(laststatus)
+			{
+				case MIDI_STATUS_NOTE_OFF:
+				case MIDI_STATUS_NOTE_ON: /* Note on */
+				case MIDI_STATUS_AFTERTOUCH: /* Key Pressure */
+				case MIDI_STATUS_CONTROLLER: /* Control change */
+				case MIDI_STATUS_PITCH_WHEEL: /* Pitch wheel */
+					b = track->data[currentPos++] & 0x7F;
+					currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, b);
+					currentEvent = currentEvent->next;
+					if (NULL == currentEvent)
+					{
+						FreeMIDIEventList(head);
+						return NULL;
+					}
+					break;
+
+				case MIDI_STATUS_PROG_CHANGE: /* Program change */
+				case MIDI_STATUS_PRESSURE: /* Channel pressure */
+					a &= 0x7f;
+					currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, 0);
+					currentEvent = currentEvent->next;
+					if (NULL == currentEvent)
+					{
+						FreeMIDIEventList(head);
+						return NULL;
+					}
+					break;
+
+				default: /* Sysex already handled above */
+					break;
+			}
+		}
+	}
+	
+	currentEvent = head->next;
+	free(head);	/* release the dummy head event */
+	return currentEvent;
+}
+
+/*
+ *  Convert a midi song, consisting of up to 32 tracks, to a list of MIDIEvents.
+ *  To do so, first convert the tracks seperatly, then interweave the resulting
+ *  MIDIEvent-Lists to one big list.
+ */
+static MIDIEvent *MIDItoStream(MIDIFile *mididata)
+{
+	MIDIEvent **track;
+	MIDIEvent *head = CreateEvent(0,0,0,0);	/* dummy event to make handling the list easier */
+	MIDIEvent *currentEvent = head;
+	int trackID;
+
+    if (NULL == head)
+		return NULL;
+        
+    track = (MIDIEvent**) calloc(1, sizeof(MIDIEvent*) * mididata->nTracks);
+	if (NULL == head)
+        return NULL;
+	
+	/* First, convert all tracks to MIDIEvent lists */
+	for (trackID = 0; trackID < mididata->nTracks; trackID++)
+		track[trackID] = MIDITracktoStream(&mididata->track[trackID]);
+
+	/* Now, merge the lists. */
+	/* TODO */
+	while(1)
+	{
+		Uint32 lowestTime = INT_MAX;
+		int currentTrackID = -1;
+		
+		/* Find the next event */
+		for (trackID = 0; trackID < mididata->nTracks; trackID++)
+		{
+			if (track[trackID] && (track[trackID]->time < lowestTime))
+			{
+				currentTrackID = trackID;
+				lowestTime = track[currentTrackID]->time;
+			}
+		}
+		
+		/* Check if we processes all events */
+		if (currentTrackID == -1)
+			break;
+		
+		currentEvent->next = track[currentTrackID];
+		track[currentTrackID] = track[currentTrackID]->next;
+
+		currentEvent = currentEvent->next;
+		
+		
+		lowestTime = 0;
+	}
+
+	/* Make sure the list is properly terminated */
+	currentEvent->next = 0;
+
+	currentEvent = head->next;
+    free(track);
+	free(head);	/* release the dummy head event */
+	return currentEvent;
+}
+
+static int ReadMIDIFile(MIDIFile *mididata, SDL_RWops *rw)
+{
+	int i = 0;
+	Uint32	ID;
+	Uint32	size;
+	Uint16	format;
+	Uint16	tracks;
+	Uint16	division;
+
+	if (!mididata)
+		return 0;
+	if (!rw)
+		return 0;
+
+	/* Make sure this is really a MIDI file */
+	SDL_RWread(rw, &ID, 1, 4);
+	if (BE_LONG(ID) != 'MThd')
+		return 0;
+	
+	/* Header size must be 6 */
+	SDL_RWread(rw, &size, 1, 4);
+	size = BE_LONG(size);
+	if (size != 6)
+		return 0;
+	
+	/* We only support format 0 and 1, but not 2 */
+	SDL_RWread(rw, &format, 1, 2);
+	format = BE_SHORT(format);
+	if (format != 0 && format != 1)
+		return 0;
+	
+	SDL_RWread(rw, &tracks, 1, 2);
+	tracks = BE_SHORT(tracks);
+	mididata->nTracks = tracks;
+    
+    /* Allocate tracks */
+    mididata->track = (MIDITrack*) calloc(1, sizeof(MIDITrack) * mididata->nTracks);
+    if (NULL == mididata->track)
+    {
+        printf("Out of memory");
+        goto bail;
+    }
+    
+	/* Retrieve the PPQN value, needed for playback */
+	SDL_RWread(rw, &division, 1, 2);
+	mididata->division = BE_SHORT(division);
+	
+	
+	for (i=0; i<tracks; i++)
+	{
+		SDL_RWread(rw, &ID, 1, 4);	/* We might want to verify this is MTrk... */
+		SDL_RWread(rw, &size, 1, 4);
+		size = BE_LONG(size);
+		mididata->track[i].len = size;
+		mididata->track[i].data = malloc(size);
+		if (NULL == mididata->track[i].data)
+		{
+			printf("Out of memory");
+			goto bail;
+		}
+		SDL_RWread(rw, mididata->track[i].data, 1, size);
+	}
+	return 1;
+
+bail:
+	for(;i >= 0; i--)
+	{
+		if (mididata->track[i].data)
+			free(mididata->track[i].data);
+	}
+
+	return 0;
+}
+
+MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division)
+{
+	MIDIFile *mididata = NULL;
+	MIDIEvent *eventList;
+	int trackID;
+	
+	mididata = calloc(1, sizeof(MIDIFile));
+	if (!mididata)
+		return NULL;
+
+	/* Open the file */
+	if ( rw != NULL )
+	{
+		/* Read in the data */
+		if ( ! ReadMIDIFile(mididata, rw))
+		{
+			free(mididata);
+			return NULL;
+		}
+	}
+	else
+	{
+		free(mididata);
+		return NULL;
+	}
+	
+	if (division)
+		*division = mididata->division;
+	
+	eventList = MIDItoStream(mididata);
+	
+	for(trackID = 0; trackID < mididata->nTracks; trackID++)
+	{
+		if (mididata->track[trackID].data)
+			free(mididata->track[trackID].data);
+	}
+	free(mididata->track);
+    free(mididata);
+	
+	return eventList;
+}
+
+void FreeMIDIEventList(MIDIEvent *head)
+{
+	MIDIEvent *cur, *next;
+	
+	cur = head;
+
+	while (cur)
+	{
+		next = cur->next;
+		if (cur->extraData) 
+			free (cur->extraData);
+		free (cur);
+		cur = next;
+	}
+}

+ 67 - 0
native_midi/native_midi_common.h

@@ -0,0 +1,67 @@
+/*
+    native_midi:  Hardware Midi support for the SDL_mixer library
+    Copyright (C) 2000,2001  Florian 'Proff' Schulze & Max Horn
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Florian 'Proff' Schulze
+    florian.proff.schulze@gmx.net
+
+    Max Horn
+    max@quendi.de
+*/
+
+#ifndef _NATIVE_MIDI_COMMON_H_
+#define _NATIVE_MIDI_COMMON_H_
+
+#include "SDL.h"
+
+/* Midi Status Bytes */
+#define MIDI_STATUS_NOTE_OFF	0x8
+#define MIDI_STATUS_NOTE_ON	0x9
+#define MIDI_STATUS_AFTERTOUCH	0xA
+#define MIDI_STATUS_CONTROLLER	0xB
+#define MIDI_STATUS_PROG_CHANGE	0xC
+#define MIDI_STATUS_PRESSURE	0xD
+#define MIDI_STATUS_PITCH_WHEEL	0xE
+#define MIDI_STATUS_SYSEX	0xF
+
+/* We store the midi events in a linked list; this way it is
+   easy to shuffle the tracks together later on; and we are
+   flexible in the size of each elemnt.
+ */
+typedef struct MIDIEvent
+{
+	Uint32	time;		/* Time at which this midi events occurs */
+	Uint8	status;		/* Status byte */
+	Uint8	data[2];	/* 1 or 2 bytes additional data for most events */
+
+	Uint32	extraLen;	/* For some SysEx events, we need additional storage */
+	Uint8	*extraData;
+	
+	struct MIDIEvent *next;
+} MIDIEvent;
+
+
+/* Load a midifile to memory, converting it to a list of MIDIEvents.
+   This function returns a linked lists of MIDIEvents, 0 if an error occured.
+ */ 
+MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division);
+
+/* Release a MIDIEvent list after usage. */
+void FreeMIDIEventList(MIDIEvent *head);
+
+
+#endif /* _NATIVE_MIDI_COMMON_H_ */

+ 312 - 0
native_midi/native_midi_macosx.c

@@ -0,0 +1,312 @@
+/*
+    native_midi_macosx:  Native Midi support on Mac OS X for the SDL_mixer library
+    Copyright (C) 2009  Ryan C. Gordon
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Ryan C. Gordon
+    icculus@icculus.org
+*/
+
+/* This is Mac OS X only, using Core MIDI.
+   Mac OS 9 support via QuickTime is in native_midi_mac.c */
+
+#include "SDL_config.h"
+
+#include <Carbon/Carbon.h>
+#include <AudioToolbox/AudioToolbox.h>
+#include <AvailabilityMacros.h>
+
+#include "SDL.h"
+#include "SDL_endian.h"
+#include "native_midi.h"
+
+/* Native Midi song */
+struct _NativeMidiSong
+{
+    MusicPlayer player;
+    MusicSequence sequence;
+    MusicTimeStamp endTime;
+    AudioUnit audiounit;
+};
+
+static NativeMidiSong *currentsong = NULL;
+static int latched_volume = 128;
+
+static OSStatus
+GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
+{
+    // http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
+    // figure out sequence length
+    UInt32 ntracks, i;
+    MusicTimeStamp sequenceLength = 0;
+    OSStatus err;
+
+    err = MusicSequenceGetTrackCount(sequence, &ntracks);
+    if (err != noErr)
+        return err;
+
+    for (i = 0; i < ntracks; ++i)
+    {
+        MusicTrack track;
+        MusicTimeStamp tracklen = 0;
+        UInt32 tracklenlen = sizeof (tracklen);
+
+        err = MusicSequenceGetIndTrack(sequence, i, &track);
+        if (err != noErr)
+            return err;
+
+        err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
+                                    &tracklen, &tracklenlen);
+        if (err != noErr)
+            return err;
+
+        if (sequenceLength < tracklen)
+            sequenceLength = tracklen;
+    }
+
+    *_sequenceLength = sequenceLength;
+
+    return noErr;
+}
+
+
+/* we're looking for the sequence output audiounit. */
+static OSStatus
+GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit)
+{
+    AUGraph graph;
+    UInt32 nodecount, i;
+    OSStatus err;
+
+    err = MusicSequenceGetAUGraph(sequence, &graph);
+    if (err != noErr)
+        return err;
+
+    err = AUGraphGetNodeCount(graph, &nodecount);
+    if (err != noErr)
+        return err;
+
+    for (i = 0; i < nodecount; i++) {
+        AUNode node;
+
+        if (AUGraphGetIndNode(graph, i, &node) != noErr)
+            continue;  /* better luck next time. */
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* this is deprecated, but works back to 10.0 */
+        {
+            struct ComponentDescription desc;
+            UInt32 classdatasize = 0;
+            void *classdata = NULL;
+            err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize,
+                                     &classdata, aunit);
+            if (err != noErr)
+                continue;
+            else if (desc.componentType != kAudioUnitType_Output)
+                continue;
+            else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
+                continue;
+        }
+        #else  /* not deprecated, but requires 10.5 or later */
+        {
+            AudioComponentDescription desc;
+            if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr)
+                continue;
+            else if (desc.componentType != kAudioUnitType_Output)
+                continue;
+            else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
+                continue;
+        }
+        #endif
+
+        return noErr;  /* found it! */
+    }
+
+    return kAUGraphErr_NodeNotFound;
+}
+
+
+int native_midi_detect()
+{
+    return 1;  /* always available. */
+}
+
+NativeMidiSong *native_midi_loadsong(const char *midifile)
+{
+    NativeMidiSong *retval = NULL;
+    SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
+    if (rw != NULL) {
+        retval = native_midi_loadsong_RW(rw);
+        SDL_RWclose(rw);
+    }
+
+    return retval;
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
+{
+    NativeMidiSong *retval = NULL;
+    void *buf = NULL;
+    int len = 0;
+    CFDataRef data = NULL;
+
+    if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
+        goto fail;
+    len = SDL_RWtell(rw);
+    if (len < 0)
+        goto fail;
+    if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
+        goto fail;
+
+    buf = malloc(len);
+    if (buf == NULL)
+        goto fail;
+
+    if (SDL_RWread(rw, buf, len, 1) != 1)
+        goto fail;
+
+    retval = malloc(sizeof(NativeMidiSong));
+    if (retval == NULL)
+        goto fail;
+
+    memset(retval, '\0', sizeof (*retval));
+
+    if (NewMusicPlayer(&retval->player) != noErr)
+        goto fail;
+    if (NewMusicSequence(&retval->sequence) != noErr)
+        goto fail;
+
+    data = CFDataCreate(NULL, (const UInt8 *) buf, len);
+    if (data == NULL)
+        goto fail;
+
+    free(buf);
+    buf = NULL;
+
+    #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 /* this is deprecated, but works back to 10.3 */
+    if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
+        goto fail;
+    #else  /* not deprecated, but requires 10.5 or later */
+    if (MusicSequenceFileLoadData(retval->sequence, data, 0, 0) != noErr)
+        goto fail;
+    #endif
+
+    CFRelease(data);
+    data = NULL;
+
+    if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
+        goto fail;
+
+    if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
+        goto fail;
+
+    return retval;
+
+fail:
+    if (retval) {
+        if (retval->sequence)
+            DisposeMusicSequence(retval->sequence);
+        if (retval->player)
+            DisposeMusicPlayer(retval->player);
+        free(retval);
+    }
+
+    if (data)
+        CFRelease(data);
+
+    if (buf)
+        free(buf);
+
+    return NULL;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+    if (song != NULL) {
+        if (currentsong == song)
+            currentsong = NULL;
+        MusicPlayerStop(song->player);
+        DisposeMusicSequence(song->sequence);
+        DisposeMusicPlayer(song->player);
+        free(song);
+    }
+}
+
+void native_midi_start(NativeMidiSong *song)
+{
+    int vol;
+
+    if (song == NULL)
+        return;
+
+    SDL_PauseAudio(1);
+    SDL_UnlockAudio();
+
+    if (currentsong)
+        MusicPlayerStop(currentsong->player);
+
+    currentsong = song;
+    MusicPlayerStart(song->player);
+
+    GetSequenceAudioUnit(song->sequence, &song->audiounit);
+
+    vol = latched_volume;
+    latched_volume++;  /* just make this not match. */
+    native_midi_setvolume(vol);
+
+    SDL_LockAudio();
+    SDL_PauseAudio(0);
+}
+
+void native_midi_stop()
+{
+    if (currentsong) {
+        SDL_PauseAudio(1);
+        SDL_UnlockAudio();
+        MusicPlayerStop(currentsong->player);
+        currentsong = NULL;
+        SDL_LockAudio();
+        SDL_PauseAudio(0);
+    }
+}
+
+int native_midi_active()
+{
+    MusicTimeStamp currentTime = 0;
+    if (currentsong == NULL)
+        return 0;
+
+    MusicPlayerGetTime(currentsong->player, &currentTime);
+    return ((currentTime < currentsong->endTime) ||
+            (currentTime >= kMusicTimeStamp_EndOfTrack));
+}
+
+void native_midi_setvolume(int volume)
+{
+    if (latched_volume == volume)
+        return;
+
+    latched_volume = volume;
+    if ((currentsong) && (currentsong->audiounit)) {
+        const float floatvol = ((float) volume) / ((float) 128);
+        AudioUnitSetParameter(currentsong->audiounit, kHALOutputParam_Volume,
+                              kAudioUnitScope_Global, 0, floatvol, 0);
+    }
+}
+
+const char *native_midi_error(void)
+{
+    return "";  /* !!! FIXME */
+}

+ 317 - 0
native_midi/native_midi_win32.c

@@ -0,0 +1,317 @@
+/*
+    native_midi:  Hardware Midi support for the SDL_mixer library
+    Copyright (C) 2000,2001  Florian 'Proff' Schulze
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Florian 'Proff' Schulze
+    florian.proff.schulze@gmx.net
+*/
+
+#include "SDL.h"
+
+/* everything below is currently one very big bad hack ;) Proff */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <windowsx.h>
+#include <mmsystem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "native_midi.h"
+#include "native_midi_common.h"
+
+struct _NativeMidiSong {
+  int MusicLoaded;
+  int MusicPlaying;
+  MIDIHDR MidiStreamHdr;
+  MIDIEVENT *NewEvents;
+	Uint16 ppqn;
+  int Size;
+  int NewPos;
+};
+
+static UINT MidiDevice=MIDI_MAPPER;
+static HMIDISTRM hMidiStream;
+static NativeMidiSong *currentsong;
+
+static int BlockOut(NativeMidiSong *song)
+{
+  MMRESULT err;
+  int BlockSize;
+
+  if ((song->MusicLoaded) && (song->NewEvents))
+  {
+    // proff 12/8/98: Added for savety
+    midiOutUnprepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
+    if (song->NewPos>=song->Size)
+      return 0;
+    BlockSize=(song->Size-song->NewPos);
+    if (BlockSize<=0)
+      return 0;
+    if (BlockSize>36000)
+      BlockSize=36000;
+    song->MidiStreamHdr.lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
+    song->NewPos+=BlockSize;
+    song->MidiStreamHdr.dwBufferLength=BlockSize;
+    song->MidiStreamHdr.dwBytesRecorded=BlockSize;
+    song->MidiStreamHdr.dwFlags=0;
+    err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
+    if (err!=MMSYSERR_NOERROR)
+      return 0;
+    err=midiStreamOut(hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
+      return 0;
+  }
+  return 1;
+}
+
+static void MIDItoStream(NativeMidiSong *song, MIDIEvent *evntlist)
+{
+  int eventcount;
+  MIDIEvent *event;
+  MIDIEVENT *newevent;
+
+  eventcount=0;
+  event=evntlist;
+  while (event)
+  {
+    eventcount++;
+    event=event->next;
+  }
+  song->NewEvents=malloc(eventcount*3*sizeof(DWORD));
+  if (!song->NewEvents)
+    return;
+  memset(song->NewEvents,0,(eventcount*3*sizeof(DWORD)));
+
+  eventcount=0;
+  event=evntlist;
+  newevent=song->NewEvents;
+  while (event)
+  {
+		int status = (event->status&0xF0)>>4;
+		switch (status)
+		{
+		case MIDI_STATUS_NOTE_OFF:
+		case MIDI_STATUS_NOTE_ON:
+		case MIDI_STATUS_AFTERTOUCH:
+		case MIDI_STATUS_CONTROLLER:
+		case MIDI_STATUS_PROG_CHANGE:
+		case MIDI_STATUS_PRESSURE:
+		case MIDI_STATUS_PITCH_WHEEL:
+      newevent->dwDeltaTime=event->time;
+		  newevent->dwEvent=(event->status|0x80)|(event->data[0]<<8)|(event->data[1]<<16)|(MEVT_SHORTMSG<<24);
+      newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
+      eventcount++;
+			break;
+
+		case MIDI_STATUS_SYSEX:
+			if (event->status == 0xFF && event->data[0] == 0x51) /* Tempo change */
+			{
+				int tempo = (event->extraData[0] << 16) |
+					          (event->extraData[1] << 8) |
+					           event->extraData[2];
+        newevent->dwDeltaTime=event->time;
+				newevent->dwEvent=(MEVT_TEMPO<<24) | tempo;
+        newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
+        eventcount++;
+			}
+			break;
+    }
+
+    event=event->next;
+  }
+
+  song->Size=eventcount*3*sizeof(DWORD);
+
+  {
+    int time;
+    int temptime;
+
+    song->NewPos=0;
+    time=0;
+    newevent=song->NewEvents;
+    while (song->NewPos<song->Size)
+    {
+      temptime=newevent->dwDeltaTime;
+      newevent->dwDeltaTime-=time;
+      time=temptime;
+      if ((song->NewPos+12)>=song->Size)
+        newevent->dwEvent |= MEVT_F_CALLBACK;
+      newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
+      song->NewPos+=12;
+    }
+  }
+  song->NewPos=0;
+  song->MusicLoaded=1;
+}
+
+void CALLBACK MidiProc( HMIDIIN hMidi, UINT uMsg, unsigned long dwInstance,
+                        unsigned long dwParam1, unsigned long dwParam2 )
+{
+    switch( uMsg )
+    {
+    case MOM_DONE:
+      if ((currentsong->MusicLoaded) && (dwParam1 == (unsigned long)&currentsong->MidiStreamHdr))
+        BlockOut(currentsong);
+      break;
+    case MOM_POSITIONCB:
+      if ((currentsong->MusicLoaded) && (dwParam1 == (unsigned long)&currentsong->MidiStreamHdr))
+        currentsong->MusicPlaying=0;
+      break;
+    default:
+      break;
+    }
+}
+
+int native_midi_detect()
+{
+  MMRESULT merr;
+  HMIDISTRM MidiStream;
+
+  merr=midiStreamOpen(&MidiStream,&MidiDevice,(DWORD)1,(unsigned long)MidiProc,(unsigned long)0,CALLBACK_FUNCTION);
+  if (merr!=MMSYSERR_NOERROR)
+    return 0;
+  midiStreamClose(MidiStream);
+  return 1;
+}
+
+NativeMidiSong *native_midi_loadsong(const char *midifile)
+{
+	NativeMidiSong *newsong;
+	MIDIEvent		*evntlist = NULL;
+	SDL_RWops	*rw;
+
+	newsong=malloc(sizeof(NativeMidiSong));
+	if (!newsong)
+		return NULL;
+	memset(newsong,0,sizeof(NativeMidiSong));
+
+	/* Attempt to load the midi file */
+	rw = SDL_RWFromFile(midifile, "rb");
+	if (rw) {
+		evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
+		SDL_RWclose(rw);
+		if (!evntlist)
+		{
+			free(newsong);
+			return NULL;
+		}
+	}
+
+	MIDItoStream(newsong, evntlist);
+
+	FreeMIDIEventList(evntlist);
+
+	return newsong;
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
+{
+	NativeMidiSong *newsong;
+	MIDIEvent		*evntlist = NULL;
+
+	newsong=malloc(sizeof(NativeMidiSong));
+	if (!newsong)
+		return NULL;
+	memset(newsong,0,sizeof(NativeMidiSong));
+
+	/* Attempt to load the midi file */
+	evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
+	if (!evntlist)
+	{
+		free(newsong);
+		return NULL;
+	}
+
+	MIDItoStream(newsong, evntlist);
+
+	FreeMIDIEventList(evntlist);
+
+	return newsong;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+  if (hMidiStream)
+  {
+    midiStreamStop(hMidiStream);
+    midiStreamClose(hMidiStream);
+  }
+  if (song)
+  {
+    if (song->NewEvents)
+      free(song->NewEvents);
+    free(song);
+  }
+}
+
+void native_midi_start(NativeMidiSong *song)
+{
+  MMRESULT merr;
+  MIDIPROPTIMEDIV mptd;
+
+  native_midi_stop();
+  if (!hMidiStream)
+  {
+    merr=midiStreamOpen(&hMidiStream,&MidiDevice,1,(DWORD)&MidiProc,0,CALLBACK_FUNCTION);
+    if (merr!=MMSYSERR_NOERROR)
+    {
+      hMidiStream=0;
+      return;
+    }
+    //midiStreamStop(hMidiStream);
+    currentsong=song;
+    currentsong->NewPos=0;
+    currentsong->MusicPlaying=1;
+    mptd.cbStruct=sizeof(MIDIPROPTIMEDIV);
+    mptd.dwTimeDiv=currentsong->ppqn;
+    merr=midiStreamProperty(hMidiStream,(LPBYTE)&mptd,MIDIPROP_SET | MIDIPROP_TIMEDIV);
+    BlockOut(song);
+    merr=midiStreamRestart(hMidiStream);
+  }
+}
+
+void native_midi_stop()
+{
+  if (!hMidiStream)
+    return;
+  midiStreamStop(hMidiStream);
+  midiStreamClose(hMidiStream);
+  currentsong=NULL;
+  hMidiStream = 0;
+}
+
+int native_midi_active()
+{
+  return currentsong->MusicPlaying;
+}
+
+void native_midi_setvolume(int volume)
+{
+  int calcVolume;
+  if (volume > 128)
+    volume = 128;
+  if (volume < 0)
+    volume = 0;
+  calcVolume = (65535 * volume / 128);
+
+  midiOutSetVolume((HMIDIOUT)hMidiStream, MAKELONG(calcVolume , calcVolume));
+}
+
+const char *native_midi_error(void)
+{
+  return "";
+}