Author Topic: Implementing vinyl scratching sound  (Read 608 times)

kafffee

  • Posts: 252
Implementing vinyl scratching sound
« on: 1 Dec '22 - 21:10 »
Hi everybody  :)

I found this demo code in this forum for creating a vinyl scratching sound:

Code: [Select]
if (scratchVelocity < 100 && scratchVelocity > -100000)
    {
        BASS_ChannelStop([bassPointer getChannel]);
        QWORD pos=BASS_ChannelGetPosition([bassPointer getChannel], BASS_POS_BYTE); // get current position
        BASS_ChannelSetPosition([bassPointer getChannel], pos, BASS_POS_BYTE); // "seek" there to clear output buffer (avoid latency)
        BASS_ChannelSetAttribute([bassPointer getRevChannel], BASS_ATTRIB_REVERSE_DIR, BASS_FX_RVS_REVERSE);
        BASS_ChannelPlay([bassPointer getChannel], false);
        NSLog(@"scratchVelocity %f", -scratchVelocity);
        BASS_ChannelSlideAttribute([bassPointer getChannel], BASS_ATTRIB_FREQ, -scratchVelocity, 100);
       
    }
    else if (scratchVelocity > 100 && scratchVelocity < 100000)
    {
        BASS_ChannelStop([bassPointer getChannel]);
        QWORD pos=BASS_ChannelGetPosition([bassPointer getChannel], BASS_POS_BYTE);
        BASS_ChannelSetPosition([bassPointer getChannel], pos, BASS_POS_BYTE);
        BASS_ChannelSetAttribute([bassPointer getRevChannel], BASS_ATTRIB_REVERSE_DIR, BASS_FX_RVS_FORWARD);
        BASS_ChannelPlay([bassPointer getChannel], false);
        NSLog(@"scratchVelocity %f", scratchVelocity);
        BASS_ChannelSlideAttribute([bassPointer getChannel], BASS_ATTRIB_FREQ, scratchVelocity, 100);
    }

Seems to be pretty easy, but what is this  NSLog(@"scratchVelocity %f", scratchVelocity); line? What does it do? Is there anything else I should think of?

Chris

  • Posts: 2169
Re: Implementing vinyl scratching sound
« Reply #1 on: 2 Dec '22 - 07:47 »
NsLog I think it's  a Logfile

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #2 on: 2 Dec '22 - 08:15 »
Ah okay so this must be only for debugging purposes?

Ian @ un4seen

  • Administrator
  • Posts: 25460
Re: Implementing vinyl scratching sound
« Reply #3 on: 2 Dec '22 - 18:01 »
Yes, the NSLog function is for logging/debugging on macOS/iOS platforms:

   https://developer.apple.com/documentation/foundation/1395275-nslog

Regarding the subject of a vinyl scratching effect, here's an old thread on the subject:

   www.un4seen.com/forum/?topic=9754.msg68053#msg68053

Unfortunately, the download links appear to be dead now, but there's still some code/discussion that you may find helpful.

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #4 on: 3 Dec '22 - 09:13 »
Yes I've already seen this. I dont really get along with the code so I want to stick with what I have:

I translated to c# and now it looks like this:

Code: [Select]
private void Scratching(TimeSpan ts)
        {
            if (ts.Milliseconds < 100 && ts.Milliseconds > -100000)
            {
                Bass.BASS_ChannelStop(streamforward);
                long pos = Bass.BASS_ChannelGetPosition(streamforward, BASSMode.BASS_POS_BYTE); // get current position
                Bass.BASS_ChannelSetPosition(streamforward, pos, BASSMode.BASS_POS_BYTE); // "seek" there to clear output buffer (avoid latency)
                Bass.BASS_ChannelSetAttribute(streamreverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, -1);
                Bass.BASS_ChannelPlay(streamforward, false);
                //NSLog(@"scratchVelocity %f", -scratchVelocity);
                Bass.BASS_ChannelSlideAttribute(streamforward, BASSAttribute.BASS_ATTRIB_FREQ, -ts.Milliseconds, 100);

            }
            else if (ts.Milliseconds > 100 && ts.Milliseconds < 100000)
            {
                Bass.BASS_ChannelStop(streamforward);
                long pos = Bass.BASS_ChannelGetPosition(streamforward, BASSMode.BASS_POS_BYTE);
                Bass.BASS_ChannelSetPosition(streamforward, pos, BASSMode.BASS_POS_BYTE);
                Bass.BASS_ChannelSetAttribute(streamreverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1);
                Bass.BASS_ChannelPlay(streamforward, false);
                //NSLog(@"scratchVelocity %f", scratchVelocity);
                Bass.BASS_ChannelSlideAttribute(streamforward, BASSAttribute.BASS_ATTRIB_FREQ, ts.Milliseconds, 100);
            }
        }

