mix multiple voices
This commit is contained in:
parent
51e55d2428
commit
39f934d810
@ -22,7 +22,7 @@ reasonably shouldn't, let me know (or fix it and then let me know!)
|
|||||||
- [x] handling everyone's state
|
- [x] handling everyone's state
|
||||||
- [x] any of the actual audio stuff
|
- [x] any of the actual audio stuff
|
||||||
- [x] noise suppression with rnnoise
|
- [x] noise suppression with rnnoise
|
||||||
- [ ] chat with more than a singular other person, probably
|
- [x] chat with more than a singular other person, probably
|
||||||
|
|
||||||
## building
|
## building
|
||||||
hubbub requires go 1.23 to build. it might run on earlier versions, but i think
|
hubbub requires go 1.23 to build. it might run on earlier versions, but i think
|
||||||
|
|||||||
@ -31,15 +31,7 @@ const channels = 1
|
|||||||
type Audio struct {
|
type Audio struct {
|
||||||
Muted bool
|
Muted bool
|
||||||
Deafened bool
|
Deafened bool
|
||||||
OutBuffer chan string
|
Buffers map[string]chan string
|
||||||
}
|
|
||||||
|
|
||||||
func NewAudio() Audio {
|
|
||||||
return Audio{
|
|
||||||
Muted: false,
|
|
||||||
Deafened: false,
|
|
||||||
OutBuffer: make(chan string),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (au *Audio) ProcessInput(conn *ircevent.Connection, channel string) error {
|
func (au *Audio) ProcessInput(conn *ircevent.Connection, channel string) error {
|
||||||
@ -72,23 +64,36 @@ func (au *Audio) ProcessInput(conn *ircevent.Connection, channel string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
empty := make([]float32, len(out))
|
// mix all outputs together
|
||||||
|
mix := make([]float32, len(out))
|
||||||
|
voices := 0
|
||||||
|
for _, buffer := range au.Buffers {
|
||||||
select {
|
select {
|
||||||
case str := <-au.OutBuffer:
|
case str := <-buffer:
|
||||||
if !au.Deafened {
|
if !au.Deafened {
|
||||||
raw, err := base64.StdEncoding.DecodeString(str)
|
raw, err := base64.StdEncoding.DecodeString(str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if _, err = dec.DecodeFloat32(raw, out); err != nil {
|
decoded := make([]float32, len(out))
|
||||||
|
if _, err = dec.DecodeFloat32(raw, decoded); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
for i := range decoded {
|
||||||
copy(out, empty)
|
mix[i] += decoded[i]
|
||||||
|
}
|
||||||
|
voices++
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
copy(out, empty)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if voices > 0 {
|
||||||
|
for i := range mix {
|
||||||
|
mix[i] /= float32(voices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy(out, mix)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error opening input stream: %v", err)
|
log.Printf("error opening input stream: %v", err)
|
||||||
|
|||||||
17
main.go
17
main.go
@ -119,6 +119,7 @@ func (m model) Init() tea.Cmd {
|
|||||||
u, ok := m.users[e.Nick()]
|
u, ok := m.users[e.Nick()]
|
||||||
if !ok {
|
if !ok {
|
||||||
m.users[e.Nick()] = user{}
|
m.users[e.Nick()] = user{}
|
||||||
|
m.au.Buffers[e.Nick()] = make(chan string)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch message {
|
switch message {
|
||||||
@ -133,7 +134,7 @@ func (m model) Init() tea.Cmd {
|
|||||||
u.isMuted = false
|
u.isMuted = false
|
||||||
default:
|
default:
|
||||||
u.lastSpoke = time.Now()
|
u.lastSpoke = time.Now()
|
||||||
m.au.OutBuffer <- message
|
m.au.Buffers[e.Nick()] <- message
|
||||||
}
|
}
|
||||||
|
|
||||||
m.users[e.Nick()] = u
|
m.users[e.Nick()] = u
|
||||||
@ -141,6 +142,9 @@ func (m model) Init() tea.Cmd {
|
|||||||
|
|
||||||
m.conn.AddCallback("JOIN", func(e ircmsg.Message) {
|
m.conn.AddCallback("JOIN", func(e ircmsg.Message) {
|
||||||
m.users[e.Nick()] = user{}
|
m.users[e.Nick()] = user{}
|
||||||
|
if e.Nick() != m.nick {
|
||||||
|
m.au.Buffers[e.Nick()] = make(chan string)
|
||||||
|
}
|
||||||
|
|
||||||
// advertise your muted and deafened statuses on someone joining
|
// advertise your muted and deafened statuses on someone joining
|
||||||
if m.deafen {
|
if m.deafen {
|
||||||
@ -157,10 +161,12 @@ func (m model) Init() tea.Cmd {
|
|||||||
|
|
||||||
m.conn.AddCallback("PART", func(e ircmsg.Message) {
|
m.conn.AddCallback("PART", func(e ircmsg.Message) {
|
||||||
delete(m.users, e.Nick())
|
delete(m.users, e.Nick())
|
||||||
|
delete(m.au.Buffers, e.Nick())
|
||||||
})
|
})
|
||||||
|
|
||||||
m.conn.AddCallback("QUIT", func(e ircmsg.Message) {
|
m.conn.AddCallback("QUIT", func(e ircmsg.Message) {
|
||||||
delete(m.users, e.Nick())
|
delete(m.users, e.Nick())
|
||||||
|
delete(m.au.Buffers, e.Nick())
|
||||||
})
|
})
|
||||||
|
|
||||||
m.conn.Join(m.channel)
|
m.conn.Join(m.channel)
|
||||||
@ -215,8 +221,9 @@ func (m model) View() (s string) {
|
|||||||
}
|
}
|
||||||
s += fmt.Sprintf("%d user%s connected:\n", numUsers, plural)
|
s += fmt.Sprintf("%d user%s connected:\n", numUsers, plural)
|
||||||
|
|
||||||
for _, nick := range slices.Sorted(maps.Keys(m.users)) {
|
users := maps.Clone(m.users)
|
||||||
user := m.users[nick]
|
for _, nick := range slices.Sorted(maps.Keys(users)) {
|
||||||
|
user := users[nick]
|
||||||
status := " "
|
status := " "
|
||||||
nickStyled := styleInactive.Render(nick)
|
nickStyled := styleInactive.Render(nick)
|
||||||
if user.isDeafened {
|
if user.isDeafened {
|
||||||
@ -282,7 +289,9 @@ func start(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
au := audio.NewAudio()
|
au := audio.Audio{
|
||||||
|
Buffers: map[string](chan string){},
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
if err := au.ProcessInput(&conn.Connection, config.Channel); err != nil {
|
if err := au.ProcessInput(&conn.Connection, config.Channel); err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user