BASS for WinCE

Started by Ian @ un4seen,

Ian @ un4seen

Good to hear that you got it working after the addition of ACM. I'll see if it is possible to make the ACM support optional, so that BASS will still load without it.

Regarding DX8 effects, I'm afraid they are not included in WinCE. So you would indeed need to implement your own equalizer via a DSP function. You can find some equalizer source code here...

   www.musicdsp.org

Note that it should be implemented in integer/fixed-point for decent performance, as floating-point is very slow without an FPU.

Ian @ un4seen

An updated BASS build is now in the CE package (see 1st post), which should work without ACM support being present in the OS (BASS will just disable its ACM support in that case). Please report any problems with it.

cablehead

Can anyone convert the C spectrum.exe to C#?

Simon chen

@cablehead
it's easy to implement the spectrum use the bass.net for ce, this is a piece of example code:
            Graphics g = Graphics.FromImage(pictureBox.Image);
            Rectangle rect = new Rectangle(0, 0, WIDTH, HEIGHT);
            SolidBrush brush = new SolidBrush(Color.Black);
            g.FillRectangle(brush, rect);
            brush.Dispose();
            brush = new SolidBrush(Color.Green);
            int bandWidth = WIDTH / BAND_CONST;//BAND_CONST = 28
            int b0 = 0;
            int band, height;
            Random rnd1 = new Random();
            StringBuilder sb = new StringBuilder();
           

            for (band = 0; band < BAND_CONST; band++)
            {
                float sum = 0;
                int sc, b1 = (int)System.Math.Pow(2, band * 10.0 / (BAND_CONST - 1));
                if (b1 > 1023) b1 = 1023;
                if (b1 <= b0) b1 = b0 + 1; // make sure it uses at least 1 FFT bin
                sc = 10 + b1 - b0;
                for (; b0 < b1; b0++)
                {
                    sum += FFTData[1 + b0];
                }

                height = (int)(System.Math.Sqrt(sum / System.Math.Log10(sc)) * 1.5 * HEIGHT) - 4; // scale it
                if (height> HEIGHT)
                {
                    height = HEIGHT;
                }

                g.FillRectangle(brush, band * bandWidth, HEIGHT - height, bandWidth - 1, height);
            }

            brush.Dispose();
            g.Dispose();
the code show the Spectrum to pictureBox componet. i only implement the case specmode==1(logarithmic, acumulate & average bins).
the other case can translate into CSharp in the same method. i'm not use CreateDIBSection to deal bmp, because it quick enough to me, if you want to use it, use DllImport to import it.

Simon chen

@IVan

thank you. i had find a equalizer source code, it work well in my PC, but too slowly to run in my wince device. i'm afraid that it's impossible to implement the equalizer quickly for me. is it possible to upgrade the directx to some new version to use BASS_ChannelSetFX correctly?