Looks like something is wrong, because when I scratch, all I hear is a buzzing.

Edit: When I spin the turntable for either just two or three pixels or When I spin as fast as I can do with my mouse I can hear something like a scratching sound for like half a second.

I guess it has to do with the values for ts. Anybody know an approach on how to calculate this argument? Should I  better pass a TimeSpan or a velocity?

Edit: Ah okay I found out about it. Must be the sampling rate and I have to leave out everything but ChannelSetAttribute and ChannelSlideAttribute...

Further questions may come...  :)
« Last Edit: 4 Dec '22 - 07:27 by kafffee »

Ian @ un4seen

  • Administrator
  • Posts: 25460
Re: Implementing vinyl scratching sound
« Reply #5 on: 5 Dec '22 - 13:49 »
Those old threads and code are from before BASS had the option of disabling playback buffering. So seeking was used to reset the playback buffer and avoid latency when switching direction. These days you can disable playback buffering instead (by setting BASS_ATTRIB_BUFFER to 0 via BASS_ChannelSetAttribute), which allows your function to be reduced to something like this:

Code: [Select]
private void Scratching(TimeSpan ts)
        {
            if (ts.Milliseconds < 100 && ts.Milliseconds > -100000)
            {
                Bass.BASS_ChannelSetAttribute(streamreverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, -1);
                Bass.BASS_ChannelSlideAttribute(streamforward, BASSAttribute.BASS_ATTRIB_FREQ, -ts.Milliseconds, 100);

            }
            else if (ts.Milliseconds > 100 && ts.Milliseconds < 100000)
            {
                Bass.BASS_ChannelSetAttribute(streamreverse, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1);
                Bass.BASS_ChannelSlideAttribute(streamforward, BASSAttribute.BASS_ATTRIB_FREQ, ts.Milliseconds, 100);
            }
        }

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #6 on: 19 Jan '23 - 12:53 »
Ok I can hear something like a scratching when I do this. But the tones coming out seem to be too low, just as if you would turn down the pitch.

I have been trying with all types of values for SamplingRate. Is there a better way to do it?

Code: [Select]
Public Sub New()
Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, Nothing)
MainModule.forwardstream = Bass.BASS_StreamCreateFile("C:\Test.mp3", -1, -1, BASSFlag.BASS_STREAM_PRESCAN)
MainModule.reversestream = BassFx.BASS_FX_ReverseCreate(MainModule.forwardstream, 2.0F, BASSFlag.BASS_FX_FREESOURCE)
Bass.BASS_ChannelGetAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, SampleRate)
Bass.BASS_ChannelPlay(MainModule.forwardstream, False)
Bass.BASS_ChannelPlay(MainModule.reversestream, False)
End Sub

Private Sub ScratchingCommand_Execute(_Rate As Integer)

        Dim SamplingRate As Integer = _Rate

        If ((SamplingRate1 < 100) AndAlso (SamplingRate1 > -100000)) Then
            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, -1)
            Bass.BASS_ChannelSlideAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(-SamplingRate), 100)
        ElseIf ((SamplingRate1 > 100) AndAlso (SamplingRate < 100000)) Then
 

            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1)
            Bass.BASS_ChannelSlideAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(SamplingRate), 100)

        End If
    End Sub

Ian @ un4seen

  • Administrator
  • Posts: 25460
Re: Implementing vinyl scratching sound
« Reply #7 on: 19 Jan '23 - 16:01 »
Ok I can hear something like a scratching when I do this. But the tones coming out seem to be too low, just as if you would turn down the pitch.

That sounds like the BASS_ATTRIB_FREQ setting is lower than you want. How are you calculating the ScratchingCommand_Execute call parameter? I notice that function references "SamplingRate" and "SamplingRate1" variables. Is "SamplingRate1" just a typo in the post and not in the code?

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #8 on: 19 Jan '23 - 21:40 »
Oh yes thats a typo sorry :o

