Pergunta

iam making an application which plays a sound when a key is down, the sound stops immediately when the key is released.

The problem I found is that if you press a key it plays the first miliseconds of it and then infinite loop it until you release the key.

The code iam currently using is the following:

        public class Foo
        {

            public static int GetStream1(string path)
            {
                return Bass.BASS_StreamCreateFile(path, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN);
            }
            public static int GetStream2(string path)
            {
                return Bass.BASS_StreamCreateFile(path, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN);
            }
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            Bass.BASS_Init(1, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle);
            Bass.BASS_Init(2, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle);


                if (e.KeyCode == Keys.D1)
                {
                    if (beatload1.Text == "Waiting 01.wav")
                    {
                        MessageBox.Show("No beat loaded");
                        return;
                    }
                    Beat1.Image = Beatpadpc.Properties.Resources.white_square_button;
                    try
                    {
                        Bass.BASS_SetDevice(1);
                        Bass.BASS_ChannelPlay(Foo.GetStream1(path1.Text), false);
                    }
                    catch (FileNotFoundException)
                    {
                        MessageBox.Show("File has been moved." + "\n" + "Please relocate it now!");
                    }
                }

                if (e.KeyCode == Keys.D2)
                {
                    if (beatload2.Text == "Waiting 02.wav")
                    {
                        MessageBox.Show("No beat loaded");
                        return;
                    }
                    Beat2.Image = Beatpadpc.Properties.Resources.white_square_button;
                    try
                    {
                        Bass.BASS_SetDevice(2);
                        Bass.BASS_ChannelPlay(Foo.GetStream2(path2.Text), false);
                    }
                    catch (FileNotFoundException)
                    {
                        MessageBox.Show("File has been moved." + "\n" + "Please relocate it now!");
                    }
               }
        }

        private void Window_KeyUp(object sender, KeyEventArgs e)
        {
         if (e.KeyCode == Keys.D1)
            {
                Beat1.Image = Beatpadpc.Properties.Resources.black_square_button;
                Bass.BASS_StreamFree(Foo.GetStream1(path1.Text));
                Bass.BASS_SetDevice(1);
                Bass.BASS_Free();
            }
            if (e.KeyCode == Keys.D2)
            {
                Beat2.Image = Beatpadpc.Properties.Resources.black_square_button;
                Bass.BASS_StreamFree(Foo.GetStream2(path2.Text));
                Bass.BASS_SetDevice(2);
                Bass.BASS_Free();
            }
}

So is there a way to play 1 or more sounds at the same time without them getting looped for ever?

Foi útil?

Solução

Add a private member to your class:

private Dictionary<Key, Boolean> KeyIsDown;

In your OnKeyDown method, set KeyIsDown(currentKey) = true; In your OnKeyUp method, set KeyIsDown(currentKey) = false;

Then add a delegate for the onIdle event. Whenever the delegate is called check each key in KeyIsDown using an if statement instead of foreach and process each key as you like depending on whether KeyIsDown(aKey) is true or false.

Since I do not have the Bass class that your code refers to, I can only come to a close approximation of what it should look like. You will have to make the real adaptations yourself.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Input;

namespace WinformExcercise1
{
   public partial class Form1 : Form
   {
      private Dictionary<Keys, bool> keyIsDown = new Dictionary<Keys,bool>();
      private Timer timer;
      private int stream1;

      public Form1()
      {
         InitializeComponent();

         keyIsDown.Add(Keys.J, false);
         keyIsDown.Add(Keys.K, false);
         keyIsDown.Add(Keys.L, false);

         setupPlayer();
         this.KeyPreview = true;
      }

      private void setupPlayer()
      {
         // Bass.BASS_SetDevice(1);
         stream1 = Foo.GetStream2(path1.Text);
         // all code that is called once for setting things up goes here
      }

      private void Form1_KeyDown(object sender, KeyEventArgs e)
      {
         if (true == keyIsDown.ContainsKey(e.KeyCode))
         {
            keyIsDown[e.KeyCode] = true;
         }
      }

      private void Form1_KeyUp(object sender, KeyEventArgs e)
      {
         if (true == keyIsDown.ContainsKey(e.KeyCode))
         {
            keyIsDown[e.KeyCode] = false;
         }
      }

      private void Form1_Load(object sender, EventArgs e)
      {
         // This makes the computer constantly call the playKeys method
         timer = new Timer();
         timer.Interval = 1000;
         timer.Tick += new EventHandler(playKeys);
         timer.Enabled = true;
      }

      private void playKeys(Object source, EventArgs e)
      {
         // You have to add the next 8 lines once for each key you are watching
         // What I have here only does something for the J key.
         if (true == keyIsDown[Keys.J])
         {
            Bass.BASS_Init(1, 44100, BASSInit.BASS_DEVICE_DEFAULT, this.Handle);
         }
         else
         {
            Bass.BASS_StreamFree(Stream1);
         }
      }


   }
}

Outras dicas

haha nice, i was just posting a similar answer then philogon, but with a slight difference:

private Dictionary<Key, bool> myKeys;

while initializing you add all keys you want to press (e.g. Keys.D1, Keys.D2), all with "false". write a function like:

private bool getKeyState(Keys k) 

this function can be used everytime a key is pressed. the parameter will be the key, which is pressed. if its already pressed, ignore it. if not, yeah play the bass.

and then, i'd write a function like:

private void updateKeyDictionary(Key, boolean state)

here you could check with "getKeyState" you get the current state of the key - if it's the same state, do nothing, otherwise update. with some nice linq-expression this tasks could be done in 2-3 lines

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top