another problem, i writen a piece of code in my program to show spectrum:
   if (BASS_ChannelIsActive(stream) == BASS_ACTIVE_PLAYING)
   {
      CurrentTime = BASS_ChannelBytes2Seconds(stream, BASS_ChannelGetPosition(stream, BASS_POS_BYTE));
      CString PlayTime = FormatTime(CurrentTime) + " / " + FormatTime(TotalTime);
      SetWindowText(SongName + " - " + PlayTime);
      
      HDC dc;
      int x,y;
      DWORD result;
      CString msg;
      if (-1 == (result = BASS_ChannelGetData(stream, FFTData, BASS_DATA_FFT2048)))
      {
         return;
      }
      
      int b0=0;
      float sum;
      int sc,b1;
      memset(specbuf,0,SPECWIDTH*SPECHEIGHT);
#define BANDS 28
      for (x=0;x<BANDS;x++) {
         sum=0;
         b1=(int)pow(2,x*10.0/(BANDS-1));
         if (b1>1023) b1=1023;
         if (b1<=b0) b1=b0+1; // make sure it uses at least 1 FFT bin
         sc=10+b1-b0;
         for (;b0<b1;b0++)
         {
            sum+=FFTData[1+b0];
         }
         sum *= 1e38f;
         y=(int)(sqrt(sum/log10(sc))*1.7*SPECHEIGHT)-4; // scale it
         if (y>SPECHEIGHT) y=SPECHEIGHT; // cap it
         while (--y>=0)
         {
            memset(specbuf+y*SPECWIDTH+x*(SPECWIDTH/BANDS),y+1,SPECWIDTH/BANDS-2); // draw bar
         }
      }
      dc=::GetDC(m_Picture.GetSafeHwnd());
      BitBlt(dc,0,0,SPECWIDTH,SPECHEIGHT,specdc,0,0,SRCCOPY);
      ::ReleaseDC(m_Picture.GetSafeHwnd(), dc);
this code is modified from spectrum.c in bass package.  it's nessary to add sum *= 1e38f to show spectrum in my ce device, or else it didn't show correct.
but it show the spectrum correct without the (sum *= 1e38f;)statement when run it in my PC. why the return FFTData from BASS_ChannelGetData() function is different between XP and CE?(ce:about 1e-41,xp:about 1e-3?), the 1e38f is got from tries.

Ian @ un4seen

Quote from: Simon chenthank you. i had find a equalizer source code, it work well in my PC, but too slowly to run in my wince device. i'm afraid that it's impossible to implement the equalizer quickly for me. is it possible to upgrade the directx to some new version to use BASS_ChannelSetFX correctly?

CE can support some DirectX components, but not fully (I think they are just emulated using other APIs) and unfortunately I don't think the DX8 effects are one of the supported things.

Did you implement your equalizer using integer/fixed-point math? Floating-point will be very slow, but I think the CPU usage of an integer/fixed-point EQ should be within reason.

Quote from: Simon chenthis code is modified from spectrum.c in bass package.  it's nessary to add sum *= 1e38f to show spectrum in my ce device, or else it didn't show correct.
but it show the spectrum correct without the (sum *= 1e38f;)statement when run it in my PC. why the return FFTData from BASS_ChannelGetData() function is different between XP and CE?(ce:about 1e-41,xp:about 1e-3?), the 1e38f is got from tries.

That looks like you have taken the Win32 SPECTRUM example as a starting point, rather than the WinCE version of it? In the CE version, BASS_ChannelGetData gives 8.24 fixed-point data rather than floating-point.

radio42

Here comes the new BASS.NET CE version (for the .Net CompactFramework 2.0):
v2.4.0.9:
www.un4seen.com/filez/4/Bass24.Net_compact.zip

It now also supports the BASSenc add-on as well as the Encoder framework.
Let me know what you find...

cablehead

Simon...What is FFTData in your example?

Simon chen

cablehead

        float[] FFTData = new float[1024];
        int length = Un4seen.Bass.Bass.BASS_ChannelGetData(handle, FFTData, (int)Un4seen.Bass.BASSData.BASS_DATA_FFT2048);
        if (length <= 0)
        {
            return;
        }

Simon chen

Ivan

I have modified my equalizer using 32 bit fixed-point integer math, it brought a significant improvement in playback speed, I estimate that it increased nearly 10 times. but ... the speed is still not fast enough, it have clear pause. i thought that it's difficult to implement it on wince.

gregory

Hi ! I'd like to develop a very useful program for my online station Vombat Radio - and i think we need a Win CE version of Bass.dll . Can anyone help me ? My email address is : vombatradio@gmail.com

cablehead

Simon:

Your using-
 Graphics g = Graphics.FromImage(pictureBox.Image);
 
What are you using for the initail image?

Its null...

simon.chen

@cablehead

add following code after InitializeComponent():
            pictureBox.Height = HEIGHT;
            pictureBox.Width = WIDTH;
            pictureBox.Image = new Bitmap(WIDTH, HEIGHT);
            BassNet.Registration("emailaddress", "xxxxxxxx");
            if ((Bass.BASS_GetVersion() >> 16) != Bass.BASSVERSION)
            {
                MessageBox.Show("Error version of 'Bass.dll' ");
            }

            if (!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle))
            {
                MessageBox.Show("Can't initialize device");
            }

or check up it before use:
if (pictureBox.Image == null)
{
    pictureBox.Image = new Bitmap(WIDTH, HEIGHT);
}
Graphics g = Graphics.FromImage(pictureBox.Image);

hc_mark

Hi! I am currently making a wince application that records voice input. I am using Bass.Net_compact and I am able to record and save it as wav file. However, I would like my recorded wav file to be encoded to mp3. Is this possible for WINCE?

Ian @ un4seen

Quote from: Simon chenI have modified my equalizer using 32 bit fixed-point integer math, it brought a significant improvement in playback speed, I estimate that it increased nearly 10 times. but ... the speed is still not fast enough, it have clear pause. i thought that it's difficult to implement it on wince.

How many bands were you using? Perhaps that could be reduced, eg. just 3 bands (low/mid/high).

Anyway, I guess EQ will be a pretty common requirement, so I'll see if BASS can be made to emulate the BASS_FX_DX8_PARAMEQ effect on WinCE.