I have a jog wheel on a hardware mixing desk, whose commands I can receive via MIDI. It will send a value 1 when moved forwards and 127 in reverse. This command is being sent 128 times for each rotation.

This is how I am trying to calculate it:

Code: [Select]
Private oldTime As DateTime = DateTime.Now            'get current system time when initialized
Private newTime As DateTime                                   'declare variable to measure time in between two events

And this is being called when a MIDI-event happens, respectively the jog wheel is being moved:

Code: [Select]
Public Sub NewMIDI-Event()

newTime = DateTime.Now                                     'get current system time when jog wheel is being moved
Dim timeDifference As TimeSpan = newTime - oldTime          'get timespan in between two moving-events
oldTime = newTime                                                             'update old time for the next call

If MIDIEvent.Value = 127 Then                                              'If wheel has been moved in reverse then
   ScratchingCommand_Execute(-100000) 'with this value it sounds like the tones are too low
Else                                                                                     ' íf wheel has been moved forward
   ScratchingCommand_Execute(100000) 'with this value it sounds like the tones are too low
End Sub

Now what I need to get is a correct value instead of 100000 respectively -100000...

I am not exactly a genius at mathematics and I 've been staring at my screen and contemplating for like two hours now, but I need to somehow get the correct sampling rate out of  the varibale timeDifference, which should return the timespan in between two moving-events (which occur 128 times at each rotation) in milliseconds when I do:

timeDifference.TotalMilliSeconds

When I assume, that a record is spinning with 45 rpm and the event happens 128 times per rotation I should somehow be able to get this...?

jpf

  • Posts: 182
Re: Implementing vinyl scratching sound
« Reply #9 on: 20 Jan '23 - 03:45 »
I never did vinyl scratching in my life but I did a lot of cueing when I had to cover for an absent desk operator in the radio station I worked for 43 years, so I can figure out how scratching must sound.

For simplicity let's consider just the forward scratching.
Let's assume one turn of the jog wheel would move the 45 rpm vinyl exactly one turn.
The nominal rotational speed of the record is 45/60 turn/sec.
At that speed and 128 Midi events per turn, we have one Midi event each 45/60/128 sec. or approx. 5.86 ms.
At that jog speed the samplerate must be 1x the native samplerate of the file being played.
For shorter timeDifference the samplerate must rise, and viceversa.
So the scratching samplerate should be: (native file samplerate) * 5.86 / timeDifference.
(Please check my math. I did it all in my mind.)

I anticipate an ill extreme case of this approach due to the scratching samplerate being applied after each Midi event and not at a fixed interval.
Suppose you're turning the jog wheel at a somehow high speed, producing a high pitched scratch sound. If you then suddenly stop turning it, the next Midi event will never arrive and the pitch will stay high forever.
A possible workaround could be to have a timer set on each Midi event that will call ScratchingCommand_Execute(native file samplerate) if the next Midi event doesn't arrive within a specified time.
That will sound like you releasing your hand from the vinyl and letting the turntable spin it at normal speed.
But if you instead wanted to hold the vinyl steady waiting for the right moment to mix it in by not moving the jog wheel, then the timer must pause the playback instead.
I think the pausing and unpausing could be implemented inside the ScratchingCommand_Execute sub for simplicity. If called with an argument < 100 then it should pause, else it should unpause.

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #10 on: 20 Jan '23 - 06:05 »
Wow cool I can use that  :D

I'll let you know how it worked out, thank you


>>>>>>>>>Edit:

So far so good. Now I got this:

Code: [Select]
Bass.BASS_ChannelGetAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, SampleRate)

Public Sub NewMIDI-Event()

newTime = DateTime.Now
Dim timeDifference As TimeSpan = newTime - oldTime
oldTime = newTime

If (timeDifference.TotalMilliseconds > 80) AndAlso (IsPaused = False) Then
            Bass.BASS_ChannelPause(MainModule.forwardstream)
            Bass.BASS_ChannelPause(MainModule.reversestream)
            IsPaused = True
