Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Discuss NSF files, FamiTracker, MML tools, or anything else related to NES music.

Moderator: Moderators

User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Ben Boldt »

Over the 4th of July weekend, I will have access to my old Yamaha PSS-140 keyboard, which contains a YM2413 synthesizer, and most importantly, 100 selectable custom patches. These patches would theoretically be 100% compatible with the VRC7. So I started a small project to help debug and grab this data.

setup.jpg

This is a 16-bit dsPIC33FJ64GS606 microcontroller with lots of 5V-tolerant inputs. The basic idea is that it captures the data bus and A0 address bit whenever /WR and /CE are low at the same time. I have a 74LS02 NOR gate taking in /WR and /CE, then a rising edge interrupt on the output of the NOR gate. (Not sure if this keyboard might do writes to other stuff with YM2413 /CE high.) The microcontroller queues the captured data up in its RAM, and can do so quite rapidly. Over time, it pops the data out of the queue and sends over serial at 57600 baud via the blue serial-to-USB adapter.

I did some pretty dirty magic to get the external rising edge interrupt as fast as possible. The very first instruction captures everything (data and address), and this happens after 224nsec (interrupt latency). I clear the interrupt flag at the end after a total of 348nsec, which means that I can do captures at a maximum frequency of 2.87 MHz. Actually a bit slower than that because it probably has to complete exiting the interrupt before re-entering. I think that part should be fast enough but my interrupt latency might be too long, not sure. It can't be made faster unless I overclock the micro, which does screw up the UART serial output of this micro. (I tried it.)

Anyway, each capture saves 4 bytes:
  • address bit A0, plus one additional input pin reserved. This byte encodes as 0x55 or 0xAA based on the 1 bit to find the beginning of 4-byte packets easily, but can be changed to use both bits if I find another bit I need to record for some reason.
  • data bus
  • 16-bit 44.1kHz counter high byte
  • counter low byte
In theory, I can post-process this data on a PC to create a VGM file, specifically the demonstration mode of this keyboard. So those are my goals with this. #1. Get all 100 custom patches, #2 create VGM file of the demonstration mode.

Here is the source code I came up with:
main.c:

Code: Select all

/* 
 * File:   main.c
 * Author: benboldt
 */

#include "p33FJ64GS606.h"

_FBS( BSS_NO_BOOT_CODE & BWRP_WRPROTECT_OFF);
_FGS( GWRP_OFF & GSS_OFF );
_FOSCSEL( FNOSC_FRC & IESO_ON );
_FOSC( POSCMD_NONE & OSCIOFNC_ON & FCKSM_CSECMD );
_FWDT( WDTPOST_PS256 & WDTPRE_PR128 & WINDIS_OFF & FWDTEN_OFF );
_FPOR( FPWRT_PWR1 & ALTSS1_OFF & ALTQIO_OFF);
_FICD( ICS_PGD2 & JTAGEN_OFF );
_FCMP(HYST0_HYST0 & CMPPOL0_POL_RISE & HYST1_HYST0 & CMPPOL1_POL_RISE)

typedef signed char         int8_t;
typedef signed int          int16_t;
typedef signed long         int32_t;
typedef signed long long    int64_t;

typedef unsigned char       uint8_t;
typedef unsigned int        uint16_t;
typedef unsigned long       uint32_t;
typedef unsigned long long  uint64_t;

#define OUTP_CPU_DATA_BUS       LATD
#define INP_CPU_DATA_BUS        PORTD  // bits 0..7
#define INP_ADDRESS_BIT         PORTDbits.RD8
#define INP_ALL_ITEMS           PORTD

// From datasheet:
// FOSC = FIN * ( M / ( N1 * N2 ) )
#define MHZ  *(1.0e6)
#define KD_CPU_CLK_FRC      (7.37 MHZ)  // FIN: Internal FRC Nominal Frequency
#define KD_CPU_CLK_PLLFBD   43.0    // M: PLLFBD for 39.61375 MHz FJ part
//#define KD_CPU_CLK_PLLFBD   53.0    // M: PLLFBD for 48.826248 MHz Overclocked FJ part
//#define KD_CPU_CLK_PLLFBD   65.0    // M: PLLFBD for 59.88125 MHz EP part
#define KD_CPU_CLK_N1       2.0     // N1: PLLPRE
#define KD_CPU_CLK_N2       2.0     // N2: PLLPOST

