PureBasic Forumhttp://forums.purebasic.com/english/ Noob's investigation of VGM and DMF and SMD audio drivershttp://forums.purebasic.com/english/viewtopic.php?f=17&t=64280 Page 4 of 8

 Author: wilbert [ Tue Sep 27, 2016 1:51 pm ] Post subject: Re: Noob's investigation of VGM I updated the function. It's called nowSetChipVolume(volume.u, chip = 0)The volume is a value between 0 and \$400 where \$400 means 4 times multiplication.That sounds like enough for me as it's already causing distortion with a 4 times multiplication.

 Author: SeregaZ [ Tue Sep 27, 2016 4:05 pm ] Post subject: Re: Noob's investigation of VGM this value need to get from extra, when it have?

 Author: wilbert [ Tue Sep 27, 2016 4:53 pm ] Post subject: Re: Noob's investigation of VGM SeregaZ wrote:this value need to get from extra, when it have?Yes, the VGM v1.70 Extra Header can have both information about the clock setting of a chip and about the volume of a chip.

 Author: wilbert [ Wed Sep 28, 2016 4:59 am ] Post subject: Re: Noob's investigation of VGM SeregaZ wrote:it have one small problem you say command set a multiple, but:Quote:Note: If Bit 15 is 0, this is an absolute volume setting. If Bit 15 is 1, it's relative and the chip volume gets multiplied by ((Value & 0x7FFF) / 0x0100).it can be multiple, and i understand how it work - multiple is multiple, but what does it mean absolute? it means maximum volume for volume 0 in a table? chip have 15 values... which one of them is this "absolute"? it is black hole no examples, no clear explanation of ValleyBell... i set any values for VGM and play in winamp - 0 to \$FF - silence, \$100 to \$FFFF - i think same volume. no louder, no lower...As far as I understand for the SN76489 the ratio is always 2:1 .So a relative volume of \$100 is the same as an absolute volume of \$80.A relative volume of \$200 is the same as an absolute volume of \$100.In other words, with the same value for absolute and relative, absolute should be 3 dB louder.I found another volume related thing v1.60 and above have Volume Modifier (header offset \$7c).Don't know if it's important or not.

 Author: SeregaZ [ Wed Sep 28, 2016 6:42 am ] Post subject: Re: Noob's investigation of VGM i am forgot set break and id 0 checking anyway - where to get examples for check how correct this values is reads and apply? that test vgm - i make, and i am not sure how correct i made it. i think if some values make silence - it is right place, but why volume have only two cases - sound or silence i didnt hear difference by set any values.and i am start hate VGM maybe we are will kick out extra volume header and will use only this volume modifier? btw this train song says this modifier is 24.so volume is:note volume 15 casesextra header settingvolume modifiertoo much for volume note volume 15 cases - individual noteextra header setting - for both, or just for second.volume modifier - for both chips?

 Author: wilbert [ Wed Sep 28, 2016 9:33 am ] Post subject: Re: Noob's investigation of VGM SeregaZ wrote:and i am start hate VGM maybe we are will kick out extra volume header and will use only this volume modifier?I think for now it might be best to ignore both that volume modifier and the difference between absolute and relative volume setting.The volume modifier is not related to a specific chip but to the entire player in general.The difference between absolute and relative volume varies per chip model. I posted an update of the moduleI added SetNoisePattern which allows to set the noise pattern that is used.Clock is renamed now to SetClock for consistency with other procedure names.

 Author: SeregaZ [ Wed Sep 28, 2016 1:26 pm ] Post subject: Re: Noob's investigation of VGM Quote:2016-09-28 12:41:44 ValleyBell 0x7C is a global setting used to makes quiet VGMs louder.2016-09-28 12:57:23 ValleyBell (tl;dr: It is "Replay Gain" for VGMs.)Quote:I think for now it might be best to ignore both that volume modifier and the difference between absolute and relative volume setting.i agree frequency for chip will be enough. other params can go to hell

 Author: wilbert [ Thu Sep 29, 2016 9:45 am ] Post subject: Re: Noob's investigation of VGM I posted a small update.The bit from the clock frequency which indicates a second chip should only be looked at when the clock for the first chip is set.With the previous version, setting the clock of the second chip without the bit set put it back to one chip again.v 1.43 fixes a noise frequency problem.

 Author: wilbert [ Sat Oct 01, 2016 6:12 pm ] Post subject: Re: Noob's investigation of VGM Here's a rough attempt at a playback which works on Windows and MacOS also (my main OS).The Delay() method wan't accurate enough for that on MacOS.Here's v 1.43 of the include fileviewtopic.php?p=494943#p494943Code:XIncludeFile "SN76489.pbi"CompilerSelect #PB_Compiler_OS  CompilerCase #PB_OS_Windows    Macro ztype:l:EndMacro      #ZLIB_Filename = "zlib.lib"  CompilerCase #PB_OS_Linux    Macro ztype:i:EndMacro      #ZLIB_Filename = #PB_Compiler_Home + "purelibraries/linux/libraries/zlib.a"  CompilerDefault    Macro ztype:i:EndMacro      #ZLIB_Filename = "-lz"CompilerEndSelectStructure zstream_ Align #PB_Structure_AlignC  *next_in  avail_in.ztype  total_in.ztype  *next_out  avail_out.ztype  total_out.ztype  *msg  *state  *zalloc  *zfree  *opaque  data_type.ztype  adler.ztype  reserved.ztypeEndStructureImportC #ZLIB_Filename  inflate(*strm, flush)  inflateEnd(*strm)  inflateInit2_(*strm, windowBits, *version, stream_size)  zlibVersion()EndImport;-Catch and Load VGM filesProcedure.i CatchVGM(*VGM, Size = -1)  Protected strm.zstream_, *m, *l.Long = *vgm  Protected.i done, vgmsize  If *l    Size & \$3fffffff    If *l\l = \$206d6756      *l + 4 : vgmsize = *l\l + 4      *l = AllocateMemory(vgmsize)      If *l And vgmsize <= Size        CopyMemory(*vgm, *l, vgmsize)        done = #True      EndIf    ElseIf *l\l & \$ffff = \$8b1f      *l = AllocateMemory(65536)      If *l        strm\next_in = *vgm        strm\avail_in = Size        strm\next_out = *l        strm\avail_out = 65536        If inflateInit2_(@strm, 31, zlibVersion(), SizeOf(zstream_)) = 0          inflate(@strm, 0)          If *l\l = \$206d6756            *l + 4 : vgmsize = *l\l + 4 : *l - 4            If vgmsize              *m = ReAllocateMemory(*l, vgmsize)              If *m                *l = *m                If strm\total_out < vgmsize                  strm\avail_out = vgmsize - 65536                  inflate(@strm, 4)                EndIf                If strm\total_out = vgmsize                  done = #True                EndIf              EndIf            EndIf          EndIf        EndIf      EndIf    EndIf  EndIf  If *l And Not done    FreeMemory(*l) : *l = 0  EndIf  ProcedureReturn *l  EndProcedureProcedure.i LoadVGM(Filename.s)  Protected.i file, size, *m, *vgm  file = ReadFile(#PB_Any, Filename)  If file    size = Lof(file) : *m = AllocateMemory(size)    If *m      If ReadData(file, *m, size) = size        *vgm = CatchVGM(*m)      EndIf      CloseFile(file)      FreeMemory(*m)      EndIf  EndIf  ProcedureReturn *vgmEndProcedureProcedure FreeVGM(*VGM)  If *VGM : FreeMemory(*VGM) : EndIfEndProcedureStructure VGMData  l.l[0] : u.u[0] : a.a[0]EndStructureStructure VGMCommand  cmd.a : u.u[0] : a.a[0]EndStructureDataSection  SkipTable:  ;      0 1 2 3 4 5 6 7 8 9 a b c d e f  Data.a 1,1,1,2,3,3,0,1,1,0,3,3,4,4,5,5  ; cmd skip  Data.a 5,5,6,11,2,5                     ; DAC skipEndDataSectionGlobal *VGM, *CurrentPos, lOffset, EnableVGM, WaitProcedure RenderVGM(*buf, len.l)  Protected.l version, dOffset, lOffset, i, skip  Protected *cmd.VGMCommand, cmd.a  Protected.VGMData *v_, *v = *VGM, *skipTable = ?SkipTable  If EnableVGM And *v And *v\l[0] = \$206d6756        ; >> header <<    If *CurrentPos - *VGM < \$40      version = *v\l[2]                       ; VGM version      lOffset = *v\l[7]                       ; loop offset      If lOffset : lOffset + \$1C : EndIf      dOffset = *v\l[13] + \$34                ; data offset      If version < \$150 Or dOffset < \$40        dOffset = \$40      EndIf      SN76489::SetClock(*v\l[3])              ; SN76489 clock      If version < \$110        SN76489::SetNoisePattern(\$100009)     ; SN76489 noise      Else        SN76489::SetNoisePattern(*v\l[10])      EndIf      If dOffset >= \$C0                       ;  extra header        *v = *v\l[47] + \$BC        If *v >= \$C0 And dOffset > *v          *v + *VGM          If *v\l[0] >= 8            If *v\l[1]              *v_ = *v + *v\l[1] + 4              i = *v_\a[0] : *v_ + 1              While i : i - 1                If *v_\a[0] = 0; SN76489 ?                  *v_ + 1                  SN76489::SetClock(*v_\l[0], 1)                  *v_ + 4                Else                  *v_ + 5                EndIf              Wend            EndIf          EndIf          If *v\l[0] >= 12            If *v\l[2]              *v_ = *v + *v\l[2] + 8              i = *v_\a[0] : *v_ + 1              While i : i - 1                If *v_\a[0] = 0; SN76489 ?                  SN76489::SetChipVolume(*v_\u[1], *v_\a[1] & 1)                EndIf                *v_ + 4              Wend            EndIf          EndIf        EndIf        EndIf      *CurrentPos = *VGM + dOffset    EndIf        ; >> commands <<    If *CurrentPos - *VGM >= \$40            If Wait        If Wait >= len          SN76489::Render(*buf, len)          Wait - len          ProcedureReturn        Else          SN76489::Render(*buf, Wait)          *buf + Wait << 2 : len - Wait          Wait = 0        EndIf      EndIf              *cmd = *CurrentPos      While len        wait = 0        While wait = 0          cmd = *cmd\cmd          Select cmd            Case \$50, \$30   : SN76489::Write(*cmd\a[0], cmd >> 5 & 1) : *cmd + 2            Case \$4F, \$3F   : SN76489::GGStereoWrite(*cmd\a[0], cmd >> 5 & 1) : *cmd + 2            Case \$70 To \$7F : wait = cmd & \$f + 1 : *cmd + 1            Case \$61        : wait = *cmd\u[0] : *cmd + 3            Case \$62        : wait = 735 : *cmd + 1            Case \$63        : wait = 882 : *cmd + 1            Case \$67        : *v_ = *cmd + 3 : *cmd + 7 + (*v_\l[0] & \$7fffffff)            Case \$68        : *cmd + 12            Case \$90 To \$95 : *cmd + *skipTable\a[(cmd & \$f) | \$10]            Case \$66:              ; normal end of data => loop              Debug "end"              If lOffset                *cmd = *VGM + lOffset              Else                EnableVGM = #False                wait = 10000              EndIf                      Default:              skip = *skipTable\a[cmd >> 4] : *cmd + skip              If skip = 0                ; unknown command, quit                EnableVGM = #False              EndIf          EndSelect        Wend                If Wait > len          SN76489::Render(*buf, len) : *buf + len << 2          Wait - len          Break        EndIf        SN76489::Render(*buf, wait) : *buf + wait << 2        len - wait              Wend      *CurrentPos = *cmd          EndIf      Else    FillMemory(*buf, len << 2)  EndIfEndProcedureSN76489::SN76489()CompilerIf #PB_Compiler_OS = #PB_OS_MacOS    Import "-stdlib=libc++ -mmacosx-version-min=10.7" : EndImport    DataSection    dOut:    Data.l \$61756f75,\$64656620,\$6170706c,0,0    PCM16Bit:    Data.l 0,\$40E58880,\$6C70636D,12,4,1,4,2,16,0  EndDataSection    Global PSG_Unit.i    Procedure PSG_Init(*CallbackFunction, BufferSize.l = 2048)    Protected Dim CallbackStruct.i(1) : CallbackStruct(0) = *CallbackFunction    AudioComponentInstanceNew_(AudioComponentFindNext_(#Null, ?dOut), @PSG_Unit)    AudioUnitSetProperty_(PSG_Unit, 23, 1, 0, @CallbackStruct(), SizeOf(Integer) << 1)    AudioUnitSetProperty_(PSG_Unit, 8, 1, 0, ?PCM16Bit, 40)    AudioUnitSetProperty_(PSG_Unit, \$6673697a, 1, 0, @BufferSize, 4)    AudioUnitInitialize_(PSG_Unit)  EndProcedure    Procedure PSG_Start()    ProcedureReturn Bool(AudioOutputUnitStart_(PSG_Unit) = 0)  EndProcedure    Procedure PSG_Stop()    AudioOutputUnitStop_(PSG_Unit)  EndProcedure    Procedure PSG_Terminate()    If PSG_Unit      AudioOutputUnitStop_(PSG_Unit)      AudioUnitUninitialize_(PSG_Unit)      AudioComponentInstanceDispose_(PSG_Unit)      PSG_Unit = 0    EndIf  EndProcedure    ProcedureC Callback(*inRefcon, *ioActionFlags, *inTimeStamp, inBusNumber.l, inNumberFrames.l, *ioData)    RenderVGM(PeekI(*ioData + SizeOf(Integer) + 8), inNumberFrames)    ProcedureReturn 0  EndProcedure    PSG_Init(@Callback())  PSG_Start()  CompilerElse    #PSG_BUFFERS = 4  Global Dim wavebuf.w(#PSG_BUFFERS - 1, 2047)  Global Dim wavehdr.WAVEHDR(#PSG_BUFFERS - 1)  Global.i PSG_Unit, WMME_Playing    DataSection    PCM16BitSigned:    Data.w 1,2,\$AC44,0,\$B110,2,4,16,0  EndDataSection      Procedure WMME_Callback(hwo, uMsg, dwInstance, *wavehdr.WAVEHDR, dwParam2)    If WMME_Playing And uMSG = #WOM_DONE      RenderVGM(*wavehdr\lpData, 1024)      waveOutWrite_(hwo, *wavehdr, SizeOf(WAVEHDR))    EndIf  EndProcedure    Procedure PSG_Terminate()    Protected i.i    If PSG_Unit      WMME_Playing = #False      waveOutReset_(PSG_Unit)      While i < #PSG_BUFFERS             waveOutUnprepareHeader_(PSG_Unit, @wavehdr(i), SizeOf(WAVEHDR))        i + 1      Wend              waveOutClose_(PSG_Unit)      PSG_Unit = 0    EndIf  EndProcedure      Procedure PSG_Init()    If waveOutOpen_(@PSG_Unit, #WAVE_MAPPER, ?PCM16BitSigned, @WMME_Callback(), 0, #CALLBACK_FUNCTION)      MessageRequester("Error", "Unable to initialize PSG")    Else      While i < #PSG_BUFFERS        wavehdr(i)\lpData = @wavebuf(i, 0)        wavehdr(i)\dwBufferLength = 4096        waveOutPrepareHeader_(PSG_Unit, @wavehdr(i), SizeOf(WAVEHDR))        waveOutWrite_(PSG_Unit, @wavehdr(i), SizeOf(WAVEHDR))        i + 1      Wend      WMME_Playing = #True    EndIf  EndProcedure    PSG_Init()  CompilerEndIfFileName.s = OpenFileRequester("Choose VGM file", "", "", 0)*VGM = LoadVGM(FileName)EnableVGM = #TrueMessageRequester("VGM", "Playing")PSG_Terminate()

 Author: SeregaZ [ Sat Oct 01, 2016 9:46 pm ] Post subject: Re: Noob's investigation of VGM i see you are not read vgm to array, but directly play?

 Author: wilbert [ Sun Oct 02, 2016 5:34 am ] Post subject: Re: Noob's investigation of VGM SeregaZ wrote:i see you are not read vgm to array, but directly play?Yes, that's true.Is there any reason you prefer to use an array ?

 Author: SeregaZ [ Sun Oct 02, 2016 8:00 am ] Post subject: Re: Noob's investigation of VGM for PSG probably not. for YM it need for DAC samples playing. problem is - that ValleyBell's dll play samples by external command. it need frequency, size and adress of sample. by theory samples is play by chip - by using \$2A registers, but it didnt work, so ValleyBell make that external command. system must be some kind of your PSG samples play (btw your not plays too )) some scratch and noise hear). then come problem with this frequency and size - VGM no have frequency settings for samples and size. that is why i read into array, then make puzzles for samples, only then play. even this case not very well helps. this opn.dll have some problem with save cpu - it is shutdown of playing, if samples have silence. for example: sample length 2 sec, at begin it have some sound, at middle some silence, at the end some play - this dll play first part, then shutdown. he think samples is end if pause more than 0.5 sec. second problem: samples starts VGM by setting address of sample in wav bank - some kind of setting pointer - i catch this moment and start collect sample byte per byte. and it work and frequency count correct and sample size, BUT! if track have two samples one and second and they lays at wav bank near each other one and second - setting of adress of second samples can be not happen. pointer just continue move far. and beetween of this samples can be large pause - this moment is broke all my super system )) that is why i start this topic - find help to solve this samples problem.i think check all track, get all adresses, cut wav bank, then check oversize of sample. if this oversize is happen - it means at this moment starts second sample. it will work, if track will have this second marker of adress, but if is not - deam again

 Author: SeregaZ [ Sun Oct 02, 2016 8:06 am ] Post subject: Re: Noob's investigation of VGM and about your delays - we talk about it here:viewtopic.php?f=13&t=62919maybe some one can help with pauses for your system?

 Author: wilbert [ Sun Oct 02, 2016 10:40 am ] Post subject: Re: Noob's investigation of VGM SeregaZ wrote:for YM it need for DAC samples playing. problem is - that ValleyBell's dll play samples by external command. it need frequency, size and adress of sample.Sounds difficult to get it right. A FM chip is already more complicated. What I like about the PSG is the relative simplicity of it.SeregaZ wrote:and about your delays - we talk about it here:I thought about it some more. It could also be caused by different ringbuffer implementations on different OS.Usually there are multiple sample buffers which are queued. Depending on when this is done, timing can be a bit off if you don't make changes at sample accurate timing.

 Page 4 of 8 All times are UTC + 1 hour Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Grouphttp://www.phpbb.com/