Else
            If IsPaused = True Then
                Bass.BASS_ChannelPlay(MainModule.forwardstream, False)
                Bass.BASS_ChannelPlay(MainModule.reversestream, False)
                IsPaused = False
            End If

            If MyMIDIHandler.MIDIEventParser.ControlID = 51 Then
                If MyMIDIHandler.MIDIEventParser.ControlValue = 127 Then
                    ScratchingCommand_Execute(SampleRate * 33 / 60 * 1000 / 128 / timeDifference.TotalMilliseconds)
                Else
                    ScratchingCommand_Execute(-SampleRate * 33 / 60 * 1000 / 128 / timeDifference.TotalMilliseconds)
                End If
            ElseIf MyMIDIHandler.MIDIEventParser.ControlID = 52 AndAlso MyMIDIHandler.MIDIEventParser.ControlValue = 0 Then     'if jog wheel is released
                ScratchingCommand_Execute(SampleRate)   'reset to native sample rate
            End If
        End If
End Sub

Luckily, my mixing desk also sends a MIDI command, when the jog wheel is releaed, so I don't have to worry about whether I want to pause the music or play it at native sample rate...

It's actually supposed to work I guess, but it doesn't... It sounds more like a quick pitch bending, but not like a scratching...

Any ideas?
« Last Edit: 20 Jan '23 - 08:10 by kafffee »

jpf

  • Posts: 182
Re: Implementing vinyl scratching sound
« Reply #11 on: 20 Jan '23 - 15:54 »
Your code seems fine. Maybe test small fragments of it separatelly to see if they behave as expected?

1-Does the ScratchingCommand_Execute sub produce the expected pitch? You can try calling the sub with let's say the native samplerate, 1/2 of that, twice of that, etc. and check that you get the expected pitch. Also check those values *-1 for reverse rotation. Be sure to check out of bounds values too.
2-Is the ScratchingCommand_Execute sub able to cope with the expected rate of arrival of Midi events? I'm not sure how to check this. Maybe you can set a timer to send fake Sub NewMIDI-Event calls at a high enough rate and check that timeDifference is always = the timer interval.
3-Is timeDifference really roughly inverse proportional to the jog wheel rotation speed? Since it's not ease to rotate the wheel at a constant speed by hand you may want to use some motorized gadget to do it (for instance a mirror ball motor).
4-Is the argument sent to ScratchingCommand_Execute proportional to the rotational speed of the jog wheel?

Even if ScratchingCommand_Execute passes the test it's not a perfect emulation of rotating the vinyl at very low and very high speeds. You should also mind that a real moving magnet pick-up cartridge output voltage is proportional to the rotational speed of the vinyl. This is roughly compensated by the RIAA frecuency responce curve of the preamplifier, but just roughly.

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #12 on: 7 Feb '23 - 11:26 »
Sry for the late response, I did not really get to work on this earlier.

I did some testing, here go the results (I think I found whats wrong with it):

(1) ScratchingCommand_Execute produces the right pitch, but when I pass a negative value as an argument (obj), it will not play backwards. This must be the main issue. Any ideas how to fix this? I do not really see through this piece of code, so any help is appreciated:

Code: [Select]
Private Sub ScratchingCommand_Execute(obj As Object)
        Dim Samplingrate1 As Integer = CInt(obj)   'turn object into integer
       
        If ((Samplingrate1 < 100) AndAlso (Samplingrate1 > -Limit)) Then         

            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, -1)         
            Bass.BASS_ChannelSlideAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(-Samplingrate1), 100)
           
        ElseIf ((Samplingrate1 > 100) AndAlso (Samplingrate1 < Limit)) Then
           
            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1)           
            Bass.BASS_ChannelSlideAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(Samplingrate1), 100)

           Else

            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1)
            Bass.BASS_ChannelSlideAttribute(MainModule.forwardstream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(0), 100)

        End If

    End Sub

(2) As a matter of fact, the calculated interval is different from the actual interval in between the calls. I logged this, and this was returned:
0measured time: (+)3208,7395
0actual interval: (+)100

1measured time: (+)631,2004
1actual interval: (+)600

2measured time: (+)1128,5063
2actual interval: (+)1100

3measured time: (+)1628,1082
3actual interval: (+)1600

4measured time: (+)2107,17
4actual interval: (+)2100

5measured time: (+)2621,6564
5actual interval: (+)2600

6measured time: (+)3112,9302
6actual interval: (+)3100

7measured time: (+)3626,2407
7actual interval: (+)3600

8measured time: (+)4118,6537
8actual interval: (+)4100

9measured time: (+)4614,8074
9actual interval: (+)4600

10measured time: (+)5123,1657
10actual interval: (+)5100

I don't know if this is negligible, I guess I'd have to fix issue no. (1) first to find out...

Ian @ un4seen

  • Administrator
  • Posts: 25460
