1
DotNet / SFML pour l'émulation
« le: Décembre 28, 2012, 09:07:43 pm »
Salut à tous,
Je suis en cours d'écriture d'un émulateur de vieux bouzin (Hector de la gamme Micronique à base de Z80). J'ai, au départ, voulu savoir si le VB.Net était suffisamment rapide pour programmer ce genre de chose qui au début ne pouvait fonctionner que par du code C ou asm; mais maintenant je le sais : Ca marche !
L'ensemble de l'émulateur fonctionne (Z80, Mémoire, I/O, écran, clavier, K7, joystick, lecteur de disquette (à base de Z80 séparé et d'un contrôleur) ...) et seule la gestion du son est manquant. j'ai cherché sur le net la meilleur façon de programmer le son et j'ai trouvé SFML...
Mon cahier des charges est le suivant :
* L'émulateur créé un buffer de 20ms de son. Il effectue cela durant environ 7 à 8 ms (en fait c'est l'émulation du Z80 qui bosse et remplit ce buffer, comme sur la vrai machine).
* On attend une synchronisation temporelle de 20 ms
* On envoi dans le stream de son le buffer calculé
C'est tout simple MAIS : il ne faut pas de rupture entre le buffer en cours de play et l'entrée des nouvelles donnée de façon à éviter des "plop" toutes les 20 ms...
J'ai donc créé une class audio en stream comme suit :
ensuite je créé l'instance:
(882 : c'est 44100 echantillons par seconde / 50 pour faire les 20ms de play...)
suivi d'une initialisation :
puis le play :
Ce programme me permet de tester le programme en envoyant un son continu (sinusoide) qui devrait donner un son continu, puisque dés de SFML me demande des données, je transmets un buffer contant et prés-documenté...
La problématique : Lors de l'exécution on entend parfaitement... les plop indiquant du buffer empty...
J'ai agrandi le buffer à 44100 (soit 1 seconde...) et c'est pareil (toutes les secondes). De plus il ne me semble pas que le OnGetData() soit réellement scruté toutes les 20ms (ou même toutes les secondes lorsque je mets 44100 échantillons) mais plutôt seulement 3/4 fois au total... J'ai essayé avec un buffer rempli d'un fichier (comme l'exemple) cela semble presque ok (petit plop quand même en fin de buffer, mais nettement moins fort)
Y a t il une façon de faire mieux ?
Je n'attend pas une solution toute programmée, mais juste une "bonne" idée pour la réalisation.
Pour voir l'avance du prog actuel : googélisez "VBHector yo_fr" (forum cfg system). Pour info j'avais déjà programmé dans MESS les machines Hector...en C
JJ
Je suis en cours d'écriture d'un émulateur de vieux bouzin (Hector de la gamme Micronique à base de Z80). J'ai, au départ, voulu savoir si le VB.Net était suffisamment rapide pour programmer ce genre de chose qui au début ne pouvait fonctionner que par du code C ou asm; mais maintenant je le sais : Ca marche !
L'ensemble de l'émulateur fonctionne (Z80, Mémoire, I/O, écran, clavier, K7, joystick, lecteur de disquette (à base de Z80 séparé et d'un contrôleur) ...) et seule la gestion du son est manquant. j'ai cherché sur le net la meilleur façon de programmer le son et j'ai trouvé SFML...
Mon cahier des charges est le suivant :
* L'émulateur créé un buffer de 20ms de son. Il effectue cela durant environ 7 à 8 ms (en fait c'est l'émulation du Z80 qui bosse et remplit ce buffer, comme sur la vrai machine).
* On attend une synchronisation temporelle de 20 ms
* On envoi dans le stream de son le buffer calculé
C'est tout simple MAIS : il ne faut pas de rupture entre le buffer en cours de play et l'entrée des nouvelles donnée de façon à éviter des "plop" toutes les 20 ms...
J'ai donc créé une class audio en stream comme suit :
Public Class HectorStream
Inherits SoundStream
'////////////////////////////////////////////////////////////
'/// Constructor
'////////////////////////////////////////////////////////////
Dim BufferSize As Integer
Dim myOffset As Integer
Dim myBuffer(1) As Short
Sub New(ByVal BufferSize_ As Integer)
BufferSize = BufferSize_
myOffset = 0
ReDim myBuffer(BufferSize)
End Sub
Protected Overrides Function OnStart() As Boolean
OnStart = True
Dim i As Double
'Creation d'un buffer avec une son sinusoidale
For i = 0 To BufferSize - 1
myBuffer(i) = Math.Sin(i * 6.28 / 110) * 32700
Next
End Function
Protected Overrides Function OnGetData(ByRef Data() As Short) As Boolean
'Remplissage du stream
Data = myBuffer '
OnGetData = True
End Function
Sub AddSample(ByRef Donnee() As Short)
' Futur : remplissage par le Z80, par appel de AddSample()....
' myBuffer = Donnee
End Sub
Public Sub SomeInitFunction()
Dim ChannelsCount As Integer = 1
Dim SampleRate As Integer = 44100
' init SoundStream.
Initialize(ChannelsCount, SampleRate)
End Sub
End Class
Inherits SoundStream
'////////////////////////////////////////////////////////////
'/// Constructor
'////////////////////////////////////////////////////////////
Dim BufferSize As Integer
Dim myOffset As Integer
Dim myBuffer(1) As Short
Sub New(ByVal BufferSize_ As Integer)
BufferSize = BufferSize_
myOffset = 0
ReDim myBuffer(BufferSize)
End Sub
Protected Overrides Function OnStart() As Boolean
OnStart = True
Dim i As Double
'Creation d'un buffer avec une son sinusoidale
For i = 0 To BufferSize - 1
myBuffer(i) = Math.Sin(i * 6.28 / 110) * 32700
Next
End Function
Protected Overrides Function OnGetData(ByRef Data() As Short) As Boolean
'Remplissage du stream
Data = myBuffer '
OnGetData = True
End Function
Sub AddSample(ByRef Donnee() As Short)
' Futur : remplissage par le Z80, par appel de AddSample()....
' myBuffer = Donnee
End Sub
Public Sub SomeInitFunction()
Dim ChannelsCount As Integer = 1
Dim SampleRate As Integer = 44100
' init SoundStream.
Initialize(ChannelsCount, SampleRate)
End Sub
End Class
ensuite je créé l'instance:
Son = New HectorStream(882)
(882 : c'est 44100 echantillons par seconde / 50 pour faire les 20ms de play...)
suivi d'une initialisation :
Son.SomeInitFunction()
puis le play :
Son.play()
Ce programme me permet de tester le programme en envoyant un son continu (sinusoide) qui devrait donner un son continu, puisque dés de SFML me demande des données, je transmets un buffer contant et prés-documenté...
La problématique : Lors de l'exécution on entend parfaitement... les plop indiquant du buffer empty...
J'ai agrandi le buffer à 44100 (soit 1 seconde...) et c'est pareil (toutes les secondes). De plus il ne me semble pas que le OnGetData() soit réellement scruté toutes les 20ms (ou même toutes les secondes lorsque je mets 44100 échantillons) mais plutôt seulement 3/4 fois au total... J'ai essayé avec un buffer rempli d'un fichier (comme l'exemple) cela semble presque ok (petit plop quand même en fin de buffer, mais nettement moins fort)
Y a t il une façon de faire mieux ?
Je n'attend pas une solution toute programmée, mais juste une "bonne" idée pour la réalisation.
Pour voir l'avance du prog actuel : googélisez "VBHector yo_fr" (forum cfg system). Pour info j'avais déjà programmé dans MESS les machines Hector...en C
JJ