// Note: 100 MHz < (FIN * M) < 200 MHz on FJ part
//       120 MHZ < (FIN * M) < 230 MHz on EP part

// Note: Change corresponding APSTSCLR bits in ACLKCON if you change the following:
#define KD_ACLK_POST        1.0     // ACLK Postscaler (for PWM timebase)

#define KD_CPU_FOSC         ( KD_CPU_CLK_FRC * ( KD_CPU_CLK_PLLFBD / (KD_CPU_CLK_N1 * KD_CPU_CLK_N2) ) )

// From datasheet:
// Instruction Clock FCY = FOSC / 2
#define KD_CPU_CLK_FREQ     (KD_CPU_FOSC / 2.0)  // 39.61375 MHz


#define KD_UART_BAUD_RATE       57600.0
#define K16_U1BRG_BRGH_0_VAL    ((KD_CPU_CLK_FREQ / (16.0 * KD_UART_BAUD_RATE)) - 1.0)
#define K16_U1BRG_BRGH_1_VAL    ((KD_CPU_CLK_FREQ / (4.0 * KD_UART_BAUD_RATE)) - 1.0)



volatile uint8_t uart_buffer[4096];  // (4096 = 2^12, 11-bit)  Mask is 0xFFF.
volatile uint16_t next_capture_index = 0;
uint16_t next_uart_tx_index = 0;
//volatile uint16_t timestamp = 0;
volatile uint16_t timestamp_enabled = 0;



int main( void )
{
    uint16_t byte_order_index;
    // ** Initialize Oscillator **
    PLLFBD = (uint16_t)(KD_CPU_CLK_PLLFBD - 2);
    CLKDIV = 0b1011000000000000 | (((uint16_t)(KD_CPU_CLK_N2 - 2)) << 6) | (uint16_t)(KD_CPU_CLK_N1 - 2);
    __builtin_write_OSCCONH(0x01);
    __builtin_write_OSCCONL(0x01);
    ACLKCON = 0b1010011101000000;
    while(OSCCONbits.COSC != 0b001);
    while(OSCCONbits.LOCK != 1);
    while(ACLKCONbits.APLLCK != 1);
    CORCON = 0b0000000011110100;
    
    // ** Initialize Hardware Timer: **
    T1CONbits.TON = 0; // Disable Timer
    T1CONbits.TCS = 0; // Select internal instruction cycle clock
    T1CONbits.TGATE = 0; // Disable Gated Timer mode
    //T1CONbits.TCKPS = 0b01; // Select 1:8 Prescaler
    T1CONbits.TCKPS = 0b00; // Select 1:1 Prescaler
    TMR1 = 0x0000; // Clear timer register
    PR1 = 901; // Load the period value.  Tuned with scope to 44.1kHz.
    IPC0bits.T1IP = 0x01; // Set Timer1 Interrupt Priority Level (lowest possible)
    IFS0bits.T1IF = 0; // Clear Timer1 Interrupt Flag
    IEC0bits.T1IE = 1; // Enable Timer1 interrupt
    T1CONbits.TON = 1; // Start Timer
    
    // ** Initialize GPIO: **
    // There is no Port A in this micro.
    TRISB = 0b0000000000000000;  // [15:0] CPU Address Bus
    TRISC = 0b0000000000000000;  // Not Used
    TRISD = 0b0000000111111111;  // [7:0] CPU Data Bus
    TRISE = 0b0000000000000000;  // Not Used
    TRISF = 0b0000000001001000;  // [6] INT0, [3] UART Tx
    TRISG = 0b0000000000000000;  // Not Used
    
    // ** Initialize External Interrupt on Port F6: **
    //INTCON2bits.INT0EP = 1;  // Falling edge trigger.
    INTCON2bits.INT0EP = 0;  // Rising edge trigger.
    IPC0bits.INT0IP = 7;  // Set interrupt priority highest possible.
    IFS0bits.INT0IF = 0;  // Clear Interrupt Flag.
    IEC0bits.INT0IE = 1;  // Enable INT0 Interrupt.
    // Note that INTCON1bits.NSTDIS = 0 by default, allowing the INT0 IRQ handler to start within the Timer1 IRQ handler.

    
    // ** Initialize UART Tx: **
    U1MODE = 0b1000100010001000;
    U1BRG = 171;//K16_U1BRG_BRGH_1_VAL;  57600 baud, fine-tuned with scope.
    U1STA = 0b0010000000000000;
    U1STAbits.UTXEN = 1;

    uint8_t sampleByte = 0x00;
    
    // Initialize registers that get used exclusively by non-C code:
    asm volatile( " MOV _next_capture_index, W12 ");  // Initialize W12.
    asm volatile( " MOV #_uart_buffer, W10 ");
    asm volatile( " MOV #_uart_buffer+2, W6 ");
    asm volatile( " MOV #0, W4 ");
    
    // Main Program Loop
    for(;;)
    {
        //LATE = 0x00;  // Debug.
//#define ENABLE_DEBUG_DATA
#if defined( ENABLE_DEBUG_DATA )
        if( 0 == U1STAbits.UTXBF )
        {
            U1TXREG = sampleByte;
            sampleByte++;
        }
#else
        asm volatile( " MOV W12, _next_capture_index ");
        if( next_uart_tx_index != next_capture_index )
        {
            while ( 0 != U1STAbits.UTXBF );  // Wait for UART Tx buffer to be ready.
            // Transmit next byte from buffer.
            byte_order_index = next_uart_tx_index ^ 1;
            if( 0b00 == (next_uart_tx_index & 0b11) )
            {
                if( 1 == (uart_buffer[byte_order_index] & 1) )
                {
                    U1TXREG = 0xAA;
                }
                else
                {
                    U1TXREG = 0x55;
                }
            }
            else
            {
                U1TXREG = uart_buffer[byte_order_index];
            }
            next_uart_tx_index = (next_uart_tx_index + 1) & 0xFFF;  // Increment index and rollover 4095 -> 0
            
            //LATEbits.LATE5 = !LATEbits.LATE5;
        }
#endif
    }
    
    return 0;
}