Re: Implementing vinyl scratching sound
« Reply #13 on: 7 Feb '23 - 16:03 »
I notice you have "reversestream" and "forwardstream" handles. Referring back to your earlier post, that code looks problematic. Firstly, BASS_FX_ReverseCreate requires a decoding channel (with BASS_STREAM_DECODE flag set). Secondly, you should only be playing the reverse stream (which also supports forward playback via BASS_ATTRIB_REVERSE_DIR), not the original file stream too. Try changing that code like this:

Code: [Select]
Public Sub New()
Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, Nothing)
MainModule.decoder = Bass.BASS_StreamCreateFile("C:\Test.mp3", 0, 0, BASSFlag.BASS_STREAM_PRESCAN or BASSFlag.BASS_STREAM_DECODE)
MainModule.reversestream = BassFx.BASS_FX_ReverseCreate(MainModule.decoder, 2.0F, BASSFlag.BASS_FX_FREESOURCE)
Bass.BASS_ChannelGetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, SampleRate)
Bass.BASS_ChannelPlay(MainModule.reversestream, False)
End Sub

And then change the ScratchingCommand_Execute function like this:

Code: [Select]
Private Sub ScratchingCommand_Execute(Samplingrate1 As Integer)
       
        If (Samplingrate1 < 0) Then         

            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, -1)         
            Bass.BASS_ChannelSlideAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(-Samplingrate1), 100)
           
        Else
           
            Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1)           
            Bass.BASS_ChannelSlideAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(Samplingrate1), 100)

        End If

    End Sub

If it still isn't sounding right, please try logging the "Samplingrate1" values in there when you move your jog wheel back and forward to see what they are.

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #14 on: 8 Feb '23 - 10:02 »
Yes it still sounds about the same  :(

Here is a part of the logs:

Samplingrate1: -10733
Event triggered!!
Samplingrate1: -26398
Event triggered!!
Samplingrate1: -14817
Event triggered!!
Samplingrate1: -29839
Event triggered!!
Samplingrate1: -17106
Event triggered!!
Samplingrate1: -22012
Event triggered!!
Event triggered!!
Samplingrate1: 44100
Event triggered!!
Event triggered!!
Event triggered!!
Samplingrate1: 1955
Event triggered!!
Samplingrate1: 32314
Event triggered!!
Samplingrate1: 16491
Event triggered!!
Samplingrate1: 28728

Notice that the change of driection seems to work right. but some of the events seem to get "swallowed up". At some points the midi event gets triggered but without changing SamplingRate1, as you can see...
« Last Edit: 8 Feb '23 - 10:47 by kafffee »

jpf

  • Posts: 182
Re: Implementing vinyl scratching sound
« Reply #15 on: 8 Feb '23 - 14:34 »
Those logs seem wrong. Too few events and the values are too far appart from next/previous.

(For a 1/4 turn Backspin you should get 128/4=32 events triggered about 5 ms appart from each other (that would translate into a -44100 samplerate). I'd say, if you're not very handy values from 3 to 7 ms could still do even if they'll sound too low / high pitched, but they should be about constant or smoothly varying across the whole Backspin except at the very beginning. Anything else won't sound like a Backspin.)

To see if you're skipping events because of the ScratchingCommand_Execute taking too much time you could skip it and just log the events.

I expect you're handy on real (physical) vinyl scratching and/or Serato and are comparing the sound of the same scratch effect (you didn't mention what that effect was: Baby scratch? Chirp? Scribble? etc.?).

I would still advice on breaking down the code and testing each part independently, so to identify which part isn't working properly.

Ian @ un4seen

  • Administrator
  • Posts: 25460
Re: Implementing vinyl scratching sound
« Reply #16 on: 8 Feb '23 - 15:26 »
I forgot to disable playback buffering in my last post. Try adding that:

Code: [Select]
Public Sub New()
Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, Nothing)
MainModule.decoder = Bass.BASS_StreamCreateFile("C:\Test.mp3", 0, 0, BASSFlag.BASS_STREAM_PRESCAN or BASSFlag.BASS_STREAM_DECODE)
MainModule.reversestream = BassFx.BASS_FX_ReverseCreate(MainModule.decoder, 2.0F, BASSFlag.BASS_FX_FREESOURCE)
Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_BUFFER, 0) ' disable playback buffering
Bass.BASS_ChannelGetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, SampleRate)
Bass.BASS_ChannelPlay(MainModule.reversestream, False)
End Sub