Quote from: gregoryHi ! I'd like to develop a very useful program for my online station Vombat Radio - and i think we need a Win CE version of Bass.dll . Can anyone help me ? My email address is : vombatradio@gmail.com

You can find the WinCE BASS stuff in the 1st post of this thread.

Quote from: hc_markHi! I am currently making a wince application that records voice input. I am using Bass.Net_compact and I am able to record and save it as wav file. However, I would like my recorded wav file to be encoded to mp3. Is this possible for WINCE?

I'm not sure. I don't think there are any command-line encoders for WinCE, but I guess there may be 3rd-party ACM codecs that'll do MP3 encoding. If so, they could be used via the BASSenc add-on, eg. the BASS_Encode_StartACMFile function. And if not ACM codecs, then perhaps there are MP3 encoding libraries, which could be used to encode the recorded data (eg. in the RECORDPROC callback function).

cablehead

#115
Simon...Thanks for the help..

The following code in a timer...creates the fill black rectangle...but nothing else.
No Color.green at all:

I create the stream with just the AUTOFREE flag.

private void timerpectrum_Tick(object sender, EventArgs e)
        {
            var WIDTH = pictureBoxASpectrum.Width;
            var HEIGHT = pictureBoxASpectrum.Height;
            const int BAND_CONST = 28;
            float[] FFTData = new float[1024];
            
            int length = Bass.BASS_ChannelGetData(stream, FFTData, (int)Un4seen.Bass.BASSData.BASS_DATA_FFT2048);
            if (length <= 0)
            {
                return;
            }
            if (pictureBoxASpectrum.Image == null)
            {
                pictureBoxASpectrum.Image = new Bitmap(WIDTH, HEIGHT);
            }
                      
            Graphics g = Graphics.FromImage(pictureBoxASpectrum.Image);
            Rectangle rect = new Rectangle(0, 0, WIDTH, HEIGHT);
            SolidBrush brush = new SolidBrush(Color.Black);
            g.FillRectangle(brush, rect);
            brush.Dispose();
            brush = new SolidBrush(Color.Green);
            int bandWidth = WIDTH / BAND_CONST;//BAND_CONST = 28
            int b0 = 0;
            int band, height;
          
            for (band = 0; band < BAND_CONST; band++)
            {
                float sum = 0;
                int sc, b1 = (int)System.Math.Pow(2, band * 10.0 / (BAND_CONST - 1));
                if (b1 > 1023) b1 = 1023;
                if (b1 <= b0) b1 = b0 + 1; // make sure it uses at least 1 FFT bin
                sc = 10 + b1 - b0;
                for (; b0 < b1; b0++)
                {
                    sum += FFTData[1 + b0];
                  
                }

                height = (int)(System.Math.Sqrt(sum / System.Math.Log10(sc)) * 1.5 * HEIGHT) - 4; // scale it
                if (height > HEIGHT)
                {
                    height = HEIGHT;
                }

                g.FillRectangle(brush, band * bandWidth, HEIGHT - height, bandWidth - 1, height);
            }

            brush.Dispose();
            g.Dispose();

        }

simon.chen

#116
@cablehead

you can reference  the c++ code i post to Ivan before, the reason is that i have taken the Win32 SPECTRUM example as a starting point(i test it on pc first, so...).
If you are running it on pc you will get the correct results. if you are running it on ce device, a lazy way is to add following code (red color)
                for (; b0 < b1; b0++)
                {
                    sum += FFTData[1 + b0];
                  
                }
                sum *= 1e38f;
                height = (int)(System.Math.Sqrt(sum / System.Math.Log10(sc)) * 1.5 * HEIGHT) - 4;
but the correct way is taken the Wince SPECTRUM example as a starting point.
           int[] FFTData = new int[1024];
           ...
           ...
            for (band = 0; band < BAND_CONST; band++)
            {
                int sum = 0;
                int sc, b1 = (int)System.Math.Pow(2, band * 9.0 / (BAND_CONST - 1));
                if (b1 > 1023) b1 = 1023;
                if (b1 <= b0) b1 = b0 + 1; // make sure it uses at least 1 FFT bin
                sc = 10 + b1 - b0;
                for (; b0 < b1; b0++) sum += FFTData[1 + b0];
                height = (int)(System.Math.Sqrt(sum / (float)(1 << 24) / System.Math.Log10(sc)) * 1.7 * HEIGHT) - 4; // scale it
                if (height > HEIGHT) height = HEIGHT; // cap it
                g.FillRectangle(brush, band * bandWidth, HEIGHT - height, bandWidth - 1, height);
            }
enjoy it.
BTW: maybe you can make FFTData as a member variable of your form class, it doesn't need to new it in timer event function.

