@@ -29,6 +29,7 @@ struct vgm_buf {
29
29
30
30
enum {
31
31
sn76489 = 0 ,
32
+ ay8910 ,
32
33
};
33
34
34
35
static int psg_mode = sn76489 ;
@@ -387,6 +388,22 @@ psg_off(void)
387
388
outp (psg1_io , 0xdf );
388
389
outp (psg1_io , 0xff );
389
390
}
391
+ } else {
392
+ outp (psg0_io + 0 , 0x08 );
393
+ outp (psg0_io + 1 , 0x00 );
394
+ outp (psg0_io + 0 , 0x09 );
395
+ outp (psg0_io + 1 , 0x00 );
396
+ outp (psg0_io + 0 , 0x0a );
397
+ outp (psg0_io + 1 , 0x00 );
398
+
399
+ if (psg1_io != 0 ) {
400
+ outp (psg1_io + 0 , 0x08 );
401
+ outp (psg1_io + 1 , 0x00 );
402
+ outp (psg1_io + 0 , 0x09 );
403
+ outp (psg1_io + 1 , 0x00 );
404
+ outp (psg1_io + 0 , 0x0a );
405
+ outp (psg1_io + 1 , 0x00 );
406
+ }
390
407
}
391
408
}
392
409
@@ -754,6 +771,315 @@ play_Tandy_sound(struct vgm_buf *v, struct vgm_header *header)
754
771
return ;
755
772
}
756
773
774
+ static void
775
+ play_AY8910_sound (struct vgm_buf * v , struct vgm_header * header )
776
+ {
777
+ bool done = false;
778
+
779
+ while (!done ) {
780
+ uint8_t command = get_uint8 (v );
781
+
782
+ switch (command ) {
783
+ case 0x30 : /* reserved one-byte command. */
784
+ case 0x31 : /* AY8910 stereo mask */
785
+ case 0x32 : /* reserved one-byte command. */
786
+ case 0x33 : /* reserved one-byte command. */
787
+ case 0x34 : /* reserved one-byte command. */
788
+ case 0x35 : /* reserved one-byte command. */
789
+ case 0x36 : /* reserved one-byte command. */
790
+ case 0x37 : /* reserved one-byte command. */
791
+ case 0x38 : /* reserved one-byte command. */
792
+ case 0x39 : /* reserved one-byte command. */
793
+ case 0x3a : /* reserved one-byte command. */
794
+ case 0x3b : /* reserved one-byte command. */
795
+ case 0x3c : /* reserved one-byte command. */
796
+ case 0x3d : /* reserved one-byte command. */
797
+ case 0x3e : /* reserved one-byte command. */
798
+ case 0x3f : /* reserved one-byte command. */
799
+ case 0x4f : /* Game Gear PSG stereo */
800
+ case 0x50 : /* SN76489 / SN76496 write */
801
+ case 0x94 : /* Stop stream */
802
+ printf ("command = 0x%02x\n" , (unsigned ) command );
803
+ skip_bytes (v , 1 );
804
+ break ;
805
+
806
+ case 0x40 : /* Mikey write */
807
+ case 0x41 : /* reserved two-byte command. */
808
+ case 0x42 : /* reserved two-byte command. */
809
+ case 0x43 : /* reserved two-byte command. */
810
+ case 0x44 : /* reserved two-byte command. */
811
+ case 0x45 : /* reserved two-byte command. */
812
+ case 0x46 : /* reserved two-byte command. */
813
+ case 0x47 : /* reserved two-byte command. */
814
+ case 0x48 : /* reserved two-byte command. */
815
+ case 0x49 : /* reserved two-byte command. */
816
+ case 0x4a : /* reserved two-byte command. */
817
+ case 0x4b : /* reserved two-byte command. */
818
+ case 0x4c : /* reserved two-byte command. */
819
+ case 0x4d : /* reserved two-byte command. */
820
+ case 0x4e : /* reserved two-byte command. */
821
+ case 0x51 : /* YM2413 write */
822
+ case 0x52 : /* YM2612 port 0 write */
823
+ case 0x53 : /* YM2612 port 1 write */
824
+ case 0x54 : /* YM2151 write */
825
+ case 0x55 : /* YM2203 write */
826
+ case 0x56 : /* YM2608 port 0 write */
827
+ case 0x57 : /* YM2608 port 1 write */
828
+ case 0x58 : /* YM2610 port 0 write */
829
+ case 0x59 : /* YM2610 port 1 write */
830
+ case 0x5a : /* YM3812 write */
831
+ case 0x5b : /* YM3526 write */
832
+ case 0x5c : /* Y8950 write */
833
+ case 0x5d : /* YMZ280B write */
834
+ case 0x5e : /* YMF262 port 0 write */
835
+ case 0x5f : /* YMF262 port 1 write */
836
+ case 0xa1 : /* YM2413 write (second chip) */
837
+ case 0xa2 : /* YM2612 port 0 write (second chip) */
838
+ case 0xa3 : /* YM2612 port 1 write (second chip) */
839
+ case 0xa4 : /* YM2151 write (second chip) */
840
+ case 0xa5 : /* YM2203 write (second chip) */
841
+ case 0xa6 : /* YM2608 port 0 write (second chip) */
842
+ case 0xa7 : /* YM2608 port 1 write (second chip) */
843
+ case 0xa8 : /* YM2610 port 0 write (second chip) */
844
+ case 0xa9 : /* YM2610 port 1 write (second chip) */
845
+ case 0xaa : /* YM3812 write (second chip) */
846
+ case 0xab : /* YM3526 write (second chip) */
847
+ case 0xac : /* Y8950 write (second chip) */
848
+ case 0xad : /* YMZ280B write (second chip) */
849
+ case 0xae : /* YMF262 port 0 write (second chip) */
850
+ case 0xaf : /* YMF262 port 1 write (second chip) */
851
+ case 0xb0 : /* RF5C68 write */
852
+ case 0xb1 : /* RF5C164 write */
853
+ case 0xb2 : /* PWM write */
854
+ case 0xb3 : /* GameBoy DMG write */
855
+ case 0xb4 : /* NES APU write */
856
+ case 0xb5 : /* MultiPCM write */
857
+ case 0xb6 : /* uPD7759 write */
858
+ case 0xb7 : /* OKIM6258 write */
859
+ case 0xb8 : /* OKIM6295 write */
860
+ case 0xb9 : /* HuC6280 write */
861
+ case 0xba : /* K053260 write */
862
+ case 0xbb : /* Pokey write */
863
+ case 0xbc : /* WonderSwan write */
864
+ case 0xbd : /* SAA1099 write */
865
+ case 0xbe : /* ES5506 write */
866
+ case 0xbf : /* GA20 write */
867
+ printf ("command = 0x%02x\n" , (unsigned ) command );
868
+ skip_bytes (v , 2 );
869
+ break ;
870
+
871
+ case 0xc0 : /* Sega PCM write */
872
+ case 0xc1 : /* RF5C68 write */
873
+ case 0xc2 : /* RF5C164 write */
874
+ case 0xc3 : /* MultiPCM write */
875
+ case 0xc4 : /* QSound write */
876
+ case 0xc5 : /* SCSP write */
877
+ case 0xc6 : /* WonderSwan write */
878
+ case 0xc7 : /* VSU write */
879
+ case 0xc8 : /* X1-010 write */
880
+ case 0xc9 : /* reserved three-byte command. */
881
+ case 0xca : /* reserved three-byte command. */
882
+ case 0xcb : /* reserved three-byte command. */
883
+ case 0xcc : /* reserved three-byte command. */
884
+ case 0xcd : /* reserved three-byte command. */
885
+ case 0xce : /* reserved three-byte command. */
886
+ case 0xcf : /* reserved three-byte command. */
887
+ case 0xd0 : /* YMF278B port write */
888
+ case 0xd1 : /* YMF271 port write */
889
+ case 0xd2 : /* SCC1 port write */
890
+ case 0xd3 : /* K054539 write */
891
+ case 0xd4 : /* C140 write */
892
+ case 0xd5 : /* ES5503 write */
893
+ case 0xd6 : /* ES5506 write */
894
+ case 0xd7 : /* reserved three-byte command. */
895
+ case 0xd8 : /* reserved three-byte command. */
896
+ case 0xd9 : /* reserved three-byte command. */
897
+ case 0xda : /* reserved three-byte command. */
898
+ case 0xdb : /* reserved three-byte command. */
899
+ case 0xdc : /* reserved three-byte command. */
900
+ case 0xdd : /* reserved three-byte command. */
901
+ case 0xde : /* reserved three-byte command. */
902
+ case 0xdf : /* reserved three-byte command. */
903
+ case 0xe1 : /* C352 write */
904
+ printf ("command = 0x%02x\n" , (unsigned ) command );
905
+ skip_bytes (v , 3 );
906
+ break ;
907
+
908
+ case 0xe0 : /* Seek to offset in PCM data bank. */
909
+ case 0xe2 : /* reserved four-byte command. */
910
+ case 0xe3 : /* reserved four-byte command. */
911
+ case 0xe4 : /* reserved four-byte command. */
912
+ case 0xe5 : /* reserved four-byte command. */
913
+ case 0xe6 : /* reserved four-byte command. */
914
+ case 0xe7 : /* reserved four-byte command. */
915
+ case 0xe8 : /* reserved four-byte command. */
916
+ case 0xe9 : /* reserved four-byte command. */
917
+ case 0xea : /* reserved four-byte command. */
918
+ case 0xeb : /* reserved four-byte command. */
919
+ case 0xec : /* reserved four-byte command. */
920
+ case 0xed : /* reserved four-byte command. */
921
+ case 0xee : /* reserved four-byte command. */
922
+ case 0xef : /* reserved four-byte command. */
923
+ case 0xf0 : /* reserved four-byte command. */
924
+ case 0xf1 : /* reserved four-byte command. */
925
+ case 0xf2 : /* reserved four-byte command. */
926
+ case 0xf3 : /* reserved four-byte command. */
927
+ case 0xf4 : /* reserved four-byte command. */
928
+ case 0xf5 : /* reserved four-byte command. */
929
+ case 0xf6 : /* reserved four-byte command. */
930
+ case 0xf7 : /* reserved four-byte command. */
931
+ case 0xf8 : /* reserved four-byte command. */
932
+ case 0xf9 : /* reserved four-byte command. */
933
+ case 0xfa : /* reserved four-byte command. */
934
+ case 0xfb : /* reserved four-byte command. */
935
+ case 0xfc : /* reserved four-byte command. */
936
+ case 0xfd : /* reserved four-byte command. */
937
+ case 0xfe : /* reserved four-byte command. */
938
+ case 0xff : /* reserved four-byte command. */
939
+ case 0x90 : /* Setup stream control */
940
+ case 0x91 : /* Set stream data */
941
+ case 0x95 : /* Start stream (fast call) */
942
+ printf ("command = 0x%02x\n" , (unsigned ) command );
943
+ skip_bytes (v , 4 );
944
+ break ;
945
+
946
+ case 0x92 : /* Set stream frequency */
947
+ printf ("command = 0x%02x\n" , (unsigned ) command );
948
+ skip_bytes (v , 5 );
949
+ break ;
950
+
951
+ case 0x93 : /* Start stream */
952
+ printf ("command = 0x%02x\n" , (unsigned ) command );
953
+ skip_bytes (v , 10 );
954
+ break ;
955
+
956
+ case 0x61 :
957
+ /* Wait n samples. n is 16-bit value. */
958
+ wait_44khz (get_uint16 (v ));
959
+ break ;
960
+
961
+ case 0x62 :
962
+ /* Wait 735 samples */
963
+ wait_44khz (735 );
964
+ break ;
965
+
966
+ case 0x63 :
967
+ /* Wait 882 samples */
968
+ wait_44khz (882 );
969
+ break ;
970
+
971
+ case 0x66 :
972
+ /* End of sound data. */
973
+ done = true;
974
+ break ;
975
+
976
+ case 0x67 : {
977
+ /* Data block. */
978
+ printf ("command = 0x%02x\n" , (unsigned ) command );
979
+
980
+ /* Should be 0x66, followed by a byte for the data type. */
981
+ uint8_t marker = get_uint8 (v );
982
+ if (marker != 0x66 )
983
+ goto parse_error ;
984
+
985
+ skip_bytes (v , 1 );
986
+
987
+ /* The next four bytes specify how much data follows. */
988
+ skip_bytes (v , get_uint32 (v ));
989
+ break ;
990
+ }
991
+
992
+ case 0x68 : {
993
+ /* PCM RAM write. */
994
+ printf ("command = 0x%02x\n" , (unsigned ) command );
995
+
996
+ /* Should be 0x66, followed by a byte for the chip type, and 12
997
+ * bytes of offsets and sizes.
998
+ */
999
+ uint8_t marker = get_uint8 (v );
1000
+ if (marker != 0x66 )
1001
+ goto parse_error ;
1002
+
1003
+ skip_bytes (v , 13 );
1004
+ break ;
1005
+ }
1006
+
1007
+ case 0x70 :
1008
+ case 0x71 :
1009
+ case 0x72 :
1010
+ case 0x73 :
1011
+ case 0x74 :
1012
+ case 0x75 :
1013
+ case 0x76 :
1014
+ case 0x77 :
1015
+ case 0x78 :
1016
+ case 0x79 :
1017
+ case 0x7a :
1018
+ case 0x7b :
1019
+ case 0x7c :
1020
+ case 0x7d :
1021
+ case 0x7e :
1022
+ case 0x7f :
1023
+ /* Wait n+1 samples. */
1024
+ wait_44khz ((command & 0x0f ) + 1 );
1025
+ break ;
1026
+
1027
+ case 0x80 :
1028
+ case 0x81 :
1029
+ case 0x82 :
1030
+ case 0x83 :
1031
+ case 0x84 :
1032
+ case 0x85 :
1033
+ case 0x86 :
1034
+ case 0x87 :
1035
+ case 0x88 :
1036
+ case 0x89 :
1037
+ case 0x8a :
1038
+ case 0x8b :
1039
+ case 0x8c :
1040
+ case 0x8d :
1041
+ case 0x8e :
1042
+ case 0x8f :
1043
+ printf ("command = 0x%02x\n" , (unsigned ) command );
1044
+ /* YM2612 port 0 write from data pointer, then wait. */
1045
+ break ;
1046
+
1047
+ case 0xa0 : {
1048
+ /* AY8910 write */
1049
+ uint8_t v1 = get_uint8 (v );
1050
+ uint8_t v2 = get_uint8 (v );
1051
+
1052
+ /* https://vgmrips.net/wiki/VGM_Specification#Dual_Chip_Support
1053
+ * says:
1054
+ *
1055
+ * "All other chips use bit 7 (0x80) of the first parameter
1056
+ * byte to distinguish between the 1st and 2nd chip."
1057
+ */
1058
+ if (v1 & 0x80 == 0 ) {
1059
+ outp (psg0_io , v1 & 0x7f );
1060
+ outp (psg0_io + 1 , v2 );
1061
+ } else if (psg1_io != 0 ) {
1062
+ outp (psg1_io , v1 & 0x7f );
1063
+ outp (psg1_io + 1 , v2 );
1064
+ }
1065
+ break ;
1066
+ }
1067
+
1068
+ default :
1069
+ printf ("command = 0x%02x\n" , (unsigned ) command );
1070
+ goto parse_error ;
1071
+ }
1072
+ }
1073
+
1074
+ psg_off ();
1075
+ return ;
1076
+
1077
+ parse_error :
1078
+ printf ("parse error\n" );
1079
+ psg_off ();
1080
+ return ;
1081
+ }
1082
+
757
1083
static void
758
1084
show_help (const char * progname )
759
1085
{
@@ -846,6 +1172,11 @@ static const struct known_mode known_modes[] = {
846
1172
* generic 25MHz 386sx system with a PicoGUS.
847
1173
*/
848
1174
{ "tandy1000rsx" , 101 , 1079 , 0x01e0 , 0x0000 , sn76489 },
1175
+
1176
+ /* Mindscape Music Board is a dual AY-3-8913 card. The default base IO
1177
+ * addresses for the chips are 300h and 302h.
1178
+ */
1179
+ { "msmb" , 0 , 0 , 0x0300 , 0x0302 , ay8910 },
849
1180
};
850
1181
851
1182
static int
@@ -1141,7 +1472,12 @@ main(int argc, char **argv)
1141
1472
header .total_samples );
1142
1473
1143
1474
uint32_t before = get_tick ();
1144
- play_Tandy_sound (& v , & header );
1475
+
1476
+ if (psg_mode == sn76489 ) {
1477
+ play_Tandy_sound (& v , & header );
1478
+ } else {
1479
+ play_AY8910_sound (& v , & header );
1480
+ }
1145
1481
uint32_t after = get_tick ();
1146
1482
1147
1483
uint32_t elapsed_ms = 55ul * (after - before );
0 commit comments