Regarding the "swallowed up" events, please show where exactly you are writing the "Event triggered" and "Samplingrate1" log entries to confirm whether the latter should always follow the former (and why it might not).

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #17 on: 9 Feb '23 - 15:09 »
OK I got this:


Code: [Select]
Private Testtimer As New System.Timers.Timer

Public Sub New()
        Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, Nothing)
        MainModule.forwardstream = Bass.BASS_StreamCreateFile("C:\Test.mp3", 0, 0, BASSFlag.BASS_STREAM_PRESCAN Or BASSFlag.BASS_STREAM_DECODE)
        MainModule.reversestream = BassFx.BASS_FX_ReverseCreate(MainModule.forwardstream, 2.0F, BASSFlag.BASS_FX_FREESOURCE)
        Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_BUFFER, 0)
        Bass.BASS_ChannelGetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, SampleRate)
        Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1)
        Bass.BASS_ChannelPlay(MainModule.reversestream, False)
        AddHandler Testtimer.Elapsed, AddressOf TestProcedure
        Testtimer.Start()
End Sub

Private Sub TestProcedure(sender As Object, e As ElapsedEventArgs)
        If TestCounter <= 10 Then
            NewMIDIEvent()
            TestCounter = TestCounter + 1
            Testtimer.Interval = Testtimer.Interval + 500
        Else
            Testtimer.Stop()
        End If
End Sub

 Private Sub ScratchingCommand_Execute(obj As Object)
        Dim Samplingrate1 As Integer = CInt(obj)
       
'If (Samplingrate1 < 0) Then                     'I commented this part for testing purposes
'          Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, -1)
'          Bass.BASS_ChannelSlideAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(-Samplingrate1), 100)
'Else
'        Bass.BASS_ChannelSetAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_REVERSE_DIR, 1)
'       Bass.BASS_ChannelSlideAttribute(MainModule.reversestream, BASSAttribute.BASS_ATTRIB_FREQ, CSng(Samplingrate1), 100)

'End If
End Sub

Public Sub NewMIDIEvent()
neueZeit = DateTime.Now
        Dim measuredTime As TimeSpan = newTime - oldTime
        RPM = measuredTime.TotalMilliseconds
        oldTime = newTime

        Debug.WriteLine(TestCounter & "measured Time: " & measuredTime.TotalMilliseconds)
        Debug.WriteLine(TestCounter & "actual Time: " & "" & Testtimer.Interval)

 If (measuredTime.TotalMilliseconds > 120) AndAlso (IsPaused = False) Then
            Bass.BASS_ChannelPause(MainModule.reversestream)
            IsPaused = True
        Else
            If IsPaused = True Then
                Bass.BASS_ChannelPlay(MainModule.reversestream, False)
                IsPaused = False
            End If

            If MyMIDIHandler.MIDIEventParser.ControlID = 51 Then
                If MyMIDIHandler.MIDIEventParser.ControlValue = 127 Then
                    ScratchingCommand_Execute(SampleRate * 45 / 60 * 1000 / 128 / measuredTime.TotalMilliseconds) 
                Else
                    ScratchingCommand_Execute(-SampleRate * 45 / 60 * 1000 / 128 / gemesseneZeit.TotalMilliseconds)
                End If
            ElseIf MyMIDIHandler.MIDIEventParser.ControlID = 52 AndAlso MyMIDIHandler.MIDIEventParser.ControlWert = 0 Then
                ScratchingCommand_Execute(SampleRate)
            End If
            IsPaused = False
        End If
End Sub

I get this log when I use the timer to trigger NewMIDIEvent:

0measured Time: (+)4043,6372
0actual Time: (+)100
1measured Time: (+)605,0795
1actual Time: (+)600
2measured Time: (+)1111,7357
2actual Time: (+)1100
3measured Time: (+)1608,8819
3actual Time: (+)1600
4measured Time: (+)2106,8814
4actual Time: (+)2100
5measured Time: (+)2623,2064
5actual Time: (+)2600
6measured Time: (+)3116,5642
6actual Time: (+)3100
7measured Time: (+)3608,7941
7actual Time: (+)3600
8measured Time: (+)4107,0186
8actual Time: (+)4100
9measured Time: (+)4607,73
9actual Time: (+)4600
10measured Time: (+)5109,3356
10actual Time: (+)5100

When I spin the wheel 1/4th clockwise I get this:

Event triggered!!
0measured Time: (+)3839,0526
0actual Time: (+)100
Event triggered!!
0measured Time: (+)8,4367
0actual Time: (+)100
Event triggered!!
0measured Time: (+)88,5754
0actual Time: (+)100
ÜBERGEBEN: -2917
Event triggered!!
0measured Time: (+)27,9836
0actual Time: (+)100
ÜBERGEBEN: -9234
Event triggered!!
0measured Time: (+)34,9778
0actual Time: (+)100
ÜBERGEBEN: -7387
Event triggered!!
0measured Time: (+)29,4601
0actual Time: (+)100
ÜBERGEBEN: -8771
Event triggered!!
0measured Time: (+)95,403
0actual Time: (+)100
ÜBERGEBEN: -2708
Event triggered!!
0measured Time: (+)25,9845
0actual Time: (+)100
ÜBERGEBEN: -9944
Event triggered!!
0measured Time: (+)51,9599
0actual Time: (+)100
ÜBERGEBEN: -4973
Event triggered!!
0measured Time: (+)26,1403
0actual Time: (+)100
ÜBERGEBEN: -9885
Event triggered!!
0measured Time: (+)52,954
0actual Time: (+)100
ÜBERGEBEN: -4880
Event triggered!!
0measured Time: (+)27,9917
0actual Time: (+)100
ÜBERGEBEN: -9231
Event triggered!!
0measured Time: (+)75,9569
0actual Time: (+)100
ÜBERGEBEN: -3402
Event triggered!!
0measured Time: (+)36,0114
0actual Time: (+)100
ÜBERGEBEN: -7175
Event triggered!!
0measured Time: (+)77,676
0actual Time: (+)100
ÜBERGEBEN: -3327
Event triggered!!
0measured Time: (+)28,1927
0actual Time: (+)100
ÜBERGEBEN: -9165
Event triggered!!
0measured Time: (+)51,3276
0actual Time: (+)100
ÜBERGEBEN: -5034
Event triggered!!
0measured Time: (+)27,954
0actual Time: (+)100
ÜBERGEBEN: -9244
Event triggered!!
0measured Time: (+)60,8658
0actual Time: (+)100
ÜBERGEBEN: -4245
Event triggered!!
0measured Time: (+)45,3432
0actual Time: (+)100
ÜBERGEBEN: -5699
Event triggered!!
0measured Time: (+)43,3191
0actual Time: (+)100
ÜBERGEBEN: -5965
Event triggered!!
0measured Time: (+)28,0247
0actual Time: (+)100
ÜBERGEBEN: -9220
Event triggered!!
0measured Time: (+)31,9986
0actual Time: (+)100
ÜBERGEBEN: -8075
Event triggered!!
0measured Time: (+)16,9906
0actual Time: (+)100
ÜBERGEBEN: -15208
Event triggered!!
0measured Time: (+)84,2012
0actual Time: (+)100
ÜBERGEBEN: -3069
Event triggered!!
0measured Time: (+)25,0896
0actual Time: (+)100
ÜBERGEBEN: -10299
Event triggered!!
0measured Time: (+)77,4813
0actual Time: (+)100
ÜBERGEBEN: -3335
Event triggered!!
0measured Time: (+)18,996
0actual Time: (+)100
ÜBERGEBEN: -13603
Event triggered!!
0measured Time: (+)65,9089
0actual Time: (+)100
ÜBERGEBEN: -3921
Event triggered!!
0measured Time: (+)36,0575
0actual Time: (+)100
ÜBERGEBEN: -7166
Event triggered!!
0measured Time: (+)74,3826
0actual Time: (+)100
ÜBERGEBEN: -3474
Event triggered!!
0measured Time: (+)37,8621
0actual Time: (+)100
ÜBERGEBEN: -6825
Event triggered!!
0measured Time: (+)41,4372
0actual Time: (+)100
ÜBERGEBEN: -6236
Event triggered!!
0measured Time: (+)29,9059
0actual Time: (+)100
ÜBERGEBEN: -8640
Event triggered!!
0measured Time: (+)62,5297
0actual Time: (+)100
ÜBERGEBEN: -4132
Event triggered!!
0measured Time: (+)423,402
0actual Time: (+)100

@jpf
I don't really have a clue of the different types of scratching (didn't even know there are any different types...)
But this is not what its supposed to sound like I guess...

jpf

  • Posts: 182