//void __attribute__((interrupt, no_auto_psv)) _INT0Interrupt( void )  // High Priority
//{
//    // External interrupt on rising edge of YM2413 (/CS NOR /WE).
//    
//    // Grab Data Bus and Address Bit really fast:
//    LATE = 0xFF;
//    uint16_t all_data = INP_ALL_ITEMS;
//    
//    *((uint16_t*)&(uart_buffer[next_capture_index])) = all_data;  // Record address bit and data bus.
//    *((uint16_t*)&(uart_buffer[next_capture_index + 2])) = timestamp;  // Record 44.1kHz timestamp.
//    
//    next_capture_index = (next_capture_index + 4) & 0xFFF;  // Rollover 4095 -> 0.
//    // Since bytes are added in multiples of 4, it should be fine to do it at the end like this.
//    
//    //LATEbits.LATE5 = !LATEbits.LATE5;
//    //LATE = 0xFF;
//    IFS0bits.INT0IF = 0;  // Clear INT0 Interrupt Flag.
//}

void __attribute__((interrupt, no_auto_psv)) _T1Interrupt( void )  // Low priority
{
    if( 0 != next_capture_index )  // Hold the timestamp at 0 until the first item gets logged.
    {
        timestamp_enabled = 1;
    }
    if( timestamp_enabled )
    {
        asm volatile( " INC W4, W4 ");
        //timestamp++;
    }
    //LATEbits.LATE5 = !LATEbits.LATE5;  // Debug for measuring 44.1kHz, tweaking value written to PR1.
        
    IFS0bits.T1IF = 0;  // Clear Timer1 interrupt flag.
}

irq.s, not good quality coding but definitely fast. I left parts as comments that I was able to strip out for time savings.

Code: Select all

.include "p33FJ64GS606.inc"


    .global __INT0Interrupt