Ian @ un4seen

An update is now in the CE package (see 1st post), including support for the BASS_FX_DX8_PARAMEQ effect. An FXTEST example has also been added to test it.

BASSenc has also been updated to work without ACM support being present in the OS (like BASS was recently).

simon.chen

Quote from: Ian @ un4seenAn update is now in the CE package (see 1st post), including support for the BASS_FX_DX8_PARAMEQ effect. An FXTEST example has also been added to test it.

BASSenc has also been updated to work without ACM support being present in the OS (like BASS was recently).

Yeah, It does work.

hc_dondon

How can i play mp3 via memory stream.
can you check my code pls.
 
FileStream fs = new FileStream(AFileName, FileMode.Open);
byte[] b = new byte[(int)fs.Length];
fs.Read(b, 0, (int)b.Length);
fs.Close();
IntPtr pval = Marshal.AllocHGlobal(b.Length);
try
{
 Marshal.Copy(b, 0, pval, (int)b.Length);
  Bass.BASS_StreamFree(playBackStream);
  playBackStream = Bass.BASS_StreamCreateFile(pval, 0, 0, BASSFlag.BASS_UNICODE); //BASS_UNICODE
}
finally
{
Marshal.FreeHGlobal(pval);
}

playBackStream returns -1 Am i missing something here.

thanks

radio42

Yes, please check the sample as provided in the BASS.NET docs!!!

private GCHandle _hGCFile;
...
// open a file
FileStream fs = File.OpenRead( "test.mp3" );
// get the legth of the file
long length = fs.Length;
// create the buffer which will keep the file in memory
byte[] buffer = new byte[length];
// read the file into the buffer
fs.Read(buffer, 0, length);
// buffer is filled, file can be closed
fs.Close();

// now create a pinned handle, so that the Garbage Collector will not move this object
_hGCFile = GCHandle.Alloc( buffer, GCHandleType.Pinned );
// create the stream (AddrOfPinnedObject delivers the necessary IntPtr)
int stream = Bass.BASS_StreamCreateFile(_hGCFile.AddrOfPinnedObject(),
                  0L, length, BASSFlag.BASS_SAMPLE_FLOAT);

if (stream != 0 && Bass.BASS_ChannelPlay(stream, false) )
{
    // playing...
}
else
{
    Console.WriteLine("Error = {0}", Bass.BASS_ErrorGetCode());
}
...
// when playback has ended and the pinned object is not needed anymore,
// we need to free the handle!
// Note: calling this method to early will crash the application,
// since the buffer would be stolen from BASS while still playing!
_hGCFile.Free();

hc_dondon

@radio24, i will check again my code and will use this one.
do you know of an encoder that converts wav to mp3 or  wav to wma?
we are pretty new to wince development, this is painless in win32 but not in wince.  :'(

hc_dondon

   private void SetFileName(string AFileName)
        {
            FFileName = AFileName;           
            //Open file
            FileStream fs = File.OpenRead(AFileName);               
            //get length of the file
            long length = fs.Length;
            //create memory buffer
            byte[] buffer = new byte[length];           
            fs.Read(buffer, 0, (int)length);
            fs.Close();                       
           
            if (this.GetState() == 1) this.Stop();           
            Bass.BASS_StreamFree(playBackStream);
            // now create a pinned handle, so that the Garbage Collector will not move this object
            _hGCFile = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            // create the stream (AddrOfPinnedObject delivers the necessary IntPtr)
            playBackStream = Bass.BASS_StreamCreateFile(_hGCFile.AddrOfPinnedObject(), 0L, length, BASSFlag.BASS_SAMPLE_FLOAT);
            //playBackStream = Bass.BASS_StreamCreateFile(pval, 0, 0, BASSFlag.BASS_UNICODE); //BASS_UNICODE
            FPLength = Bass.BASS_ChannelGetLength(playBackStream, BASSMode.BASS_POS_BYTES);

            FTotalTime = Decimal.Truncate(Convert.ToDecimal(Bass.BASS_ChannelBytes2Seconds(playBackStream, FPLength) * 1000));
            FStopPosition = Convert.ToInt32(FTotalTime);
            //_hGCFile.Free();       
}

playbackstream returns -1


radio42

What error code do you get when you call BASS_ErrorGetCode right after the BASS_StreamCreateFile call?

hc_dondon

it worked, i checked the code and it returns invalid format. I just changed it to BASSFlag.BASS_UNICODE..

playBackStream = Bass.BASS_StreamCreateFile(_hGCFile.AddrOfPinnedObject(), 0L, length, BASSFlag.BASS_UNICODE);

thanks radio..