Re: Implementing vinyl scratching sound
« Reply #18 on: 9 Feb '23 - 19:09 »
Your TestProcedure seems aimed to produce a logarithmic Spindown effect. Was this your intention?

I was expecting you to set a fixed Testtimer.Interval = 5 ms, which would translate into an aprox. 45 rpm rotation speed, and log the argument sent to ScratchingCommand_Execute.

If everything's right that log should always read close to SampleRate. How close? A +/- 6% variation means a +/- half tone pitch variation. That's unacceptable for my taste. Variation should probably be less than 1%.

If that's achieved then you should uncomment the code into ScratchingCommand_Execute and log. The values should be within the same range as with the code commented out, and the sound should be about the same as playing the file at normal speed. If not, then it probably means that ScratchingCommand_Execute is taking too much time to sustain stable 45 rmp rotation of the jog wheel.

Then you should repeat both tests with a more stressfull Testtimer.Interval, let's say = 1 ms (5x45 rpm). That jog wheel rotational speed is almost impossible to get by a human being, so if you get stable values you can be happy! Then in the uncommented code run, the pitch of the sound should be about 2 octaves higher (if Bass can support so high a samplerate).

The 2nd log you posted (you spinning the jog) shows large variations in "measured time". That would hardly translate into any known kind of scratch. It may sound like you randomly moving a pitch wheel. That doesn't necessarily mean that your spinning speed isn't constant enough. It may also mean that the jog events aren't processed fast enough, or both things.

You could practice spinning at constant speed using your code but instead of a text log you should use an analog indicator like a progress bar or a slider.

It seems you're not trained on scratching. You should at least learn the basics. I just saw that there are a bunch of tutorials on YouTube. I didn't actually watch any of them so I can't advise you on which ones are better. Accomplishing even the easier scratch forms to sound smooth enough may take months depending on your abilities. Or it may take you just a few minutes if you're a natural. I used to practice spinning at specific speeds a 400 Hz test vinyl, aiming to make it "sing" a melody like you do with the violin. It's really difficult! (I'm not a violin player, though).

There are a few VST out there that simulate scratching without human interaction (no jog wheel). That could be useful too if you're not aiming at pro use but just domestic/game.

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #19 on: 9 Feb '23 - 19:44 »
Quote
Your TestProcedure seems aimed to produce a logarithmic Spindown effect. Was this your intention?
No I just thought it might be interesting to try with changing intervals.

Your way of testing sounds good to me, I will try and report the results here.

Quote
It may sound like you randomly moving a pitch wheel

I tried to slowly spin the wheel 1/4th of a rotation for once and only in one direction at a consistant speed. The wheel is pretty small though, about 7 cm, lets say 2.75 inches of diameter.

So for now, it's planned to be for domestic use and playing around a bit, but once its well-tested and people like it - you never know...

But the solution with the VST sounds interesting to me, too. Do you have any names of the VSTs? I produce music myself so I could just try along with my DAW if I like it and then implement this to my app...

jpf

  • Posts: 182
Re: Implementing vinyl scratching sound
« Reply #20 on: 9 Feb '23 - 20:05 »
But the solution with the VST sounds interesting to me, too. Do you have any names of the VSTs?

A quick Google search displayed this at the top:
https://bedroomproducersblog.com/2014/03/06/scratch-free-vinyl-scratch-vst-plugin-effect-z3-audiolabs/

I'm not into scratching so I can't give you leads. Maybe you'll be able to find more stuff.

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #21 on: 10 Feb '23 - 12:51 »
Okay I have found some.

Is there any way to use 64Bit-VSTs? If so, also in a x86 app?

Chris

  • Posts: 2169
Re: Implementing vinyl scratching sound
« Reply #22 on: 10 Feb '23 - 13:21 »
No
32Bit Application -> 32Bit Host
by the way , the most Applications in the Today Time are x64

jpf

  • Posts: 182
Re: Implementing vinyl scratching sound
« Reply #23 on: 10 Feb '23 - 14:24 »
Maybe try jBridge, NetVST, Bitbridge or any other bridge?

kafffee

  • Posts: 252
Re: Implementing vinyl scratching sound
« Reply #24 on: 11 Feb '23 - 11:22 »
That would be worth a try.

I will keep evaluating what you told me to concerning the jog wheel stuff.

Also, I just decided to use VSTs in my app as well, but before I start, I have a bunch of questions, but I will start another thread on that...