; ** INT0 IRQ Handler **
__INT0Interrupt:
    ;BSET LATE, #5  ; Debug.
    MOV PORTD, W8  ; Grab Port D
    ;MOV #0x800, W10  ; W10 is untouched anywhere else, so no point reloading it.
    ;MOV _next_capture_index, W12  ; W12 is untouched anywhere else, so no point reloading it.
    MOV W8, [W10 + W12]
    ;MOV _timestamp, W8  ; Dedicate W4 to the timestamp instead of using the RAM variable.
    ;MOV #0x802, W6  ; W6 is untouched anywhere else, so no point reloading it.
    MOV W4, [W6 + W12]
    ADD W12, #4, W12
    BCLR W12, #12  ;Since rollover to zero is triggered specifically at value 0x1000, can just clear bit 12.
    ;MOV #0xFFF, W10  ; Old way of doing rollover with AND 0xFFF.
    ;AND W12, W10, W12
    
    ;MOV W12, _next_capture_index  ; This can be done in the main loop when checking.

    ;BSET LATE, #5  ; Debug.
    BCLR IFS0, #0  ; Clear INT0 interrupt flag.
    RETFIE
I will be in the middle of nowhere doing this, so hopefully I have prepared well.
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Ben Boldt »

Small update on this:

I built an additional board with 74HC273 / 74HC373 to latch the data bus in case my interrupt latency is too long. The '273 is a octal D-flip flop and the '373 is a transparent latch. These have basically the same pinout, so I used a socket and also a couple 3-pin headers that I can use to jumper 2 things:

- Clock polarity.
- Pin 1 /MR ('273) needs to be high vs. /OE ('373) needs to be low.

Monitoring what exactly is happening with the scope, hopefully this gives me enough options to capture stuff. The scope itself can capture this stuff but manually recording 800 patch data bytes (though possible) would be prone to error and I really want that working where I can manipulate data with copy/paste. Hopefully I have something in the next week or so. I started a wiki page here:

https://wiki.nesdev.com/w/index.php/Use ... 13_Patches

I have already found a number of patches from MSX VGM files. I also found what strongly appears to be a whopping 95 patches in the ROM data of Lagrange Point.

Table of pointers @ $AFF8 (=ROM $3008)
Data starting @ $B0B8 (=ROM $30C8), indicated by each pointer in the table.

I correlated all patches in the Lagrange Point VGM files to this data, leaving about half of them unused. I am not sure why they have so many unused patches in the ROM. Interestingly, patch #62 (unused) actually matches VRC7 internal patch #6. I really want to see if any of the PSS-140's patches match anywhere else as well.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by calima »

Would these be usable on Genesis too? That console was badly held back by a lack of instrument data for the FM chip.

Also, what is the legal status of such dumped instruments? Presumably being data on a chip in the keyboard, they could be copyrighted.
User avatar
TmEE
Posts: 960
Joined: Wed Feb 13, 2008 9:10 am
Location: Norway (50 and 60Hz compatible :P)
Contact:

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by TmEE »

When I was active in MD music stuff a decade ago, I remember there were bigass collections of instrument files for YM2612, extracted from VGMs with a tool which name I currently don't recall. I believe they were by Shiru, who quit the MD scene a while ago and made everything related unavailable from their end... My memory is hazy though and when I looked into my backups I didn't seem to find anything in first glance...
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by lidnariq »

calima wrote: Mon Jun 28, 2021 10:59 pm Would these be usable on Genesis too? That console was badly held back by a lack of instrument data for the FM chip.
OPL patches support different waveforms, not just sine waves. OPN chips only support sine waves (compared to the OPLL's two, OPL2's four, or OPL3's eight).

That said, I'm not convinced the different waveforms matter that much. I previously wrote something in PureData to change the choice of modulator and carrier in a 2op synth and ... it sounds different, but not that different.

As far as using 2op patches on the OPN... the answer is "sorta". OPN algorithms 4 and 5 effectively hold 2op instruments, and "sound effect mode" can let you get two entirely independent 2op instruments in one of the OPN2's six voices. Each voice can have each operator keyed on and off independently (even if no soundtracks supposedly use this functionality). The other five voices will be constrained to two notes that are related as a ratio of small integers (since there's only one fnum and oct, but per-operator mul: any interval that can be expressed as a ratio of integers 1 to 15)
Also, what is the legal status of such dumped instruments? Presumably being data on a chip in the keyboard, they could be copyrighted.
I'm personally of the opinion that they're too small to be copyrightable. (Previous discussion: viewtopic.php?p=246860#p246860 )

Also, there's already a freely-distributed set of General MIDI OPL2 patches as part of ALSA ("std.sb") and I wouldn't be surprised if a lot of the OPLL patches that have been found above correspond. I'll try to build a tool to check this in a couple days.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Bregalad »

Also, there's already a freely-distributed set of General MIDI OPL2 patches as part of ALSA ("std.sb") and I wouldn't be surprised if a lot of the OPLL patches that have been found above correspond. I'll try to build a tool to check this in a couple days.
Amazing, when I was a kid I spent a lot of time playing with MIDIs and I had a terrible-sounding OPL2 soundcart in my Compaq PC. Good old-times !

An interesting project would be to remake the Lagrange Point OST in MIDI and making it sound as close as the original when played back with the OPL2 soundtrack.
Useless, lumbering half-wits don't scare us.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by lidnariq »

I've written a tool to convert OPL2 patches ("SBI" format) into OPLL patches. This is somewhat lossy, because there are a few things missing from OPLL's custom patch.

OPLL patches are 63 bits in size (packed into 8 bytes); OPL2 patches are 72 bits in size (packed into 11 bytes). OPL2 supports: four waveforms for both carrier and modulator, instead of two (+2 bits); the ability to use the two operators in additive mode instead of FM mode (+1 bit); and a different "total level" for each of carrier and modulator (+6 bits).

Even just among ADSR parameters, there's no exact matches between the VRC7 patch set and ALSA's OPL2 parameters, and I'm really not certain how to evaluate "closeness" here.
plgDavid
Posts: 27
Joined: Tue Aug 07, 2012 11:01 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by plgDavid »

Hey

Was browsing this forum and the title of the post struct me and I remembered I did exactly that a while ago and never published the results.
Just used a Logic analyzer and custom code but legally cannot ship these patches in chipsynth PortaFM so I forgot their existence.

Also dumped the PSS140 demo song (in YM2420 format) which I need to massage (I did release the SHS10 demo in VGM format two xmas ago)
Mind you some of those sounds, including the ones in the PSS270 use CPU automation to make them more interesting; Fake echo, quick octave jumps, arps etc, but the core registers are a go.

Here are the full set of OPLL patches for the PSS140, PSS270 and SHS10:
https://github.com/plgDavid/misc/tree/m ... %20Patches

Legal warning: these are copyrighted, please only use for study.
Have fun.
plgDavid
Posts: 27
Joined: Tue Aug 07, 2012 11:01 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by plgDavid »

plgDavid wrote: Sun Jul 04, 2021 5:52 pm Legal warning: these are copyrighted, please only use for study.
Have fun.
Forgot to add. Eventually maybe those HD63XYXXX mcus will be decapped and the full synths will appear in MAME, making such ripping trivial.
For now, logging them by sniffing the data bus is the best we can get.
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Ben Boldt »

Thanks for the info plgDavid. I was able to verify each and every PSS-140 patch that you have is correct. Strangely though, I am absolutely not able to get a decent VGM file created from the demonstration mode of this keyboard. It has the correct beat but the main instrument is absent and what is left doesn’t sound quite exactly right either. I am totally confused what could be wrong. If I can capture the patch writes all matching yours, that verifies my setup pretty well, so that makes me lean more towards a problem with this hacky program I wrote to translate my data dump into VGM format. It is just so confusing though because it is saving register writes. That can’t discriminate against the lead instrument... there is nothing my setup does that could make it aware of that.

What did you use to capture the data? Do you mind sharing how you did it?


Edit:
What do you trigger on to capture the data bus? I basically take the logical OR of /CS and /WE and capture based on the falling edge of the result. I also tried the rising edge of the result with little to no difference.


Edit 2:
Added attachment. This is the faulty VGM file I am producing. I run this VGM file through my patch extractor program and it finds all good patches that match the ones that you and I have dumped plgDavid. I noticed also that the dumped data does attempt to write to some invalid registers, almost all in the 0x50's. That can be a clue; whether or not the real keyboard is doing this I do not know.
Attachments
pss-140 - problematic.vgm
(56.87 KiB) Downloaded 66 times
User avatar
nin-kuuku
Posts: 67
Joined: Tue Jan 24, 2017 1:23 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by nin-kuuku »

plgDavid wrote: Sun Jul 04, 2021 5:52 pm Hey

Was browsing this forum and the title of the post struct me and I remembered I did exactly that a while ago and never published the results.
Just used a Logic analyzer and custom code but legally cannot ship these patches in chipsynth PortaFM so I forgot their existence.

Also dumped the PSS140 demo song (in YM2420 format) which I need to massage (I did release the SHS10 demo in VGM format two xmas ago)
Mind you some of those sounds, including the ones in the PSS270 use CPU automation to make them more interesting; Fake echo, quick octave jumps, arps etc, but the core registers are a go.

Here are the full set of OPLL patches for the PSS140, PSS270 and SHS10:
https://github.com/plgDavid/misc/tree/m ... %20Patches

Legal warning: these are copyrighted, please only use for study.
Have fun.
Here's VRC7 NSF. No drums yet.
Attachments
SHS-10_ym2413_test.nsf
(226.07 KiB) Downloaded 56 times
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Ben Boldt »

I found that I am not actually receiving invalid register address writes in the 0x50’s. I was checking for this in my VGM converter, and used “if register > 38” but using decimal instead of hex. So in fact I do not have any invalid register addresses.

I tried taking out that assembly magic in my capture tool and back to using straight C code. It sounds just the same that way too. I am not dropping any bytes from the serial connection because that would show up as a shift in the data and everything does stay synchronized.

I guess it is also possible that this keyboard does something strange that isn’t emulated correctly. I am working with laptop speakers. Listening closely, the missing parts might be playing with extremely low frequency.


Edit:
Here is my VGM converter code. It is dead simple. The raw data comes in groups of 4 bytes:
  • Address (0x55) / Data (0xAA)
  • Data Bus
  • 44.1kHz timestamp (high byte)
  • 44.1kHz timestamp (low byte)

Code: Select all

        UInt16 getTimestamp( int index )
        {
            UInt16 return_val = dumped_data[index + 2];
            return_val <<= 8;
            return_val |= ((UInt16)(dumped_data[index + 3]));
            return return_val;
        }

        private void parseDumpedData()
        {
            string s = "";
            int index = 0;
            UInt16 prev_timestamp = getTimestamp(index);
            UInt16 timestamp;
            UInt16 delay;
            byte address = 0x00;
            while(index < dumped_data.Length && index < 100000)
            {
                if (0x55 == dumped_data[index])  // addess byte
                {
                    address = dumped_data[index + 1];
                    //address &= 0x3F;
                    if (address > 0x38)
                    {
                        MessageBox.Show("Invalid Address: " + address);
                    }
                }
                else  // data byte
                {
                    timestamp = getTimestamp(index);
                    delay = (UInt16)(timestamp - prev_timestamp);
                    prev_timestamp = timestamp;

                    if (delay != 0)
                    {
                        if (delay < 17)
                        {
                            s += "7" + (delay - 1).ToString("X1") + " ";
                        }
                        else
                        {
                            s += "61 " + (delay & 0xFF).ToString("X2") + " " + (delay >> 8).ToString("X2") + " ";
                        }
                    }

                    s += "51 " + address.ToString("X2") + " " + dumped_data[index + 1].ToString("X2") + " ";
                }
                index += 4;
            }
            s += "66"; // End
            textBox1.Text = s;
        }
Then I just copy/paste the output of that into a hex editor, with this header:

Code: Select all

56 67 6D 20 73 E3 00 00 51 01 00 00 00 00 00 00 
99 9E 36 00 00 00 00 00 76 F5 C4 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 4C 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Ben Boldt »

I am starting to think there must be a problem with VGMplay now. Some notes are just playing a much lower than expected frequency, and in a totally consistent way. I have a feeling there is some strange combination of frequency and octave values that that this keyboard uses that behaves different on the real chip vs. VGMplay.

It seems quite out of tune (though I can’t say that for certain). If so, it suggests an issue with frequency and not octave. Maybe the 9th frequency bit (MSB) doesn’t work right in VGMplay and is rarely used elsewhere? That could explain everything.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by lidnariq »

I haven't noticed anything unusual in hacking around with VGMplay.

Why don't you post (or PM me) one of your buggy VGMs?
User avatar
Ben Boldt
Posts: 1149
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Capturing YM2413 patches from Yamaha PSS-140 for potential use with VRC7

Post by Ben Boldt »

lidnariq wrote: Tue Jul 06, 2021 12:13 pm I haven't noticed anything unusual in hacking around with VGMplay.

Why don't you post (or PM me) one of your buggy VGMs?
If you go up a few posts, I attached a buggy VGM file. Let me know if there is anything else you would like to see.
Post Reply